Mercurial > hg > orthanc
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 |