~ubuntu-branches/debian/jessie/armory/jessie

« back to all changes in this revision

Viewing changes to cppForSwig/log.h

  • Committer: Package Import Robot
  • Author(s): Joseph Bisch
  • Date: 2014-10-07 10:22:45 UTC
  • Revision ID: package-import@ubuntu.com-20141007102245-2s3x3rhjxg689hek
Tags: upstream-0.92.3
ImportĀ upstreamĀ versionĀ 0.92.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
////////////////////////////////////////////////////////////////////////////////
 
2
//                                                                            //
 
3
//  Copyright (C) 2011-2014, Armory Technologies, Inc.                        //
 
4
//  Distributed under the GNU Affero General Public License (AGPL v3)         //
 
5
//  See LICENSE or http://www.gnu.org/licenses/agpl.html                      //
 
6
//                                                                            //
 
7
////////////////////////////////////////////////////////////////////////////////
 
8
//
 
9
// This is a convenient little C++ logging class that was based on a Dr. Dobbs
 
10
// article on the subject.  The logger was rewritten to include a DualStream
 
11
// that pushes the log data to both std output AND file.  This could easily 
 
12
// be extended to use an arbitrary number of streams, with a different log lvl
 
13
// set on each one.   At the moment, it only supports stdout and one file 
 
14
// simultaneously at the same loglvl, though you can use LOGDISABLESTDOUT()
 
15
// to turn off the cout portion but still write to the log file.
 
16
//
 
17
// Usage:
 
18
//
 
19
// If you do not initialize the logger, the default behavior is to log nothing. 
 
20
// All LOGERR, LOGWARN, etc, calls wll execute without error, but they will be
 
21
// diverted to a NullStream object (which throws them away).  
 
22
//
 
23
// To use the logger, all you need to do is make one call to STARTLOGGING with
 
24
// the file name and log level, and then all subsequent calls to LOGERR, etc, 
 
25
// will work as expected.
 
26
//
 
27
//    STARTLOGGING("logfile.txt", LogLvlWarn); // ignore anything below LOGWARN
 
28
//
 
29
//    LOGERR   << "This is an error message, pretty much always logged";
 
30
//    LOGWARN  << "This is a warning";
 
31
//    LOGINFO  << "Given the LogLvlWarn above, this message will be ignored";
 
32
//    LOGDEBUG << "This one will also be ignored"
 
33
//
 
34
//    FLUSHLOG();          // force-flush all write buffers
 
35
//    LOGDISABLESTDOUT();  // Stop writing log msgs to cout, only write to file
 
36
//    LOGENABLESTDOUT();   // Okay nevermind, use cout again
 
37
//
 
38
// All logged lines begin with the msg type (ERROR, WARNING, etc), the current
 
39
// time down to one second, and the file:line.  Then the message is printed.
 
40
// Newlines are added automatically to the end of each line, so there is no 
 
41
// need to use "<< endl" at the end of any log messages (in fact, it will
 
42
// croak if you try to).  Here's what the messages look like:
 
43
//
 
44
//  -ERROR - 22:16:26: (code.cpp:129) I am recording an error!
 
45
//  -WARN  - 22:16:26: (code.cpp:130) This is just a warning, don't be alarmed!
 
46
//  -DEBUG4- 22:16:26: (code.cpp:131) A seriously low-level debug message.
 
47
//
 
48
// If you'd like to change the format of the messages, you can modify the 
 
49
// #define'd FILEANDLINE just below the #include's, and/or modify the 
 
50
// getLogStream() method in the LoggerObj class (just note, you cannot 
 
51
// move the __FILE__ and/or __LINE__ commands into the getLogStream() method
 
52
// because then it will always print "log.h:282" for the file and line).
 
53
//
 
54
////////////////////////////////////////////////////////////////////////////////
 
55
#ifndef __LOG_H__
 
56
#define __LOG_H__
 
57
 
 
58
#include <sstream>
 
59
#include <ctime>
 
60
#include <string>
 
61
#include <fstream>
 
