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