1 /*******************************************************
2
3 CoolReader Engine
4
5 crlog.cpp: logging classes implementation
6
7 (c) Vadim Lopatin, 2000-2006
8 This source code is distributed under the terms of
9 GNU General Public License
10 See LICENSE file for details
11
12 *******************************************************/
13
14 #include "../include/crlog.h"
15 #include "lvtypes.h"
16
17 #ifdef LINUX
18 #include <sys/time.h>
19 #endif
20 #include <time.h>
21 #include <stdio.h>
22
23 #if !defined(__SYMBIAN32__) && defined(_WIN32)
24 extern "C" {
25 #include <windows.h>
26 }
27 #endif
28
29 class CRFileLogger;
30
31 CRLog * CRLog::CRLOG = NULL;
setLogger(CRLog * logger)32 void CRLog::setLogger( CRLog * logger )
33 {
34 if ( CRLOG!=NULL ) {
35 delete CRLOG;
36 }
37 CRLOG = logger;
38 }
39
setLogLevel(CRLog::log_level level)40 void CRLog::setLogLevel( CRLog::log_level level )
41 {
42 if ( !CRLOG )
43 return;
44 warn( "Changing log level from %d to %d", (int)CRLOG->curr_level, (int)level );
45 CRLOG->curr_level = level;
46 }
47
getLogLevel()48 CRLog::log_level CRLog::getLogLevel()
49 {
50 if ( !CRLOG )
51 return LL_INFO;
52 return CRLOG->curr_level;
53 }
54
isLogLevelEnabled(CRLog::log_level level)55 bool CRLog::isLogLevelEnabled( CRLog::log_level level )
56 {
57 if ( !CRLOG )
58 return false;
59 return (CRLOG->curr_level >= level);
60 }
61
fatal(const char * msg,...)62 void CRLog::fatal( const char * msg, ... )
63 {
64 if ( !CRLOG )
65 return;
66 va_list args;
67 va_start( args, msg );
68 CRLOG->log( "FATAL", msg, args );
69 va_end(args);
70 }
71
error(const char * msg,...)72 void CRLog::error( const char * msg, ... )
73 {
74 if ( !CRLOG || CRLOG->curr_level<LL_ERROR )
75 return;
76 va_list args;
77 va_start( args, msg );
78 CRLOG->log( "ERROR", msg, args );
79 va_end(args);
80 }
81
warn(const char * msg,...)82 void CRLog::warn( const char * msg, ... )
83 {
84 if ( !CRLOG || CRLOG->curr_level<LL_WARN )
85 return;
86 va_list args;
87 va_start( args, msg );
88 CRLOG->log( "WARN", msg, args );
89 va_end(args);
90 }
91
info(const char * msg,...)92 void CRLog::info( const char * msg, ... )
93 {
94 if ( !CRLOG || CRLOG->curr_level<LL_INFO )
95 return;
96 va_list args;
97 va_start( args, msg );
98 CRLOG->log( "INFO", msg, args );
99 va_end(args);
100 }
101
debug(const char * msg,...)102 void CRLog::debug( const char * msg, ... )
103 {
104 if ( !CRLOG || CRLOG->curr_level<LL_DEBUG )
105 return;
106 va_list args;
107 va_start( args, msg );
108 CRLOG->log( "DEBUG", msg, args );
109 va_end(args);
110 }
111
trace(const char * msg,...)112 void CRLog::trace( const char * msg, ... )
113 {
114 if ( !CRLOG || CRLOG->curr_level<LL_TRACE )
115 return;
116 va_list args;
117 va_start( args, msg );
118 CRLOG->log( "TRACE", msg, args );
119 va_end(args);
120 }
121
CRLog()122 CRLog::CRLog()
123 : curr_level(LL_INFO)
124 {
125 }
126
~CRLog()127 CRLog::~CRLog()
128 {
129 }
130
131
132 // private class CRFileLogger
133
134 #ifndef LOG_HEAP_USAGE
135 #define LOG_HEAP_USAGE 0
136 #endif
137
138 #ifdef _WIN32
139 static bool __timerInitialized = false;
140 static double __timeTicksPerMillis;
141 static lUInt64 __timeStart;
142 static lUInt64 __timeAbsolute;
143 static lUInt64 __startTimeMillis;
144
CRReinitTimer()145 static void CRReinitTimer() {
146 LARGE_INTEGER tps;
147 QueryPerformanceFrequency(&tps);
148 __timeTicksPerMillis = (double)(tps.QuadPart / 1000L);
149 LARGE_INTEGER queryTime;
150 QueryPerformanceCounter(&queryTime);
151 __timeStart = (lUInt64)(queryTime.QuadPart / __timeTicksPerMillis);
152 __timerInitialized = true;
153 FILETIME ft;
154 GetSystemTimeAsFileTime(&ft);
155 __startTimeMillis = (ft.dwLowDateTime | (((lUInt64)ft.dwHighDateTime) << 32)) / 10000;
156 }
157 #endif
158
GetCurrentTimeMillis()159 static lUInt64 GetCurrentTimeMillis() {
160 #if defined(LINUX) || defined(ANDROID) || defined(_LINUX)
161 timeval ts;
162 gettimeofday(&ts, NULL);
163 return ts.tv_sec * (lUInt64)1000 + ts.tv_usec / 1000;
164 #else
165 #ifdef _WIN32
166 if (!__timerInitialized) {
167 CRReinitTimer();
168 return __startTimeMillis;
169 } else {
170 LARGE_INTEGER queryTime;
171 QueryPerformanceCounter(&queryTime);
172 __timeAbsolute = (lUInt64)(queryTime.QuadPart / __timeTicksPerMillis);
173 return __startTimeMillis + (lUInt64)(__timeAbsolute - __timeStart);
174 }
175 #else
176 #error * You should define GetCurrentTimeMillis() *
177 #endif
178 #endif
179 }
180
181 class CRFileLogger : public CRLog
182 {
183 protected:
184 FILE * f;
185 bool autoClose;
186 bool autoFlush;
log(const char * level,const char * msg,va_list args)187 virtual void log( const char * level, const char * msg, va_list args )
188 {
189 if ( !f )
190 return;
191 #ifdef LINUX
192 struct timeval tval;
193 gettimeofday( &tval, NULL );
194 int ms = tval.tv_usec;
195 time_t t = tval.tv_sec;
196 #if LOG_HEAP_USAGE
197 struct mallinfo mi = mallinfo();
198 int memusage = mi.arena;
199 #endif
200 #else
201 lUInt64 ts = GetCurrentTimeMillis();
202 //time_t t = (time_t)time(0);
203 time_t t = ts / 1000;
204 int ms = (ts % 1000) * 1000;
205 #if LOG_HEAP_USAGE
206 int memusage = 0;
207 #endif
208 #endif
209 struct tm * bt = localtime(&t);
210 #if LOG_HEAP_USAGE
211 fprintf(f, "%04d/%02d/%02d %02d:%02d:%02d.%04d [%d] %s ", bt->tm_year+1900, bt->tm_mon+1, bt->tm_mday, bt->tm_hour, bt->tm_min, bt->tm_sec, ms/100, memusage, level);
212 #else
213 fprintf(f, "%04d/%02d/%02d %02d:%02d:%02d.%04d %s ", bt->tm_year+1900, bt->tm_mon+1, bt->tm_mday, bt->tm_hour, bt->tm_min, bt->tm_sec, ms/100, level);
214 #endif
215 vfprintf( f, msg, args );
216 fprintf(f, "\n" );
217 if ( autoFlush )
218 fflush( f );
219 }
220 public:
CRFileLogger(FILE * file,bool _autoClose,bool _autoFlush)221 CRFileLogger( FILE * file, bool _autoClose, bool _autoFlush )
222 : f(file), autoClose(_autoClose), autoFlush( _autoFlush )
223 {
224 info( "Started logging" );
225 }
CRFileLogger(const char * fname,bool _autoFlush)226 CRFileLogger( const char * fname, bool _autoFlush )
227 : f(fopen( fname, "wt" )), autoClose(true), autoFlush( _autoFlush )
228 {
229 static unsigned char utf8sign[] = {0xEF, 0xBB, 0xBF};
230 static const char * log_level_names[] = {
231 "FATAL",
232 "ERROR",
233 "WARN",
234 "INFO",
235 "DEBUG",
236 "TRACE",
237 };
238 fwrite( utf8sign, 3, 1, f);
239 info( "Started logging. Level=%s", log_level_names[getLogLevel()] );
240 }
~CRFileLogger()241 virtual ~CRFileLogger() {
242 if ( f && autoClose ) {
243 info( "Stopped logging" );
244 fclose( f );
245 }
246 f = NULL;
247 }
248 };
249
250
251 // CRLog
setFileLogger(const char * fname,bool autoFlush)252 void CRLog::setFileLogger( const char * fname, bool autoFlush )
253 {
254 setLogger( new CRFileLogger( fname, autoFlush ) );
255 }
256
setStdoutLogger()257 void CRLog::setStdoutLogger()
258 {
259 setLogger( new CRFileLogger( (FILE*)stdout, false, true ) );
260 }
261
setStderrLogger()262 void CRLog::setStderrLogger()
263 {
264 setLogger( new CRFileLogger( (FILE*)stderr, false, true ) );
265 }
266