62
#include <iostream>
 
63
#include <stdio.h>
 
64
#include "OS_TranslatePath.h"
 
65
 
 
66
#define FILEANDLINE "(" << __FILE__ << ":" << __LINE__ << ") "
 
67
#define LOGERR    (LoggerObj(LogLvlError ).getLogStream() << FILEANDLINE )
 
68
#define LOGWARN   (LoggerObj(LogLvlWarn  ).getLogStream() << FILEANDLINE )
 
69
#define LOGINFO   (LoggerObj(LogLvlInfo  ).getLogStream() << FILEANDLINE )
 
70
#define LOGDEBUG  (LoggerObj(LogLvlDebug ).getLogStream() << FILEANDLINE )
 
71
#define LOGDEBUG1 (LoggerObj(LogLvlDebug1).getLogStream() << FILEANDLINE )
 
72
#define LOGDEBUG2 (LoggerObj(LogLvlDebug2).getLogStream() << FILEANDLINE )
 
73
#define LOGDEBUG3 (LoggerObj(LogLvlDebug3).getLogStream() << FILEANDLINE )
 
74
#define LOGDEBUG4 (LoggerObj(LogLvlDebug4).getLogStream() << FILEANDLINE )
 
75
#define STARTLOGGING(LOGFILE, LOGLEVEL)         \
 
76
                  Log::SetLogFile(LOGFILE);     \
 
77
                  Log::SetLogLevel(LOGLEVEL);
 
78
#define LOGDISABLESTDOUT()  Log::SuppressStdout(true)
 
79
#define LOGENABLESTDOUT()   Log::SuppressStdout(false)
 
80
#define SETLOGLEVEL(LOGLVL) Log::SetLogLevel(LOGLVL)
 
81
#define FLUSHLOG()          Log::FlushStreams()
 
82
 
 
83
 
 
84
#define MAX_LOG_FILE_SIZE (500*1024)
 
85
 
 
86
using namespace std;
 
87
 
 
88
inline string NowTime();
 
89
inline unsigned long long int NowTimeInt();
 
90
 
 
91
typedef enum 
 
92
{
 
93
   LogLvlDisabled, 
 
94
   LogLvlError, 
 
95
   LogLvlWarn, 
 
96
   LogLvlInfo, 
 
97
   LogLvlDebug, 
 
98
   LogLvlDebug1, 
 
99
   LogLvlDebug2, 
 
100
   LogLvlDebug3, 
 
101
   LogLvlDebug4 
 
102
} LogLevel;
 
103
 
 
104
 
 
105
////////////////////////////////////////////////////////////////////////////////
 
106
class LogStream
 
107
{
 
108
public:
 
109
   virtual LogStream& operator<<(const char * str) = 0;
 
110
   virtual LogStream& operator<<(string const & str) = 0;
 
111
   virtual LogStream& operator<<(int i) = 0;
 
112
   virtual LogStream& operator<<(unsigned int i) = 0;
 
113
   virtual LogStream& operator<<(unsigned long long int i) = 0;
 
114
   virtual LogStream& operator<<(float f) = 0;
 
115
   virtual LogStream& operator<<(double d) = 0;
 
116
#if !defined(_MSC_VER) && !defined(__MINGW32__) && defined(__LP64__)
 
117
   virtual LogStream& operator<<(size_t i) = 0;
 
118
#endif
 
119
};
 
120
 
 
121
////////////////////////////////////////////////////////////////////////////////
 
122
class DualStream : public LogStream
 
