1 2 /* **************************************************************************** 3 4 * eID Middleware Project. 5 * Copyright (C) 2008-2010 FedICT. 6 * 7 * This is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU Lesser General Public License version 9 * 3.0 as published by the Free Software Foundation. 10 * 11 * This software is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this software; if not, see 18 * http://www.gnu.org/licenses/. 19 20 **************************************************************************** */ 21 22 /* 23 This file contains 2 classes for log purpose : CLogger and CLog 24 25 CLOGGER 26 ------- 27 CLogger is a singleton that keep a vector of CLog (one log by group). 28 29 Instance : -The instance() method give access to the singleton object 30 31 Initialization : -The CLogger may be init. 32 -If it isn't, the default parameters are used. 33 -The init parameters are transfered to CLog object when the CLogger create them. 34 -The init may be call anywhere to change the parameters 35 but these changes only affect the future created CLog 36 37 Retreive a Log : -Use the getLog() method with the name of the group as argument 38 39 CLOG 40 ---- 41 Each CLog represents a set of log file. (One set by group) 42 The constructor is not enabled but objects are created by the logger when you ask for a new group. 43 The files are closed after each write. 44 45 PARAMETERS 46 ---------- 47 You pass the parameters with the init method of the CLogger and it passes them to CLog at creation. 48 49 These parameters are : 50 *Directory : -The folder in which the log files are created. 51 -If it doesn't exist, the current directory is used. 52 *Prefix : -Use to define the name of the files. 53 -The name is <Prefix>_[<Group>_]Index.log (Index begins to 0 until FileNr-1) 54 *FileSize : -The maximum size of the log file. 55 -0 means no limit 56 -When the file is full, we use a new file with the next index. 57 *FileNr : -The maximum number of files (by group) 58 -If the FileSize is 0, this parameter is not used. 59 -The minimum value is 2 60 -When the last file (Index=FileNr-1) is full, the file with index 0 is removed, 61 the File(1) is renamed to File(0), File(i) to File(i-1), 62 then File(FileNr-1) become free again. 63 64 *GroupInNewFile : -If true, new log files are made for each group 65 -If false, the name of the group (if any) appears on each entry line 66 67 USAGE 68 ----- 69 In complement of usual object usage, some macros are defined to give simple access to methods. 70 These macros are define below in this file. 71 You will also find macro template to enable easy use of group. Copy these macros and customize them for your own purpose. 72 73 Example of usage through objects and macro are give at the end of this file 74 */ 75 76 #pragma once 77 78 #include <memory> 79 #include <string> 80 #include <vector> 81 #include "mutex.h" 82 83 #ifndef __WFILE__ 84 #define WIDEN2(x) L ## x 85 #define WIDEN(x) WIDEN2(x) 86 #define __WFILE__ WIDEN(__FILE__) 87 #endif 88 89 #ifndef WIN32 90 #include <sys/file.h> 91 #include <fcntl.h> 92 #endif 93 94 #include <stdarg.h> 95 96 namespace eIDMW 97 { 98 99 class CLog; //define below 100 101 typedef enum 102 { 103 LEV_LEVEL_NOLOG, 104 LOG_LEVEL_CRITICAL, 105 LOG_LEVEL_ERROR, 106 LOG_LEVEL_WARNING, 107 LOG_LEVEL_INFO, 108 LOG_LEVEL_DEBUG, 109 } tLOG_Level; 110 111 #define LOG_LEVEL_DEFAULT LOG_LEVEL_ERROR 112 113 class CLogger 114 { 115 public: 116 static CLogger & instance(); 117 ~ CLogger(); 118 119 private: 120 CLogger(); 121 CLogger(const CLogger & logger); 122 CLogger & operator=(const CLogger & logger); 123 124 public: 125 void initFromConfig(); 126 void init(const wchar_t * directory, 127 const wchar_t * prefix, long filesize, 128 long filenr, tLOG_Level minlevel, 129 bool groupinnewfile); 130 void init(const char *directory, 131 const char *prefix, long filesize, 132 long filenr, tLOG_Level minlevel, 133 bool groupinnewfile); 134 CLog & getLogW(const wchar_t * group = L""); 135 CLog & getLogA(const char *group = ""); 136 void writeToGroup(const wchar_t * group, 137 tLOG_Level level, 138 const wchar_t * format, ...); 139 void writeToGroup(const char *group, 140 tLOG_Level level, 141 const char *format, ...); 142 void writeToGroup(const wchar_t * group, 143 tLOG_Level level, 144 const int line, 145 const wchar_t * file, 146 const wchar_t * format, ...); 147 void writeToGroup(const char *group, 148 tLOG_Level level, 149 const int line, 150 const char *file, 151 const char *format, ...); 152 void write(tLOG_Level level, 153 const wchar_t * format, ...); 154 void write(tLOG_Level level, const char *format, 155 ...); 156 void write(tLOG_Level level, const int line, 157 const wchar_t * file, 158 const wchar_t * format, ...); 159 void write(tLOG_Level level, const int line, 160 const char *file, const char *format, 161 ...); 162 163 private: 164 static std::unique_ptr < CLogger > m_instance; 165 static bool m_bApplicationLeaving; 166 167 std::wstring m_directory; 168 std::wstring m_prefix; 169 long m_filesize; 170 long m_filenr; 171 tLOG_Level m_maxlevel; 172 bool m_groupinnewfile; 173 174 std::vector < CLog * >m_logStore; 175 }; 176 177 class CLog 178 { 179 public: 180 ~ CLog(); 181 182 private: 183 CLog(const wchar_t * directory, const wchar_t * prefix, 184 const wchar_t * group, long filesize, long filenr, 185 tLOG_Level minlevel, bool groupinnewfile); 186 CLog(const CLog & log); 187 CLog & operator=(const CLog &); 188 189 public: 190 void write(tLOG_Level level, 191 const wchar_t * format, ...); 192 void write(tLOG_Level level, const char *format, 193 ...); 194 void write(tLOG_Level level, 195 const wchar_t * format, 196 va_list args); 197 void write(tLOG_Level level, const char *format, 198 va_list args); 199 void write(tLOG_Level level, const int line, 200 const wchar_t * file, 201 const wchar_t * format, ...); 202 void write(tLOG_Level level, const int line, 203 const char *file, const char *format, 204 ...); 205 void write(tLOG_Level level, const int line, 206 const wchar_t * file, 207 const wchar_t * format, 208 va_list args); 209 void write(tLOG_Level level, const int line, 210 const char *file, const char *format, 211 va_list args); 212 213 void writeCritical(const wchar_t * format, ...); 214 void writeCritical(const char *format, ...); 215 void writeCritical(const int line, 216 const wchar_t * file, 217 const wchar_t * format, ...); 218 void writeCritical(const int line, 219 const char *file, 220 const char *format, ...); 221 void writeError(const wchar_t * format, ...); 222 void writeError(const char *format, ...); 223 void writeError(const int line, 224 const wchar_t * file, 225 const wchar_t * format, ...); 226 void writeError(const int line, 227 const char *file, 228 const char *format, ...); 229 void writeWarning(const wchar_t * format, ...); 230 void writeWarning(const char *format, ...); 231 void writeWarning(const int line, 232 const wchar_t * file, 233 const wchar_t * format, ...); 234 void writeWarning(const int line, 235 const char *file, 236 const char *format, ...); 237 void writeInfo(const wchar_t * format, ...); 238 void writeInfo(const char *format, ...); 239 void writeInfo(const int line, 240 const wchar_t * file, 241 const wchar_t * format, ...); 242 void writeInfo(const int line, const char *file, 243 const char *format, ...); 244 void writeDebug(const wchar_t * format, ...); 245 void writeDebug(const char *format, ...); 246 void writeDebug(const int line, 247 const wchar_t * file, 248 const wchar_t * format, ...); 249 void writeDebug(const int line, 250 const char *file, 251 const char *format, ...); 252 253 //USE ONLY IN MACRO 254 bool writeLineHeaderW(tLOG_Level level, 255 const int line = 256 0, const wchar_t * file = 257 L""); 258 bool writeLineHeaderA(tLOG_Level level, 259 const int line = 260 0, const char *file = ""); 261 bool writeLineMessageW(const wchar_t * format, 262 ...); 263 bool writeLineMessageA(const char *format, ...); 264 265 friend class CLogger; 266 267 private: 268 void getFilename(std::wstring & filename); 269 void renameFiles(const wchar_t * root_filename); 270 bool open(bool bWchar); 271 void close(); 272 void writeLineMessageW(const wchar_t * format, 273 va_list argList); 274 void writeLineMessageA(const char *format, va_list argList); 275 const wchar_t *getLevel(tLOG_Level level); 276 void getLocalTimeW(std::wstring & timestamp, 277 const wchar_t * format = 278 L"%Y-%m-%d %H:%M:%S"); 279 void getLocalTimeA(std::string & timestamp, 280 const char *format = "%Y-%m-%d %H:%M:%S"); 281 282 bool isFileMixingGroups(); 283 long getOpenFailed(); 284 bool canWeTryToOpen(); 285 void incrementOpenFailed(); 286 void resetOpenFailed(); 287 288 std::wstring m_directory; 289 std::wstring m_prefix; 290 std::wstring m_group; 291 long m_filesize; 292 long m_filenr; 293 tLOG_Level m_maxlevel; 294 bool m_groupinnewfile; 295 long m_openfailed; 296 static long m_sopenfailed; 297 298 FILE *m_f; 299 300 #ifndef WIN32 301 struct flock *m_flock; 302 #endif 303 }; 304 305 //SHORTCUT MACRO 306 //General use 307 #define ZS_LOG_INIT CLogger::instance().init 308 #define ZS_LOG CLogger::instance().write 309 #define ZS_LOG_GROUP CLogger::instance().writeToGroup 310 311 //Defining a level 312 #define ZS_LOG_CRITICAL CLogger::instance().getLogW(L"").writeCritical 313 #define ZS_LOG_ERROR CLogger::instance().getLogW(L"").writeError 314 #define ZS_LOG_WARNING CLogger::instance().getLogW(L"").writeWarning 315 #define ZS_LOG_INFO CLogger::instance().getLogW(L"").writeInfo 316 #define ZS_LOG_DEBUG CLogger::instance().getLogW(L"").writeDebug 317 318 //Defining a level and trace file and line 319 #define ZS_LOG_CRITICAL_TRACE !CLogger::instance().getLogW(L"").writeLineHeaderW(LOG_LEVEL_CRITICAL,__LINE__,__WFILE__) ? 0 : CLogger::instance().getLogW(L"").writeLineMessageW 320 #define ZS_LOG_ERROR_TRACE !CLogger::instance().getLogW(L"").writeLineHeaderW(LOG_LEVEL_ERROR,__LINE__,__WFILE__) ? 0 : CLogger::instance().getLogW(L"").writeLineMessageW 321 #define ZS_LOG_WARNING_TRACE !CLogger::instance().getLogW(L"").writeLineHeaderW(LOG_LEVEL_WARNING,__LINE__,__WFILE__) ? 0 : CLogger::instance().getLogW(L"").writeLineMessageW 322 #define ZS_LOG_INFO_TRACE !CLogger::instance().getLogW(L"").writeLineHeaderW(LOG_LEVEL_INFO,__LINE__,__WFILE__) ? 0 : CLogger::instance().getLogW(L"").writeLineMessageW 323 #define ZS_LOG_DEBUG_TRACE !CLogger::instance().getLogW(L"").writeLineHeaderW(LOG_LEVEL_DEBUG,__LINE__,__WFILE__) ? 0 : CLogger::instance().getLogW(L"").writeLineMessageW 324 325 //MACRO EXTENSION 326 //Example of extanding to a groupe named Group1 327 #define ZS_LOG_GROUP1 CLogger::instance().getLogW(L"Group1").write 328 329 #define ZS_LOG_GROUP1_CRITICAL CLogger::instance().getLogW(L"Group1").writeCritical 330 #define ZS_LOG_GROUP1_ERROR CLogger::instance().getLogW(L"Group1").writeError 331 #define ZS_LOG_GROUP1_WARNING CLogger::instance().getLogW(L"Group1").writeWarning 332 #define ZS_LOG_GROUP1_INFO CLogger::instance().getLogW(L"Group1").writeInfo 333 #define ZS_LOG_GROUP1_DEBUG CLogger::instance().getLogW(L"Group1").writeDebug 334 335 #define ZS_LOG_GROUP1_CRITICAL_TRACE !CLogger::instance().getLogW(L"Group1").writeLineHeaderW(LOG_LEVEL_CRITICAL,__LINE__,__WFILE__) ? 0 : CLogger::instance().getLogW(L"Group1").writeLineMessageW 336 #define ZS_LOG_GROUP1_ERROR_TRACE !CLogger::instance().getLogW(L"Group1").writeLineHeaderW(LOG_LEVEL_ERROR,__LINE__,__WFILE__) ? 0 : CLogger::instance().getLogW(L"Group1").writeLineMessageW 337 #define ZS_LOG_GROUP1_WARNING_TRACE !CLogger::instance().getLogW(L"Group1").writeLineHeaderW(LOG_LEVEL_WARNING,__LINE__,__WFILE__) ? 0 : CLogger::instance().getLogW(L"Group1").writeLineMessageW 338 #define ZS_LOG_GROUP1_INFO_TRACE !CLogger::instance().getLogW(L"Group1").writeLineHeaderW(LOG_LEVEL_INFO,__LINE__,__WFILE__) ? 0 : CLogger::instance().getLogW(L"Group1").writeLineMessageW 339 #define ZS_LOG_GROUP1_DEBUG_TRACE !CLogger::instance().getLogW(L"Group1").writeLineHeaderW(LOG_LEVEL_DEBUG,__LINE__,__WFILE__) ? 0 : CLogger::instance().getLogW(L"Group1").writeLineMessageW 340 341 } 342 343 /* 344 ************* 345 *** USAGE *** 346 ************* 347 int i=1; 348 //INITIALIZING THE LOGGER 349 //----------------------- 350 //Object use 351 CLogger &logger = CLogger::instance(); 352 logger.init(L"C:\\Tmp", L"Test", 100000, 5, true); 353 354 //Or 355 CLogger::instance().init(L"C:\\Tmp", L"Test", 100000, 5, true); 356 357 //Macro 358 ZS_LOG_INIT(L"C:\\Tmp", L"Test", 100000, 5, true); 359 360 //SIMPLE EXAMPLE (NO GROUP, NO FILE TRACE) 361 //---------------------------------------- 362 //Object use 363 CLog &logA=logger.getLogW(); 364 logA.write(LOG_LEVEL_ERROR,L"Example %d: %s", i++, L"First test"); 365 366 //Or 367 logA.writeError(L"Example %d: %s", i++, L"First test"); 368 369 //Or 370 logger.write(LOG_LEVEL_ERROR,L"Example %d: %s", i++, L"First test"); 371 372 //Or 373 CLogger::instance().write(LOG_LEVEL_ERROR,L"Example %d: %s", i++, L"First test"); 374 375 //Macro 376 ZS_LOG(LOG_LEVEL_ERROR,L"Example %d: %s", i++, L"First test"); 377 378 //Or 379 ZS_LOG_ERROR(L"Example %d: %s", i++, L"First test"); 380 381 //SIMPLE EXAMPLE WITH FILE TRACE (NO GROUP) 382 //---------------------------------------- 383 //Object use 384 CLog &logB=logger.getLogW(); 385 logB.write(LOG_LEVEL_ERROR,__LINE__,__WFILE__,L"Example %d: %s", i++, L"Second test"); 386 387 //Or 388 logB.writeError(__LINE__,__WFILE__,L"Example %d: %s", i++, L"Second test"); 389 390 //Or 391 logger.write(LOG_LEVEL_ERROR,__LINE__,__WFILE__,L"Example %d: %s", i++, L"Second test"); 392 393 //Or 394 CLogger::instance().write(LOG_LEVEL_ERROR,__LINE__,__WFILE__,L"Example %d: %s", i++, L"Second test"); 395 396 //Macro 397 ZS_LOG(LOG_LEVEL_ERROR,__LINE__,__WFILE__,L"Example %d: %s", i++, L"Second test"); 398 399 //Or 400 ZS_LOG_ERROR_TRACE(L"Example %d: %s", i++, L"Second test"); 401 402 //EXAMPLE WITH GROUP (NO FILE TRACE) 403 //---------------------------------- 404 //Object use 405 CLog &logGroup1A=logger.getLog(L"Group1"); 406 logGroup1A.write(LOG_LEVEL_ERROR,L"Example %d: %s", i++, L"Third test"); 407 408 //Or 409 logGroup1A.writeError(L"Example %d: %s", i++, L"Third test"); 410 411 //Or 412 logger.writeToGroup(L"Group1",LOG_LEVEL_ERROR,L"Example %d: %s", i++, L"Third test"); 413 414 //Or 415 CLogger::instance().writeToGroup(L"Group1",LOG_LEVEL_ERROR,L"Example %d: %s", i++, L"Third test"); 416 417 //Macro 418 ZS_LOG_GROUP(L"Group1",LOG_LEVEL_ERROR,L"Example %d: %s", i++, L"Third test"); 419 420 //Or 421 ZS_LOG_GROUP1(LOG_LEVEL_ERROR,L"Example %d: %s", i++, L"Third test"); 422 423 //Or 424 ZS_LOG_GROUP1_ERROR(L"Example %d: %s", i++, L"Third test"); 425 426 //EXAMPLE WITH GROUP AND FILE TRACE 427 //--------------------------------- 428 //Object use 429 CLog &logGroup1B=logger.getLog(L"Group1"); 430 logGroup1B.write(LOG_LEVEL_ERROR,__LINE__,__WFILE__,L"Example %d: %s", i++, L"Fourth test"); 431 432 //Or 433 logGroup1B.writeError(__LINE__,__WFILE__,L"Example %d: %s", i++, L"Fourth test"); 434 435 //Or 436 logger.writeToGroup(L"Group1",LOG_LEVEL_ERROR,__LINE__,__WFILE__,L"Example %d: %s", i++, L"Fourth test"); 437 438 //Or 439 CLogger::instance().writeToGroup(L"Group1",LOG_LEVEL_ERROR,__LINE__,__WFILE__,L"Example %d: %s", i++, L"Fourth test"); 440 441 //Macro 442 ZS_LOG_GROUP(L"Group1",LOG_LEVEL_ERROR,__LINE__,__WFILE__,L"Example %d: %s", i++, L"Fourth test"); 443 444 //Or 445 ZS_LOG_GROUP1(LOG_LEVEL_ERROR,__LINE__,__WFILE__,L"Example %d: %s", i++, L"Fourth test"); 446 447 //Or 448 ZS_LOG_GROUP1_ERROR_TRACE(L"Example %d: %s", i++, L"Fourth test"); 449 450 */ 451