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