123
{
 
124
public:
 
125
   DualStream(void) : noStdout_(false) {}
 
126
 
 
127
   void enableStdOut(bool newbool) { noStdout_ = !newbool; }
 
128
 
 
129
   void setLogFile(string logfile, unsigned long long maxSz=MAX_LOG_FILE_SIZE)
 
130
   { 
 
131
      fname_ = logfile;
 
132
      truncateFile(fname_, maxSz);
 
133
      fout_.open(OS_TranslatePath(fname_.c_str()), ios::app); 
 
134
      fout_ << "\n\nLog file opened at " << NowTimeInt() << ": " << fname_.c_str() << endl;
 
135
   }
 
136
 
 
137
   
 
138
   void truncateFile(string logfile, unsigned long long int maxSizeInBytes)
 
139
   {
 
140
      ifstream is(OS_TranslatePath(logfile.c_str()), ios::in|ios::binary);
 
141
 
 
142
      // If file does not exist, nothing to do
 
143
      if(!is.is_open())
 
144
         return;
 
145
   
 
146
      // Check the filesize
 
147
      is.seekg(0, ios::end);
 
148
      unsigned long long int fsize = (size_t)is.tellg();
 
149
      is.close();
 
150
 
 
151
      if(fsize < maxSizeInBytes)
 
152
      {
 
153
         // If it's already smaller than max, we're done
 
154
         return;
 
155
      }
 
156
      else
 
157
      {
 
158
         // Otherwise, seek to <maxSize> before end of log file
 
159
         ifstream is(OS_TranslatePath(logfile.c_str()), ios::in|ios::binary);
 
160
         is.seekg(fsize - maxSizeInBytes);
 
161
 
 
162
         // Allocate buffer to hold the rest of the file (about maxSizeInBytes)
 
163
         unsigned long long int bytesToCopy = fsize - is.tellg();
 
164
         char* lastBytes = new char[(unsigned int)bytesToCopy];
 
165
         is.read(lastBytes, bytesToCopy);
 
166
         is.close();
 
167
         
 
168
         // Create temporary file and dump the bytes there
 
169
         string tempfile = logfile + string("temp");
 
170
         ofstream os(OS_TranslatePath(tempfile.c_str()), ios::out|ios::binary);
 
171
         os.write(lastBytes, bytesToCopy);
 
172
         os.close();
 
173
         delete[] lastBytes;
 
174
 
 
175
         // Remove the original and rename the temp file to original
 
176
                        #ifndef _MSC_VER
 
177
                                remove(logfile.c_str());
 
178
                                rename(tempfile.c_str(), logfile.c_str());
 
179
                        #else
 
180
                                _wunlink(OS_TranslatePath(logfile).c_str());
 
181
                                _wrename(OS_TranslatePath(tempfile).c_str(), OS_TranslatePath(logfile).c_str());
 
182
                        #endif
 
183
      }
 
184
   }
 
185
 
 
186
   LogStream& operator<<(const char * str)   { if(!noStdout_) cout << str;  if(fout_.is_open()) fout_ << str; return *this; }
 
187
   LogStream& operator<<(string const & str) { if(!noStdout_) cout << str.c_str(); if(fout_.is_open()) fout_ << str.c_str(); return *this; }
 
188
   LogStream& operator<<(int i)              { if(!noStdout_) cout << i;    if(fout_.is_open()) fout_ << i; return *this; }
 
189
   LogStream& operator<<(unsigned int i)     { if(!noStdout_) cout << i;    if(fout_.is_open()) fout_ << i; return *this; }
 
190
   LogStream& operator<<(unsigned long long int i) { if(!noStdout_) cout << i;    if(fout_.is_open()) fout_ << i; return *this; }
 
191
   LogStream& operator<<(float f)            { if(!noStdout_) cout << f;    if(fout_.is_open()) fout_ << f; return *this; }
 
192
   LogStream& operator<<(double d)           { if(!noStdout_) cout << d;    if(fout_.is_open()) fout_ << d; return *this; }
 
193
#if !defined(_MSC_VER) && !defined(__MINGW32__) && defined(__LP64__)
 
194
   LogStream& operator<<(size_t i)           { if(!noStdout_) cout << i;    if(fout_.is_open()) fout_ << i; return *this; }
 
195
#endif
 
196
 
 
197
   void FlushStreams(void) {cout.flush(); fout_.flush();}
 
198
 
 
199
   void newline(void) { *this << "\n"; }
 
200
   void close(void) { fout_.close(); }
 
201
 
 
202
   ofstream fout_;
 
203
   string   fname_;
 
204
   bool     noStdout_;
 
205
};
 
