root/trunk/whisperlib/common/base/log.cc

Revision 7, 6.1 kB (checked in by whispercastorg, 2 years ago)

version 0.2.0

Line 
1 // Copyright (c) 2009, Whispersoft s.r.l.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Whispersoft s.r.l. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Cosmin Tudorache & Catalin Popescu
31
32 #include <sys/time.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <iomanip>
37 #include "common/base/log.h"
38 #include "common/sync/mutex.h"
39 #include "common/base/system.h"
40 #include "common/base/gflags.h"
41
42 //////////////////////////////////////////////////////////////////////
43
44 DEFINE_int32(loglevel,
45              LINFO,
46              "We initialize the log at this maximum level."
47              "(we log messages with levels less then this)");
48
49 DEFINE_string(logdir,
50               "/tmp",
51               "We write the log file unde this directory.");
52
53 DEFINE_bool(alsologtostderr,
54             false,
55             "If this is turned on, we also write log lines to this stderr");
56
57 DEFINE_bool(logcolors,
58             false,
59             "If this is turned on, the log will use bash colors");
60
61 DEFINE_bool(logtid,
62             false,
63             "Log the thread ID");
64
65 DEFINE_bool(logflush,
66             false,
67             "Turn this on to flush log after each line");
68
69 //////////////////////////////////////////////////////////////////////
70
71 void InitLogger(int level, const char* filename) {
72   if ( log_internal::gLogger != NULL ) return;
73   log_internal::gLogger = new log_internal::Log(level, filename);
74 }
75 void InitDefaultLogger(const char* progname) {
76   if ( log_internal::gLogger != NULL ) return;
77   const string log_file(FLAGS_logdir + "/" + progname + ".LOG");
78   cerr << "Writing log to: " << log_file << endl;
79   log_internal::gLogger =
80     new log_internal::Log(FLAGS_loglevel, log_file.c_str());
81 }
82 void FlushLogger() {
83   if ( log_internal::gLogger != NULL ) {
84     log_internal::gLogger->Flush();
85   }
86 }
87
88 namespace log_internal {
89
90 Log* gLogger       = NULL;
91
92
93 //////////////////////////////////////////////////////////////////////
94
95 static const char* kLogHeader[] = { "F", "E", "W", "I", "D", "X" };
96 static const char* kLogColors[] = { "\033[1;31m",  // FATAL   Red Bold
97                                     "\033[31m",    // ERROR   Red
98                                     "\033[35m",    // WARNING Magenta(Purple)
99                                     "\033[30m",    // INFO    Black
100                                     "\033[37m",    // DEBUG   Gray
101                                     "\033[34m"};   // other   Blue
102
103 static void LogHeader(std::ostream& stream, unsigned level) {
104   struct timeval tv;
105   struct timezone tz;
106   struct tm tm_time;
107   gettimeofday(&tv, &tz);
108   localtime_r(&tv.tv_sec, &tm_time);
109   static const int kNumLevels = sizeof(kLogHeader) / sizeof(*kLogHeader);
110   if ( level >= kNumLevels ) {
111     level = kNumLevels - 1;
112   }
113   if ( FLAGS_logcolors ) {
114     // print color
115     stream << kLogColors[level];
116   }
117   const string header(strutil::StringPrintf(
118                           "%s [%04d%02d%02d %02d%02d%02d.%03ld] %s",
119                           kLogHeader[level],
120                           1900 + tm_time.tm_year,
121                           1 + tm_time.tm_mon,
122                           tm_time.tm_mday,
123                           tm_time.tm_hour,
124                           tm_time.tm_min,
125                           tm_time.tm_sec,
126                           (tv.tv_usec / 1000),
127                           FLAGS_logtid
128                           ? strutil::StringPrintf(
129                               "[TID: %d]",
130                               static_cast<int>(::pthread_self()) ).c_str()
131                           : ""));
132   stream << header;
133 }
134
135 //////////////////////////////////////////////////////////////////////
136
137 LogLine::LogLine(Log* log, int level)
138     : log_(log),
139       is_fatal_(level == LFATAL) {
140   LogHeader(stream_, level);
141 }
142
143 LogLine::~LogLine() {
144   if ( FLAGS_logcolors ) {
145     stream_ << "\033[0m";
146   }
147   stream_ << "\n";
148   log_->OutputString(stream_.str());
149   if ( is_fatal_ ) {
150     ::abort();
151   }
152 }
153
154 //////////////////////////////////////////////////////////////////////
155
156 Log::Log(int level, const char* filename)
157   : mutex_(new synch::Mutex(true)),  // reentrant
158     level_(level),
159     log_file_(NULL),
160     tee_file_(NULL) {
161   log_file_ = fopen(filename, "a");
162   if ( log_file_ == NULL ) {
163     fprintf(stderr,
164             "Cound not open the log file: [%s]. Using stderr.\n",
165             filename);
166     log_file_ = stderr;
167   } else {
168     if ( FLAGS_alsologtostderr ) {
169       tee_file_ = stderr;
170     }
171   }
172 }
173
174 Log::~Log() {
175   if ( log_file_ != stderr ) {
176     fclose(log_file_);
177   }
178   delete mutex_;
179 }
180
181 void Log::Flush() {
182   fflush(log_file_);
183 }
184
185 void Log::OutputString(const string& s) {
186   mutex_->Lock();
187   fprintf(log_file_, "%s", s.c_str());
188   if ( tee_file_ != NULL ) {
189     fprintf(tee_file_, "%s", s.c_str());
190   }
191   if ( FLAGS_logflush ) {
192     fflush(log_file_);
193   }
194   mutex_->Unlock();
195 }
196 }
Note: See TracBrowser for help on using the browser.