comparison Core/Logging.cpp @ 2015:bcc575732aef

New option "--logfile" to output the Orthanc log to the given file
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 13 Jun 2016 15:07:53 +0200
parents e39a2657f1c6
children ddc75c6c712d
comparison
equal deleted inserted replaced
2014:e39a2657f1c6 2015:bcc575732aef
45 45
46 void Finalize() 46 void Finalize()
47 { 47 {
48 } 48 }
49 49
50 void Reset()
51 {
52 }
53
54 void Flush()
55 {
56 }
57
50 void EnableInfoLevel(bool enabled) 58 void EnableInfoLevel(bool enabled)
51 { 59 {
52 } 60 }
53 61
54 void EnableTraceLevel(bool enabled) 62 void EnableTraceLevel(bool enabled)
63 {
64 }
65
66 void SetTargetFile(const std::string& path)
55 { 67 {
56 } 68 }
57 69
58 void SetTargetFolder(const std::string& path) 70 void SetTargetFolder(const std::string& path)
59 { 71 {
83 #endif 95 #endif
84 96
85 97
86 namespace 98 namespace
87 { 99 {
88 struct LoggingState 100 struct LoggingContext
89 { 101 {
90 bool infoEnabled_; 102 bool infoEnabled_;
91 bool traceEnabled_; 103 bool traceEnabled_;
104 std::string targetFile_;
105 std::string targetFolder_;
92 106
93 std::ostream* error_; 107 std::ostream* error_;
94 std::ostream* warning_; 108 std::ostream* warning_;
95 std::ostream* info_; 109 std::ostream* info_;
96 110
97 std::auto_ptr<std::ofstream> file_; 111 std::auto_ptr<std::ofstream> file_;
98 112
99 LoggingState() : 113 LoggingContext() :
100 infoEnabled_(false), 114 infoEnabled_(false),
101 traceEnabled_(false), 115 traceEnabled_(false),
102 error_(&std::cerr), 116 error_(&std::cerr),
103 warning_(&std::cerr), 117 warning_(&std::cerr),
104 info_(&std::cerr) 118 info_(&std::cerr)
107 }; 121 };
108 } 122 }
109 123
110 124
111 125
112 static std::auto_ptr<LoggingState> loggingState_; 126 static std::auto_ptr<LoggingContext> loggingContext_;
113 static boost::mutex loggingMutex_; 127 static boost::mutex loggingMutex_;
114 128
115 129
116 130
117 namespace Orthanc 131 namespace Orthanc
159 log = (root / (programName + ".log" + suffix + "." + std::string(date))); 173 log = (root / (programName + ".log" + suffix + "." + std::string(date)));
160 link = (root / (programName + ".log" + suffix)); 174 link = (root / (programName + ".log" + suffix));
161 } 175 }
162 176
163 177
164 static void PrepareLogFile(std::auto_ptr<std::ofstream>& file, 178 static void PrepareLogFolder(std::auto_ptr<std::ofstream>& file,
165 const std::string& suffix, 179 const std::string& suffix,
166 const std::string& directory) 180 const std::string& directory)
167 { 181 {
168 boost::filesystem::path log, link; 182 boost::filesystem::path log, link;
169 GetLogPath(log, link, suffix, directory); 183 GetLogPath(log, link, suffix, directory);
170 184
171 #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) 185 #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
178 192
179 193
180 void Initialize() 194 void Initialize()
181 { 195 {
182 boost::mutex::scoped_lock lock(loggingMutex_); 196 boost::mutex::scoped_lock lock(loggingMutex_);
183 loggingState_.reset(new LoggingState); 197 loggingContext_.reset(new LoggingContext);
184 } 198 }
185 199
186 void Finalize() 200 void Finalize()
187 { 201 {
188 boost::mutex::scoped_lock lock(loggingMutex_); 202 boost::mutex::scoped_lock lock(loggingMutex_);
189 loggingState_.reset(NULL); 203 loggingContext_.reset(NULL);
204 }
205
206 void Reset()
207 {
208 // Recover the old logging context
209 std::auto_ptr<LoggingContext> old;
210
211 {
212 boost::mutex::scoped_lock lock(loggingMutex_);
213 if (loggingContext_.get() == NULL)
214 {
215 return;
216 }
217 else
218 {
219 old = loggingContext_;
220
221 // Create a new logging context,
222 loggingContext_.reset(new LoggingContext);
223 }
224 }
225
226 EnableInfoLevel(old->infoEnabled_);
227 EnableTraceLevel(old->traceEnabled_);
228
229 if (!old->targetFolder_.empty())
230 {
231 SetTargetFolder(old->targetFolder_);
232 }
233 else if (!old->targetFile_.empty())
234 {
235 SetTargetFile(old->targetFile_);
236 }
190 } 237 }
191 238
192 void EnableInfoLevel(bool enabled) 239 void EnableInfoLevel(bool enabled)
193 { 240 {
194 boost::mutex::scoped_lock lock(loggingMutex_); 241 boost::mutex::scoped_lock lock(loggingMutex_);
195 assert(loggingState_.get() != NULL); 242 assert(loggingContext_.get() != NULL);
196 243
197 loggingState_->infoEnabled_ = enabled; 244 loggingContext_->infoEnabled_ = enabled;
245
246 if (!enabled)
247 {
248 // Also disable the "TRACE" level when info-level debugging is disabled
249 loggingContext_->traceEnabled_ = false;
250 }
198 } 251 }
199 252
200 void EnableTraceLevel(bool enabled) 253 void EnableTraceLevel(bool enabled)
201 { 254 {
202 boost::mutex::scoped_lock lock(loggingMutex_); 255 boost::mutex::scoped_lock lock(loggingMutex_);
203 assert(loggingState_.get() != NULL); 256 assert(loggingContext_.get() != NULL);
204 257
205 loggingState_->traceEnabled_ = enabled; 258 loggingContext_->traceEnabled_ = enabled;
206 259
207 if (enabled) 260 if (enabled)
208 { 261 {
209 // Also enable the "INFO" level when trace-level debugging is enabled 262 // Also enable the "INFO" level when trace-level debugging is enabled
210 loggingState_->infoEnabled_ = true; 263 loggingContext_->infoEnabled_ = true;
264 }
265 }
266
267
268 static void CheckFile(std::auto_ptr<std::ofstream>& f)
269 {
270 if (loggingContext_->file_.get() == NULL ||
271 !loggingContext_->file_->is_open())
272 {
273 throw OrthancException(ErrorCode_CannotWriteFile);
211 } 274 }
212 } 275 }
213 276
214 void SetTargetFolder(const std::string& path) 277 void SetTargetFolder(const std::string& path)
215 { 278 {
216 boost::mutex::scoped_lock lock(loggingMutex_); 279 boost::mutex::scoped_lock lock(loggingMutex_);
217 assert(loggingState_.get() != NULL); 280 assert(loggingContext_.get() != NULL);
218 281
219 PrepareLogFile(loggingState_->file_, "" /* no suffix */, path); 282 PrepareLogFolder(loggingContext_->file_, "" /* no suffix */, path);
220 283 CheckFile(loggingContext_->file_);
221 loggingState_->warning_ = loggingState_->file_.get(); 284
222 loggingState_->error_ = loggingState_->file_.get(); 285 loggingContext_->targetFile_.clear();
223 loggingState_->info_ = loggingState_->file_.get(); 286 loggingContext_->targetFolder_ = path;
224 } 287 loggingContext_->warning_ = loggingContext_->file_.get();
288 loggingContext_->error_ = loggingContext_->file_.get();
289 loggingContext_->info_ = loggingContext_->file_.get();
290 }
291
292
293 void SetTargetFile(const std::string& path)
294 {
295 boost::mutex::scoped_lock lock(loggingMutex_);
296 assert(loggingContext_.get() != NULL);
297
298 loggingContext_->file_.reset(new std::ofstream(path.c_str(), std::fstream::app));
299 CheckFile(loggingContext_->file_);
300
301 loggingContext_->targetFile_ = path;
302 loggingContext_->targetFolder_.clear();
303 loggingContext_->warning_ = loggingContext_->file_.get();
304 loggingContext_->error_ = loggingContext_->file_.get();
305 loggingContext_->info_ = loggingContext_->file_.get();
306 }
307
225 308
226 InternalLogger::InternalLogger(const char* level, 309 InternalLogger::InternalLogger(const char* level,
227 const char* file, 310 const char* file,
228 int line) : 311 int line) :
229 lock_(loggingMutex_), 312 lock_(loggingMutex_),
230 stream_(&null_) // By default, logging to "/dev/null" is simulated 313 stream_(&null_) // By default, logging to "/dev/null" is simulated
231 { 314 {
232 if (loggingState_.get() == NULL) 315 if (loggingContext_.get() == NULL)
233 { 316 {
234 fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine\n"); 317 fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine\n");
235 return; 318 return;
236 } 319 }
237 320
238 LogLevel l = StringToLogLevel(level); 321 LogLevel l = StringToLogLevel(level);
239 322
240 if ((l == LogLevel_Info && !loggingState_->infoEnabled_) || 323 if ((l == LogLevel_Info && !loggingContext_->infoEnabled_) ||
241 (l == LogLevel_Trace && !loggingState_->traceEnabled_)) 324 (l == LogLevel_Trace && !loggingContext_->traceEnabled_))
242 { 325 {
243 // This logging level is disabled, directly exit and unlock 326 // This logging level is disabled, directly exit and unlock
244 // the mutex to speed-up things. The stream is set to "/dev/null" 327 // the mutex to speed-up things. The stream is set to "/dev/null"
245 lock_.unlock(); 328 lock_.unlock();
246 return; 329 return;
290 header = std::string(date) + path.filename().string() + ":" + boost::lexical_cast<std::string>(line) + "] "; 373 header = std::string(date) + path.filename().string() + ":" + boost::lexical_cast<std::string>(line) + "] ";
291 } 374 }
292 375
293 376
294 // The header is computed, we now re-lock the mutex to access 377 // The header is computed, we now re-lock the mutex to access
295 // the stream objects. Pay attention that "loggingState_", 378 // the stream objects. Pay attention that "loggingContext_",
296 // "infoEnabled_" or "traceEnabled_" might have changed while 379 // "infoEnabled_" or "traceEnabled_" might have changed while
297 // the mutex was unlocked. 380 // the mutex was unlocked.
298 lock_.lock(); 381 lock_.lock();
299 382
300 if (loggingState_.get() == NULL) 383 if (loggingContext_.get() == NULL)
301 { 384 {
302 fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine\n"); 385 fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine\n");
303 return; 386 return;
304 } 387 }
305 388
306 switch (l) 389 switch (l)
307 { 390 {
308 case LogLevel_Error: 391 case LogLevel_Error:
309 stream_ = loggingState_->error_; 392 stream_ = loggingContext_->error_;
310 break; 393 break;
311 394
312 case LogLevel_Warning: 395 case LogLevel_Warning:
313 stream_ = loggingState_->warning_; 396 stream_ = loggingContext_->warning_;
314 break; 397 break;
315 398
316 case LogLevel_Info: 399 case LogLevel_Info:
317 if (loggingState_->infoEnabled_) 400 if (loggingContext_->infoEnabled_)
318 { 401 {
319 stream_ = loggingState_->info_; 402 stream_ = loggingContext_->info_;
320 } 403 }
321 404
322 break; 405 break;
323 406
324 case LogLevel_Trace: 407 case LogLevel_Trace:
325 if (loggingState_->traceEnabled_) 408 if (loggingContext_->traceEnabled_)
326 { 409 {
327 stream_ = loggingState_->info_; 410 stream_ = loggingContext_->info_;
328 } 411 }
329 412
330 break; 413 break;
331 414
332 default: 415 default:
358 stream_->flush(); 441 stream_->flush();
359 } 442 }
360 } 443 }
361 444
362 445
446 void Flush()
447 {
448 boost::mutex::scoped_lock lock(loggingMutex_);
449
450 if (loggingContext_.get() != NULL &&
451 loggingContext_->file_.get() != NULL)
452 {
453 loggingContext_->file_->flush();
454 }
455 }
363 } 456 }
364 } 457 }
365 458
366 #endif // ORTHANC_ENABLE_LOGGING 459 #endif // ORTHANC_ENABLE_LOGGING