206
 
 
207
 
 
208
////////////////////////////////////////////////////////////////////////////////
 
209
class NullStream : public LogStream
 
210
{
 
211
public:
 
212
   LogStream& operator<<(const char * str)   { return *this; }
 
213
   LogStream& operator<<(string const & str) { return *this; }
 
214
   LogStream& operator<<(int i)              { return *this; }
 
215
   LogStream& operator<<(unsigned int i)     { return *this; }
 
216
   LogStream& operator<<(unsigned long long int i)     { return *this; }
 
217
   LogStream& operator<<(float f)            { return *this; }
 
218
   LogStream& operator<<(double d)           { return *this; }
 
219
#if !defined(_MSC_VER) && !defined(__MINGW32__) && defined(__LP64__)
 
220
   LogStream& operator<<(size_t i)           { return *this; }
 
221
#endif
 
222
 
 
223
   void FlushStreams(void) {}
 
224
};
 
225
 
 
226
 
 
227
class Log
 
228
{
 
229
public:
 
230
   Log(void) : isInitialized_(false), disableStdout_(false) {}
 
231
 
 
232
   static Log & GetInstance(const char * filename=NULL)
 
233
   {
 
234
      static Log* theOneLog=NULL;
 
235
      if(theOneLog==NULL || filename!=NULL)
 
236
      {
 
237
         // Close and delete any existing Log object
 
238
         if(theOneLog != NULL)
 
239
         {
 
240
            theOneLog->ds_.close();
 
241
            delete theOneLog;
 
242
         }
 
243
   
 
244
         // Create a Log object
 
245
         theOneLog = new Log;
 
246
   
 
247
         // Open the filestream if it's open
 
248
         if(filename != NULL)
 
249
         {
 
250
            theOneLog->ds_.setLogFile(string(filename));
 
251
            theOneLog->isInitialized_ = true;
 
252
         }
 
253
      }
 
254
      return *theOneLog;
 
255
   }
 
256
 
 
257
   ~Log(void)
 
258
   {
 
259
      CloseLogFile();
 
260
   }
 
261
 
 
262
   LogStream& Get(LogLevel level = LogLvlInfo)
 
263
   {
 
264
      if((int)level > logLevel_ || !isInitialized_)
 
265
         return ns_;
 
266
      else 
 
267
         return ds_;
 
268
   }
 
269
 
 
270
   static void SetLogFile(string logfile) { GetInstance(logfile.c_str()); }
 
271
   static void CloseLogFile(void)
 
272
   { 
 
273
      GetInstance().ds_.FlushStreams();
 
274
      GetInstance().ds_ << "Closing logfile.\n";
 
275
      GetInstance().ds_.close();
 
276
      // This doesn't actually seem to stop the StdOut logging... not sure why yet
 
277
      GetInstance().isInitialized_ = false;
 
278
      GetInstance().logLevel_ = LogLvlDisabled;
 
279
   }
 
280
 
 
281
   static void SetLogLevel(LogLevel level) { GetInstance().logLevel_ = (int)level; }
 
282
   static void SuppressStdout(bool b=true) { GetInstance().ds_.enableStdOut(!b);}
 
283
 
 
284
   static string ToString(LogLevel level)
 
285
   {
 
286
           static const char* const buffer[] = {"DISABLED", "ERROR ", "WARN  ", "INFO  ", "DEBUG ", "DEBUG1", "DEBUG2", "DEBUG3", "DEBUG4"};
 
287
      return buffer[level];
 
288
   }
 
289
 
 
290
    static bool isOpen(void) {return GetInstance().ds_.fout_.is_open();}
 
291
    static string filename(void) {return GetInstance().ds_.fname_;}
 
292
    static void FlushStreams(void) {GetInstance().ds_.FlushStreams();}
 
293
 
 
294
protected:
 
295
    DualStream ds_;
 
296
    NullStream ns_;
 
297
    int logLevel_;
 
298
    bool isInitialized_;
 
299
    bool disableStdout_;
 
300
private:
 
301
    Log(const Log&);
 
302
    Log& operator =(const Log&);
 
303
 
 
304
};
 
