| 1 | // -------------------------------------------------------------------------- |
|---|
| 2 | // |
|---|
| 3 | // File |
|---|
| 4 | // Name: Logging.h |
|---|
| 5 | // Purpose: Generic logging core routines declarations and macros |
|---|
| 6 | // Created: 2006/12/16 |
|---|
| 7 | // |
|---|
| 8 | // -------------------------------------------------------------------------- |
|---|
| 9 | |
|---|
| 10 | #ifndef LOGGING__H |
|---|
| 11 | #define LOGGING__H |
|---|
| 12 | |
|---|
| 13 | #include <assert.h> |
|---|
| 14 | |
|---|
| 15 | #include <cerrno> |
|---|
| 16 | #include <cstring> |
|---|
| 17 | #include <iomanip> |
|---|
| 18 | #include <sstream> |
|---|
| 19 | #include <vector> |
|---|
| 20 | |
|---|
| 21 | #include "FileStream.h" |
|---|
| 22 | |
|---|
| 23 | #define BOX_LOG(level, stuff) \ |
|---|
| 24 | { \ |
|---|
| 25 | std::ostringstream _box_log_line; \ |
|---|
| 26 | _box_log_line << stuff; \ |
|---|
| 27 | Logging::Log(level, __FILE__, __LINE__, _box_log_line.str()); \ |
|---|
| 28 | } |
|---|
| 29 | |
|---|
| 30 | #define BOX_SYSLOG(level, stuff) \ |
|---|
| 31 | { \ |
|---|
| 32 | std::ostringstream _box_log_line; \ |
|---|
| 33 | _box_log_line << stuff; \ |
|---|
| 34 | Logging::LogToSyslog(level, __FILE__, __LINE__, _box_log_line.str()); \ |
|---|
| 35 | } |
|---|
| 36 | |
|---|
| 37 | #define BOX_FATAL(stuff) BOX_LOG(Log::FATAL, stuff) |
|---|
| 38 | #define BOX_ERROR(stuff) BOX_LOG(Log::ERROR, stuff) |
|---|
| 39 | #define BOX_WARNING(stuff) BOX_LOG(Log::WARNING, stuff) |
|---|
| 40 | #define BOX_NOTICE(stuff) BOX_LOG(Log::NOTICE, stuff) |
|---|
| 41 | #define BOX_INFO(stuff) BOX_LOG(Log::INFO, stuff) |
|---|
| 42 | #define BOX_TRACE(stuff) \ |
|---|
| 43 | if (Logging::IsEnabled(Log::TRACE)) \ |
|---|
| 44 | { BOX_LOG(Log::TRACE, stuff) } |
|---|
| 45 | |
|---|
| 46 | #define BOX_SYS_ERRNO_MESSAGE(error_number, stuff) \ |
|---|
| 47 | stuff << ": " << std::strerror(error_number) << \ |
|---|
| 48 | " (" << error_number << ")" |
|---|
| 49 | |
|---|
| 50 | #define BOX_FILE_MESSAGE(filename, message) \ |
|---|
| 51 | message << ": " << filename |
|---|
| 52 | |
|---|
| 53 | #define BOX_SYS_FILE_ERRNO_MESSAGE(filename, error_number, message) \ |
|---|
| 54 | BOX_SYS_ERRNO_MESSAGE(error_number, BOX_FILE_MESSAGE(filename, message)) |
|---|
| 55 | |
|---|
| 56 | #define BOX_SYS_ERROR_MESSAGE(stuff) \ |
|---|
| 57 | BOX_SYS_ERRNO_MESSAGE(errno, stuff) |
|---|
| 58 | |
|---|
| 59 | #define BOX_LOG_SYS_WARNING(stuff) \ |
|---|
| 60 | BOX_WARNING(BOX_SYS_ERROR_MESSAGE(stuff)) |
|---|
| 61 | #define BOX_LOG_SYS_ERROR(stuff) \ |
|---|
| 62 | BOX_ERROR(BOX_SYS_ERROR_MESSAGE(stuff)) |
|---|
| 63 | #define BOX_LOG_SYS_ERRNO(error_number, stuff) \ |
|---|
| 64 | BOX_ERROR(BOX_SYS_ERRNO_MESSAGE(error_number, stuff)) |
|---|
| 65 | #define BOX_LOG_SYS_FATAL(stuff) \ |
|---|
| 66 | BOX_FATAL(BOX_SYS_ERROR_MESSAGE(stuff)) |
|---|
| 67 | |
|---|
| 68 | #define THROW_SYS_ERROR_NUMBER(message, error_number, exception, subtype) \ |
|---|
| 69 | THROW_EXCEPTION_MESSAGE(exception, subtype, \ |
|---|
| 70 | BOX_SYS_ERRNO_MESSAGE(error_number, message)) |
|---|
| 71 | |
|---|
| 72 | #define THROW_SYS_ERROR(message, exception, subtype) \ |
|---|
| 73 | THROW_SYS_ERROR_NUMBER(message, errno, exception, subtype) |
|---|
| 74 | |
|---|
| 75 | #define THROW_SYS_FILE_ERROR(message, filename, exception, subtype) \ |
|---|
| 76 | THROW_SYS_ERROR_NUMBER(BOX_FILE_MESSAGE(filename, message), \ |
|---|
| 77 | errno, exception, subtype) |
|---|
| 78 | |
|---|
| 79 | #define THROW_SYS_FILE_ERRNO(message, filename, error_number, exception, subtype) \ |
|---|
| 80 | THROW_SYS_ERROR_NUMBER(BOX_FILE_MESSAGE(filename, message), \ |
|---|
| 81 | error_number, exception, subtype) |
|---|
| 82 | |
|---|
| 83 | #define THROW_FILE_ERROR(message, filename, exception, subtype) \ |
|---|
| 84 | THROW_EXCEPTION_MESSAGE(exception, subtype, \ |
|---|
| 85 | BOX_FILE_MESSAGE(filename, message)) |
|---|
| 86 | |
|---|
| 87 | #ifdef WIN32 |
|---|
| 88 | #define BOX_LOG_WIN_ERROR(stuff) \ |
|---|
| 89 | BOX_ERROR(stuff << ": " << GetErrorMessage(GetLastError())) |
|---|
| 90 | #define BOX_LOG_WIN_WARNING(stuff) \ |
|---|
| 91 | BOX_WARNING(stuff << ": " << GetErrorMessage(GetLastError())) |
|---|
| 92 | #define BOX_LOG_WIN_ERROR_NUMBER(stuff, number) \ |
|---|
| 93 | BOX_ERROR(stuff << ": " << GetErrorMessage(number)) |
|---|
| 94 | #define BOX_LOG_WIN_WARNING_NUMBER(stuff, number) \ |
|---|
| 95 | BOX_WARNING(stuff << ": " << GetErrorMessage(number)) |
|---|
| 96 | #define BOX_LOG_NATIVE_ERROR(stuff) BOX_LOG_WIN_ERROR(stuff) |
|---|
| 97 | #define BOX_LOG_NATIVE_WARNING(stuff) BOX_LOG_WIN_WARNING(stuff) |
|---|
| 98 | #define BOX_WIN_ERRNO_MESSAGE(error_number, stuff) \ |
|---|
| 99 | stuff << ": " << GetErrorMessage(error_number) |
|---|
| 100 | #define THROW_WIN_ERROR_NUMBER(message, error_number, exception, subtype) \ |
|---|
| 101 | THROW_EXCEPTION_MESSAGE(exception, subtype, \ |
|---|
| 102 | BOX_WIN_ERRNO_MESSAGE(error_number, message)) |
|---|
| 103 | #define THROW_WIN_FILE_ERRNO(message, filename, error_number, exception, subtype) \ |
|---|
| 104 | THROW_WIN_ERROR_NUMBER(BOX_FILE_MESSAGE(filename, message), \ |
|---|
| 105 | error_number, exception, subtype) |
|---|
| 106 | #define THROW_WIN_FILE_ERROR(message, filename, exception, subtype) \ |
|---|
| 107 | THROW_WIN_FILE_ERRNO(message, filename, GetLastError(), \ |
|---|
| 108 | exception, subtype) |
|---|
| 109 | #else |
|---|
| 110 | #define BOX_LOG_NATIVE_ERROR(stuff) BOX_LOG_SYS_ERROR(stuff) |
|---|
| 111 | #define BOX_LOG_NATIVE_WARNING(stuff) BOX_LOG_SYS_WARNING(stuff) |
|---|
| 112 | #endif |
|---|
| 113 | |
|---|
| 114 | #ifdef WIN32 |
|---|
| 115 | # define BOX_LOG_SOCKET_ERROR(_type, _name, _port, stuff) \ |
|---|
| 116 | BOX_LOG_WIN_ERROR_NUMBER(stuff << " (type " << _type << ", name " << \ |
|---|
| 117 | _name << ", port " << _port << ")", WSAGetLastError()) |
|---|
| 118 | #else |
|---|
| 119 | # define BOX_LOG_SOCKET_ERROR(_type, _name, _port, stuff) \ |
|---|
| 120 | BOX_LOG_NATIVE_ERROR(stuff << " (type " << _type << ", name " << \ |
|---|
| 121 | _name << ", port " << _port << ")") |
|---|
| 122 | #endif |
|---|
| 123 | |
|---|
| 124 | #define BOX_FORMAT_HEX32(number) \ |
|---|
| 125 | std::hex << \ |
|---|
| 126 | std::showbase << \ |
|---|
| 127 | std::internal << \ |
|---|
| 128 | std::setw(10) << \ |
|---|
| 129 | std::setfill('0') << \ |
|---|
| 130 | (number) << \ |
|---|
| 131 | std::dec |
|---|
| 132 | |
|---|
| 133 | #define BOX_FORMAT_ACCOUNT(accno) \ |
|---|
| 134 | BOX_FORMAT_HEX32(accno) |
|---|
| 135 | |
|---|
| 136 | #define BOX_FORMAT_OBJECTID(objectid) \ |
|---|
| 137 | std::hex << \ |
|---|
| 138 | std::showbase << \ |
|---|
| 139 | (objectid) << \ |
|---|
| 140 | std::dec |
|---|
| 141 | |
|---|
| 142 | #define BOX_FORMAT_TIMESPEC(timespec) \ |
|---|
| 143 | timespec.tv_sec << \ |
|---|
| 144 | std::setw(6) << \ |
|---|
| 145 | timespec.tv_usec |
|---|
| 146 | |
|---|
| 147 | #undef ERROR |
|---|
| 148 | |
|---|
| 149 | namespace Log |
|---|
| 150 | { |
|---|
| 151 | enum Level |
|---|
| 152 | { |
|---|
| 153 | NOTHING = 1, |
|---|
| 154 | FATAL, |
|---|
| 155 | ERROR, |
|---|
| 156 | WARNING, |
|---|
| 157 | NOTICE, |
|---|
| 158 | INFO, |
|---|
| 159 | TRACE, |
|---|
| 160 | EVERYTHING, |
|---|
| 161 | INVALID = -1 |
|---|
| 162 | }; |
|---|
| 163 | } |
|---|
| 164 | |
|---|
| 165 | // -------------------------------------------------------------------------- |
|---|
| 166 | // |
|---|
| 167 | // Class |
|---|
| 168 | // Name: Logger |
|---|
| 169 | // Purpose: Abstract base class for log targets |
|---|
| 170 | // Created: 2006/12/16 |
|---|
| 171 | // |
|---|
| 172 | // -------------------------------------------------------------------------- |
|---|
| 173 | |
|---|
| 174 | class Logger |
|---|
| 175 | { |
|---|
| 176 | private: |
|---|
| 177 | Log::Level mCurrentLevel; |
|---|
| 178 | |
|---|
| 179 | public: |
|---|
| 180 | Logger(); |
|---|
| 181 | Logger(Log::Level level); |
|---|
| 182 | virtual ~Logger(); |
|---|
| 183 | |
|---|
| 184 | virtual bool Log(Log::Level level, const std::string& rFile, |
|---|
| 185 | int line, std::string& rMessage) = 0; |
|---|
| 186 | |
|---|
| 187 | void Filter(Log::Level level) |
|---|
| 188 | { |
|---|
| 189 | mCurrentLevel = level; |
|---|
| 190 | } |
|---|
| 191 | |
|---|
| 192 | virtual const char* GetType() = 0; |
|---|
| 193 | Log::Level GetLevel() { return mCurrentLevel; } |
|---|
| 194 | |
|---|
| 195 | virtual void SetProgramName(const std::string& rProgramName) = 0; |
|---|
| 196 | }; |
|---|
| 197 | |
|---|
| 198 | // -------------------------------------------------------------------------- |
|---|
| 199 | // |
|---|
| 200 | // Class |
|---|
| 201 | // Name: Console |
|---|
| 202 | // Purpose: Console logging target |
|---|
| 203 | // Created: 2006/12/16 |
|---|
| 204 | // |
|---|
| 205 | // -------------------------------------------------------------------------- |
|---|
| 206 | |
|---|
| 207 | class Console : public Logger |
|---|
| 208 | { |
|---|
| 209 | private: |
|---|
| 210 | static bool sShowTag; |
|---|
| 211 | static bool sShowTime; |
|---|
| 212 | static bool sShowTimeMicros; |
|---|
| 213 | static bool sShowPID; |
|---|
| 214 | static std::string sTag; |
|---|
| 215 | |
|---|
| 216 | public: |
|---|
| 217 | virtual bool Log(Log::Level level, const std::string& rFile, |
|---|
| 218 | int line, std::string& rMessage); |
|---|
| 219 | virtual const char* GetType() { return "Console"; } |
|---|
| 220 | virtual void SetProgramName(const std::string& rProgramName); |
|---|
| 221 | |
|---|
| 222 | static void SetShowTag(bool enabled); |
|---|
| 223 | static void SetShowTime(bool enabled); |
|---|
| 224 | static void SetShowTimeMicros(bool enabled); |
|---|
| 225 | static void SetShowPID(bool enabled); |
|---|
| 226 | }; |
|---|
| 227 | |
|---|
| 228 | // -------------------------------------------------------------------------- |
|---|
| 229 | // |
|---|
| 230 | // Class |
|---|
| 231 | // Name: Syslog |
|---|
| 232 | // Purpose: Syslog (or Windows Event Viewer) logging target |
|---|
| 233 | // Created: 2006/12/16 |
|---|
| 234 | // |
|---|
| 235 | // -------------------------------------------------------------------------- |
|---|
| 236 | |
|---|
| 237 | class Syslog : public Logger |
|---|
| 238 | { |
|---|
| 239 | private: |
|---|
| 240 | std::string mName; |
|---|
| 241 | int mFacility; |
|---|
| 242 | |
|---|
| 243 | public: |
|---|
| 244 | Syslog(); |
|---|
| 245 | virtual ~Syslog(); |
|---|
| 246 | |
|---|
| 247 | virtual bool Log(Log::Level level, const std::string& rFile, |
|---|
| 248 | int line, std::string& rMessage); |
|---|
| 249 | virtual const char* GetType() { return "Syslog"; } |
|---|
| 250 | virtual void SetProgramName(const std::string& rProgramName); |
|---|
| 251 | virtual void SetFacility(int facility); |
|---|
| 252 | static int GetNamedFacility(const std::string& rFacility); |
|---|
| 253 | }; |
|---|
| 254 | |
|---|
| 255 | // -------------------------------------------------------------------------- |
|---|
| 256 | // |
|---|
| 257 | // Class |
|---|
| 258 | // Name: Logging |
|---|
| 259 | // Purpose: Static logging helper, keeps track of enabled loggers |
|---|
| 260 | // and distributes log messages to them. |
|---|
| 261 | // Created: 2006/12/16 |
|---|
| 262 | // |
|---|
| 263 | // -------------------------------------------------------------------------- |
|---|
| 264 | |
|---|
| 265 | class Logging |
|---|
| 266 | { |
|---|
| 267 | private: |
|---|
| 268 | static std::vector<Logger*> sLoggers; |
|---|
| 269 | static bool sLogToSyslog, sLogToConsole; |
|---|
| 270 | static std::string sContext; |
|---|
| 271 | static bool sContextSet; |
|---|
| 272 | static Console* spConsole; |
|---|
| 273 | static Syslog* spSyslog; |
|---|
| 274 | static Log::Level sGlobalLevel; |
|---|
| 275 | static Logging sGlobalLogging; |
|---|
| 276 | static std::string sProgramName; |
|---|
| 277 | |
|---|
| 278 | public: |
|---|
| 279 | Logging (); |
|---|
| 280 | ~Logging(); |
|---|
| 281 | static void ToSyslog (bool enabled); |
|---|
| 282 | static void ToConsole (bool enabled); |
|---|
| 283 | static void FilterSyslog (Log::Level level); |
|---|
| 284 | static void FilterConsole (Log::Level level); |
|---|
| 285 | static void Add (Logger* pNewLogger); |
|---|
| 286 | static void Remove (Logger* pOldLogger); |
|---|
| 287 | static void Log(Log::Level level, const std::string& rFile, |
|---|
| 288 | int line, const std::string& rMessage); |
|---|
| 289 | static void LogToSyslog(Log::Level level, const std::string& rFile, |
|---|
| 290 | int line, const std::string& rMessage); |
|---|
| 291 | static void SetContext(std::string context); |
|---|
| 292 | static void ClearContext(); |
|---|
| 293 | static void SetGlobalLevel(Log::Level level) { sGlobalLevel = level; } |
|---|
| 294 | static Log::Level GetGlobalLevel() { return sGlobalLevel; } |
|---|
| 295 | static Log::Level GetNamedLevel(const std::string& rName); |
|---|
| 296 | static bool IsEnabled(Log::Level level) |
|---|
| 297 | { |
|---|
| 298 | return (int)sGlobalLevel >= (int)level; |
|---|
| 299 | } |
|---|
| 300 | static void SetProgramName(const std::string& rProgramName); |
|---|
| 301 | static std::string GetProgramName() { return sProgramName; } |
|---|
| 302 | static void SetFacility(int facility); |
|---|
| 303 | |
|---|
| 304 | class Guard |
|---|
| 305 | { |
|---|
| 306 | private: |
|---|
| 307 | Log::Level mOldLevel; |
|---|
| 308 | static int sGuardCount; |
|---|
| 309 | static Log::Level sOriginalLevel; |
|---|
| 310 | |
|---|
| 311 | public: |
|---|
| 312 | Guard(Log::Level newLevel) |
|---|
| 313 | { |
|---|
| 314 | mOldLevel = Logging::GetGlobalLevel(); |
|---|
| 315 | if(sGuardCount == 0) |
|---|
| 316 | { |
|---|
| 317 | sOriginalLevel = mOldLevel; |
|---|
| 318 | } |
|---|
| 319 | sGuardCount++; |
|---|
| 320 | Logging::SetGlobalLevel(newLevel); |
|---|
| 321 | } |
|---|
| 322 | ~Guard() |
|---|
| 323 | { |
|---|
| 324 | sGuardCount--; |
|---|
| 325 | Logging::SetGlobalLevel(mOldLevel); |
|---|
| 326 | } |
|---|
| 327 | |
|---|
| 328 | static bool IsActive() { return (sGuardCount > 0); } |
|---|
| 329 | static Log::Level GetOriginalLevel() { return sOriginalLevel; } |
|---|
| 330 | static bool IsGuardingFrom(Log::Level originalLevel) |
|---|
| 331 | { |
|---|
| 332 | return IsActive() && |
|---|
| 333 | (int)sOriginalLevel >= (int)originalLevel; |
|---|
| 334 | } |
|---|
| 335 | }; |
|---|
| 336 | |
|---|
| 337 | class Tagger |
|---|
| 338 | { |
|---|
| 339 | private: |
|---|
| 340 | std::string mOldTag; |
|---|
| 341 | |
|---|
| 342 | public: |
|---|
| 343 | Tagger(const std::string& rTempTag) |
|---|
| 344 | { |
|---|
| 345 | mOldTag = Logging::GetProgramName(); |
|---|
| 346 | Logging::SetProgramName(mOldTag + " " + rTempTag); |
|---|
| 347 | } |
|---|
| 348 | ~Tagger() |
|---|
| 349 | { |
|---|
| 350 | Logging::SetProgramName(mOldTag); |
|---|
| 351 | } |
|---|
| 352 | }; |
|---|
| 353 | }; |
|---|
| 354 | |
|---|
| 355 | class FileLogger : public Logger |
|---|
| 356 | { |
|---|
| 357 | private: |
|---|
| 358 | FileStream mLogFile; |
|---|
| 359 | FileLogger(const FileLogger& forbidden) |
|---|
| 360 | : mLogFile("") { /* do not call */ } |
|---|
| 361 | |
|---|
| 362 | public: |
|---|
| 363 | FileLogger(const std::string& rFileName, Log::Level Level) |
|---|
| 364 | : Logger(Level), |
|---|
| 365 | mLogFile(rFileName, O_WRONLY | O_CREAT | O_APPEND) |
|---|
| 366 | { } |
|---|
| 367 | |
|---|
| 368 | virtual bool Log(Log::Level Level, const std::string& rFile, |
|---|
| 369 | int Line, std::string& rMessage); |
|---|
| 370 | |
|---|
| 371 | virtual const char* GetType() { return "FileLogger"; } |
|---|
| 372 | virtual void SetProgramName(const std::string& rProgramName) { } |
|---|
| 373 | }; |
|---|
| 374 | |
|---|
| 375 | class HideExceptionMessageGuard |
|---|
| 376 | { |
|---|
| 377 | public: |
|---|
| 378 | HideExceptionMessageGuard() |
|---|
| 379 | { |
|---|
| 380 | mOldHiddenState = sHiddenState; |
|---|
| 381 | sHiddenState = true; |
|---|
| 382 | } |
|---|
| 383 | ~HideExceptionMessageGuard() |
|---|
| 384 | { |
|---|
| 385 | sHiddenState = mOldHiddenState; |
|---|
| 386 | } |
|---|
| 387 | static bool ExceptionsHidden() { return sHiddenState; } |
|---|
| 388 | |
|---|
| 389 | private: |
|---|
| 390 | static bool sHiddenState; |
|---|
| 391 | bool mOldHiddenState; |
|---|
| 392 | }; |
|---|
| 393 | |
|---|
| 394 | class HideSpecificExceptionGuard |
|---|
| 395 | { |
|---|
| 396 | private: |
|---|
| 397 | std::pair<int, int> mExceptionCode; |
|---|
| 398 | |
|---|
| 399 | public: |
|---|
| 400 | typedef std::vector<std::pair<int, int> > SuppressedExceptions_t; |
|---|
| 401 | static SuppressedExceptions_t sSuppressedExceptions; |
|---|
| 402 | |
|---|
| 403 | HideSpecificExceptionGuard(int type, int subtype) |
|---|
| 404 | : mExceptionCode(std::pair<int, int>(type, subtype)) |
|---|
| 405 | { |
|---|
| 406 | sSuppressedExceptions.push_back(mExceptionCode); |
|---|
| 407 | } |
|---|
| 408 | ~HideSpecificExceptionGuard() |
|---|
| 409 | { |
|---|
| 410 | SuppressedExceptions_t::reverse_iterator i = |
|---|
| 411 | sSuppressedExceptions.rbegin(); |
|---|
| 412 | assert(*i == mExceptionCode); |
|---|
| 413 | sSuppressedExceptions.pop_back(); |
|---|
| 414 | } |
|---|
| 415 | static bool IsHidden(int type, int subtype); |
|---|
| 416 | }; |
|---|
| 417 | |
|---|
| 418 | std::string PrintEscapedBinaryData(const std::string& rInput); |
|---|
| 419 | |
|---|
| 420 | #endif // LOGGING__H |
|---|