305
 
 
306
 
 
307
 
 
308
// I missed the opportunity with the above class, to design it as a constantly
 
309
// constructing/destructing object that adds a newline on every destruct.  So 
 
310
// instead I create this little wrapper that does it for me.
 
311
class LoggerObj
 
312
{
 
313
public:
 
314
   LoggerObj(LogLevel lvl) : logLevel_(lvl) {}
 
315
 
 
316
   LogStream & getLogStream(void) 
 
317
   { 
 
318
      LogStream & lg = Log::GetInstance().Get(logLevel_);
 
319
      lg << "-" << Log::ToString(logLevel_);
 
320
      lg << "- " << NowTimeInt() << ": ";
 
321
      return lg;
 
322
   }
 
323
 
 
324
   ~LoggerObj(void) 
 
325
   { 
 
326
      Log::GetInstance().Get(logLevel_) << "\n";
 
327
      Log::GetInstance().FlushStreams();
 
328
   }
 
329
 
 
330
private:
 
331
   LogLevel logLevel_;
 
332
};
 
333
 
 
334
 
 
335
 
 
336
 
 
337
 
 
338
//#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
 
339
//#   if defined (BUILDING_FILELOG_DLL)
 
340
//#       define FILELOG_DECLSPEC   __declspec (dllexport)
 
341
//#   elif defined (USING_FILELOG_DLL)
 
342
//#       define FILELOG_DECLSPEC   __declspec (dllimport)
 
343
//#   else
 
344
//#       define FILELOG_DECLSPEC
 
345
//#   endif // BUILDING_DBSIMPLE_DLL
 
346
//#else
 
347
//#   define FILELOG_DECLSPEC
 
348
//#endif // _WIN32
 
349
 
 
350
 
 
351
//#ifndef FILELOG_MAX_LEVEL
 
352
//#define FILELOG_MAX_LEVEL LogLvlDEBUG4
 
353
//#endif
 
354
 
 
355
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
 
356
 
 
357
#include <windows.h>
 
358
 
 
359
inline string NowTime()
 
360
{
 
361
    const int MAX_LEN = 200;
 
362
    char buffer[MAX_LEN];
 
363
    if (GetTimeFormatA(LOCALE_USER_DEFAULT, 0, 0, 
 
364
            "HH':'mm':'ss", buffer, MAX_LEN) == 0)
 
365
        return "Error in NowTime()";
 
366
 
 
367
    char result[100] = {0};
 
368
    static DWORD first = GetTickCount();
 
369
    sprintf(result, "%s.%03ld", buffer, (long)(GetTickCount() - first) % 1000); 
 
370
    return result;
 
371
}
 
372
 
 
373
inline unsigned long long int NowTimeInt(void)
 
374
{
 
375
   time_t t;
 
376
   time(&t);
 
377
   return (unsigned long long int)t;
 
378
}
 
379
 
 
380
#else
 
381
 
 
382
#include <sys/time.h>
 
383
 
 
384
inline string NowTime()
 
385
{
 
386
    char buffer[11];
 
387
    time_t t;
 
388
    time(&t);
 
389
    tm r = {0};
 
390
    strftime(buffer, sizeof(buffer), "%X", localtime_r(&t, &r));
 
391
    struct timeval tv;
 
392
    gettimeofday(&tv, 0);
 
393
    char result[100] = {0};
 
394
    sprintf(result, "%s", buffer);
 
395
    return result;
 
396
}
 
397
 
 
398
inline unsigned long long int NowTimeInt(void)
 
399
{
 
400
   time_t t;
 
401
   time(&t);
 
402
   return (unsigned long long int)t;
 
403
}
 
404
 
 
405
#endif //WIN32
 
406
 
 
407
#endif //__LOG_H__