Mercurial > hg > orthanc
comparison OrthancFramework/Sources/Logging.cpp @ 4044:d25f4c0fa160 framework
splitting code into OrthancFramework and OrthancServer
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 10 Jun 2020 20:30:34 +0200 |
parents | Core/Logging.cpp@05a363186da6 |
children | bf7b9edf6b81 |
comparison
equal
deleted
inserted
replaced
4043:6c6239aec462 | 4044:d25f4c0fa160 |
---|---|
1 /** | |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU General Public License as | |
9 * published by the Free Software Foundation, either version 3 of the | |
10 * License, or (at your option) any later version. | |
11 * | |
12 * In addition, as a special exception, the copyright holders of this | |
13 * program give permission to link the code of its release with the | |
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
15 * that use the same license as the "OpenSSL" library), and distribute | |
16 * the linked executables. You must obey the GNU General Public License | |
17 * in all respects for all of the code used other than "OpenSSL". If you | |
18 * modify file(s) with this exception, you may extend this exception to | |
19 * your version of the file(s), but you are not obligated to do so. If | |
20 * you do not wish to do so, delete this exception statement from your | |
21 * version. If you delete this exception statement from all source files | |
22 * in the program, then also delete it here. | |
23 * | |
24 * This program is distributed in the hope that it will be useful, but | |
25 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
27 * General Public License for more details. | |
28 * | |
29 * You should have received a copy of the GNU General Public License | |
30 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
31 **/ | |
32 | |
33 | |
34 #include "PrecompiledHeaders.h" | |
35 #include "Logging.h" | |
36 | |
37 #include "OrthancException.h" | |
38 | |
39 | |
40 namespace Orthanc | |
41 { | |
42 namespace Logging | |
43 { | |
44 const char* EnumerationToString(LogLevel level) | |
45 { | |
46 switch (level) | |
47 { | |
48 case LogLevel_ERROR: | |
49 return "ERROR"; | |
50 | |
51 case LogLevel_WARNING: | |
52 return "WARNING"; | |
53 | |
54 case LogLevel_INFO: | |
55 return "INFO"; | |
56 | |
57 case LogLevel_TRACE: | |
58 return "TRACE"; | |
59 | |
60 default: | |
61 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
62 } | |
63 } | |
64 | |
65 | |
66 LogLevel StringToLogLevel(const char *level) | |
67 { | |
68 if (strcmp(level, "ERROR") == 0) | |
69 { | |
70 return LogLevel_ERROR; | |
71 } | |
72 else if (strcmp(level, "WARNING") == 0) | |
73 { | |
74 return LogLevel_WARNING; | |
75 } | |
76 else if (strcmp(level, "INFO") == 0) | |
77 { | |
78 return LogLevel_INFO; | |
79 } | |
80 else if (strcmp(level, "TRACE") == 0) | |
81 { | |
82 return LogLevel_TRACE; | |
83 } | |
84 else | |
85 { | |
86 throw OrthancException(ErrorCode_InternalError); | |
87 } | |
88 } | |
89 } | |
90 } | |
91 | |
92 | |
93 #if ORTHANC_ENABLE_LOGGING != 1 | |
94 | |
95 namespace Orthanc | |
96 { | |
97 namespace Logging | |
98 { | |
99 void InitializePluginContext(void* pluginContext) | |
100 { | |
101 } | |
102 | |
103 void Initialize() | |
104 { | |
105 } | |
106 | |
107 void Finalize() | |
108 { | |
109 } | |
110 | |
111 void Reset() | |
112 { | |
113 } | |
114 | |
115 void Flush() | |
116 { | |
117 } | |
118 | |
119 void EnableInfoLevel(bool enabled) | |
120 { | |
121 } | |
122 | |
123 void EnableTraceLevel(bool enabled) | |
124 { | |
125 } | |
126 | |
127 bool IsTraceLevelEnabled() | |
128 { | |
129 return false; | |
130 } | |
131 | |
132 bool IsInfoLevelEnabled() | |
133 { | |
134 return false; | |
135 } | |
136 | |
137 void SetTargetFile(const std::string& path) | |
138 { | |
139 } | |
140 | |
141 void SetTargetFolder(const std::string& path) | |
142 { | |
143 } | |
144 } | |
145 } | |
146 | |
147 | |
148 #elif ORTHANC_ENABLE_LOGGING_STDIO == 1 | |
149 | |
150 /********************************************************* | |
151 * Logger compatible with <stdio.h> OR logger that sends its | |
152 * output to the emscripten html5 api (depending on the | |
153 * definition of __EMSCRIPTEN__) | |
154 *********************************************************/ | |
155 | |
156 #include <stdio.h> | |
157 | |
158 #ifdef __EMSCRIPTEN__ | |
159 # include <emscripten/html5.h> | |
160 #endif | |
161 | |
162 namespace Orthanc | |
163 { | |
164 namespace Logging | |
165 { | |
166 static bool infoEnabled_ = false; | |
167 static bool traceEnabled_ = false; | |
168 | |
169 #ifdef __EMSCRIPTEN__ | |
170 static void ErrorLogFunc(const char* msg) | |
171 { | |
172 emscripten_console_error(msg); | |
173 } | |
174 | |
175 static void WarningLogFunc(const char* msg) | |
176 { | |
177 emscripten_console_warn(msg); | |
178 } | |
179 | |
180 static void InfoLogFunc(const char* msg) | |
181 { | |
182 emscripten_console_log(msg); | |
183 } | |
184 | |
185 static void TraceLogFunc(const char* msg) | |
186 { | |
187 emscripten_console_log(msg); | |
188 } | |
189 #else /* __EMSCRIPTEN__ not #defined */ | |
190 static void ErrorLogFunc(const char* msg) | |
191 { | |
192 fprintf(stderr, "E: %s\n", msg); | |
193 } | |
194 | |
195 static void WarningLogFunc(const char*) | |
196 { | |
197 fprintf(stdout, "W: %s\n", msg); | |
198 } | |
199 | |
200 static void InfoLogFunc(const char*) | |
201 { | |
202 fprintf(stdout, "I: %s\n", msg); | |
203 } | |
204 | |
205 static void TraceLogFunc(const char*) | |
206 { | |
207 fprintf(stdout, "T: %s\n", msg); | |
208 } | |
209 #endif /* __EMSCRIPTEN__ */ | |
210 | |
211 | |
212 InternalLogger::~InternalLogger() | |
213 { | |
214 std::string message = messageStream_.str(); | |
215 | |
216 switch (level_) | |
217 { | |
218 case LogLevel_ERROR: | |
219 ErrorLogFunc(message.c_str()); | |
220 break; | |
221 | |
222 case LogLevel_WARNING: | |
223 WarningLogFunc(message.c_str()); | |
224 break; | |
225 | |
226 case LogLevel_INFO: | |
227 if (infoEnabled_) | |
228 { | |
229 InfoLogFunc(message.c_str()); | |
230 // TODO: stone_console_info(message_.c_str()); | |
231 } | |
232 break; | |
233 | |
234 case LogLevel_TRACE: | |
235 if (traceEnabled_) | |
236 { | |
237 TraceLogFunc(message.c_str()); | |
238 } | |
239 break; | |
240 | |
241 default: | |
242 { | |
243 std::stringstream ss; | |
244 ss << "Unknown log level (" << level_ << ") for message: " << message; | |
245 std::string s = ss.str(); | |
246 ErrorLogFunc(s.c_str()); | |
247 } | |
248 } | |
249 } | |
250 | |
251 void InitializePluginContext(void* pluginContext) | |
252 { | |
253 } | |
254 | |
255 void Initialize() | |
256 { | |
257 } | |
258 | |
259 void Finalize() | |
260 { | |
261 } | |
262 | |
263 void Reset() | |
264 { | |
265 } | |
266 | |
267 void Flush() | |
268 { | |
269 } | |
270 | |
271 void EnableInfoLevel(bool enabled) | |
272 { | |
273 infoEnabled_ = enabled; | |
274 | |
275 if (!enabled) | |
276 { | |
277 // Also disable the "TRACE" level when info-level debugging is disabled | |
278 traceEnabled_ = false; | |
279 } | |
280 } | |
281 | |
282 bool IsInfoLevelEnabled() | |
283 { | |
284 return infoEnabled_; | |
285 } | |
286 | |
287 void EnableTraceLevel(bool enabled) | |
288 { | |
289 traceEnabled_ = enabled; | |
290 } | |
291 | |
292 bool IsTraceLevelEnabled() | |
293 { | |
294 return traceEnabled_; | |
295 } | |
296 | |
297 void SetTargetFile(const std::string& path) | |
298 { | |
299 } | |
300 | |
301 void SetTargetFolder(const std::string& path) | |
302 { | |
303 } | |
304 } | |
305 } | |
306 | |
307 | |
308 #else | |
309 | |
310 /********************************************************* | |
311 * Logger compatible with the Orthanc plugin SDK, or that | |
312 * mimics behavior from Google Log. | |
313 *********************************************************/ | |
314 | |
315 #include <cassert> | |
316 | |
317 namespace | |
318 { | |
319 /** | |
320 * This is minimal implementation of the context for an Orthanc | |
321 * plugin, limited to the logging facilities, and that is binary | |
322 * compatible with the definitions of "OrthancCPlugin.h" | |
323 **/ | |
324 typedef enum | |
325 { | |
326 _OrthancPluginService_LogInfo = 1, | |
327 _OrthancPluginService_LogWarning = 2, | |
328 _OrthancPluginService_LogError = 3, | |
329 _OrthancPluginService_INTERNAL = 0x7fffffff | |
330 } _OrthancPluginService; | |
331 | |
332 typedef struct _OrthancPluginContext_t | |
333 { | |
334 void* pluginsManager; | |
335 const char* orthancVersion; | |
336 void (*Free) (void* buffer); | |
337 int32_t (*InvokeService) (struct _OrthancPluginContext_t* context, | |
338 _OrthancPluginService service, | |
339 const void* params); | |
340 } OrthancPluginContext; | |
341 } | |
342 | |
343 | |
344 #include "Enumerations.h" | |
345 #include "SystemToolbox.h" | |
346 | |
347 #include <fstream> | |
348 #include <boost/filesystem.hpp> | |
349 #include <boost/thread.hpp> | |
350 #include <boost/date_time/posix_time/posix_time.hpp> | |
351 | |
352 | |
353 namespace | |
354 { | |
355 struct LoggingStreamsContext | |
356 { | |
357 std::string targetFile_; | |
358 std::string targetFolder_; | |
359 | |
360 std::ostream* error_; | |
361 std::ostream* warning_; | |
362 std::ostream* info_; | |
363 | |
364 std::unique_ptr<std::ofstream> file_; | |
365 | |
366 LoggingStreamsContext() : | |
367 error_(&std::cerr), | |
368 warning_(&std::cerr), | |
369 info_(&std::cerr) | |
370 { | |
371 } | |
372 }; | |
373 } | |
374 | |
375 | |
376 | |
377 static std::unique_ptr<LoggingStreamsContext> loggingStreamsContext_; | |
378 static boost::mutex loggingStreamsMutex_; | |
379 static Orthanc::Logging::NullStream nullStream_; | |
380 static OrthancPluginContext* pluginContext_ = NULL; | |
381 static bool infoEnabled_ = false; | |
382 static bool traceEnabled_ = false; | |
383 | |
384 | |
385 namespace Orthanc | |
386 { | |
387 namespace Logging | |
388 { | |
389 static void GetLogPath(boost::filesystem::path& log, | |
390 boost::filesystem::path& link, | |
391 const std::string& suffix, | |
392 const std::string& directory) | |
393 { | |
394 /** | |
395 From Google Log documentation: | |
396 | |
397 Unless otherwise specified, logs will be written to the filename | |
398 "<program name>.<hostname>.<user name>.log<suffix>.", | |
399 followed by the date, time, and pid (you can't prevent the date, | |
400 time, and pid from being in the filename). | |
401 | |
402 In this implementation : "hostname" and "username" are not used | |
403 **/ | |
404 | |
405 boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); | |
406 boost::filesystem::path root(directory); | |
407 boost::filesystem::path exe(SystemToolbox::GetPathToExecutable()); | |
408 | |
409 if (!boost::filesystem::exists(root) || | |
410 !boost::filesystem::is_directory(root)) | |
411 { | |
412 throw OrthancException(ErrorCode_CannotWriteFile); | |
413 } | |
414 | |
415 char date[64]; | |
416 sprintf(date, "%04d%02d%02d-%02d%02d%02d.%d", | |
417 static_cast<int>(now.date().year()), | |
418 now.date().month().as_number(), | |
419 now.date().day().as_number(), | |
420 static_cast<int>(now.time_of_day().hours()), | |
421 static_cast<int>(now.time_of_day().minutes()), | |
422 static_cast<int>(now.time_of_day().seconds()), | |
423 SystemToolbox::GetProcessId()); | |
424 | |
425 std::string programName = exe.filename().replace_extension("").string(); | |
426 | |
427 log = (root / (programName + ".log" + suffix + "." + std::string(date))); | |
428 link = (root / (programName + ".log" + suffix)); | |
429 } | |
430 | |
431 | |
432 static void PrepareLogFolder(std::unique_ptr<std::ofstream>& file, | |
433 const std::string& suffix, | |
434 const std::string& directory) | |
435 { | |
436 boost::filesystem::path log, link; | |
437 GetLogPath(log, link, suffix, directory); | |
438 | |
439 #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) | |
440 boost::filesystem::remove(link); | |
441 boost::filesystem::create_symlink(log.filename(), link); | |
442 #endif | |
443 | |
444 file.reset(new std::ofstream(log.string().c_str())); | |
445 } | |
446 | |
447 | |
448 // "loggingStreamsMutex_" must be locked | |
449 static void CheckFile(std::unique_ptr<std::ofstream>& f) | |
450 { | |
451 if (loggingStreamsContext_->file_.get() == NULL || | |
452 !loggingStreamsContext_->file_->is_open()) | |
453 { | |
454 throw OrthancException(ErrorCode_CannotWriteFile); | |
455 } | |
456 } | |
457 | |
458 | |
459 static void GetLinePrefix(std::string& prefix, | |
460 LogLevel level, | |
461 const char* file, | |
462 int line) | |
463 { | |
464 boost::filesystem::path path(file); | |
465 boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time(); | |
466 boost::posix_time::time_duration duration = now.time_of_day(); | |
467 | |
468 /** | |
469 From Google Log documentation: | |
470 | |
471 "Log lines have this form: | |
472 | |
473 Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg... | |
474 | |
475 where the fields are defined as follows: | |
476 | |
477 L A single character, representing the log level (eg 'I' for INFO) | |
478 mm The month (zero padded; ie May is '05') | |
479 dd The day (zero padded) | |
480 hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds | |
481 threadid The space-padded thread ID as returned by GetTID() (this matches the PID on Linux) | |
482 file The file name | |
483 line The line number | |
484 msg The user-supplied message" | |
485 | |
486 In this implementation, "threadid" is not printed. | |
487 **/ | |
488 | |
489 char c; | |
490 switch (level) | |
491 { | |
492 case LogLevel_ERROR: | |
493 c = 'E'; | |
494 break; | |
495 | |
496 case LogLevel_WARNING: | |
497 c = 'W'; | |
498 break; | |
499 | |
500 case LogLevel_INFO: | |
501 c = 'I'; | |
502 break; | |
503 | |
504 case LogLevel_TRACE: | |
505 c = 'T'; | |
506 break; | |
507 | |
508 default: | |
509 throw OrthancException(ErrorCode_InternalError); | |
510 } | |
511 | |
512 char date[64]; | |
513 sprintf(date, "%c%02d%02d %02d:%02d:%02d.%06d ", | |
514 c, | |
515 now.date().month().as_number(), | |
516 now.date().day().as_number(), | |
517 static_cast<int>(duration.hours()), | |
518 static_cast<int>(duration.minutes()), | |
519 static_cast<int>(duration.seconds()), | |
520 static_cast<int>(duration.fractional_seconds())); | |
521 | |
522 prefix = (std::string(date) + path.filename().string() + ":" + | |
523 boost::lexical_cast<std::string>(line) + "] "); | |
524 } | |
525 | |
526 | |
527 void InitializePluginContext(void* pluginContext) | |
528 { | |
529 assert(sizeof(_OrthancPluginService) == sizeof(int32_t)); | |
530 | |
531 boost::mutex::scoped_lock lock(loggingStreamsMutex_); | |
532 loggingStreamsContext_.reset(NULL); | |
533 pluginContext_ = reinterpret_cast<OrthancPluginContext*>(pluginContext); | |
534 } | |
535 | |
536 | |
537 void Initialize() | |
538 { | |
539 boost::mutex::scoped_lock lock(loggingStreamsMutex_); | |
540 | |
541 if (loggingStreamsContext_.get() == NULL) | |
542 { | |
543 loggingStreamsContext_.reset(new LoggingStreamsContext); | |
544 } | |
545 } | |
546 | |
547 void Finalize() | |
548 { | |
549 boost::mutex::scoped_lock lock(loggingStreamsMutex_); | |
550 loggingStreamsContext_.reset(NULL); | |
551 } | |
552 | |
553 void Reset() | |
554 { | |
555 // Recover the old logging context | |
556 std::unique_ptr<LoggingStreamsContext> old; | |
557 | |
558 { | |
559 boost::mutex::scoped_lock lock(loggingStreamsMutex_); | |
560 if (loggingStreamsContext_.get() == NULL) | |
561 { | |
562 return; | |
563 } | |
564 else | |
565 { | |
566 #if __cplusplus < 201103L | |
567 old.reset(loggingStreamsContext_.release()); | |
568 #else | |
569 old = std::move(loggingStreamsContext_); | |
570 #endif | |
571 | |
572 // Create a new logging context, | |
573 loggingStreamsContext_.reset(new LoggingStreamsContext); | |
574 } | |
575 } | |
576 | |
577 if (!old->targetFolder_.empty()) | |
578 { | |
579 SetTargetFolder(old->targetFolder_); | |
580 } | |
581 else if (!old->targetFile_.empty()) | |
582 { | |
583 SetTargetFile(old->targetFile_); | |
584 } | |
585 } | |
586 | |
587 | |
588 void EnableInfoLevel(bool enabled) | |
589 { | |
590 infoEnabled_ = enabled; | |
591 | |
592 if (!enabled) | |
593 { | |
594 // Also disable the "TRACE" level when info-level debugging is disabled | |
595 traceEnabled_ = false; | |
596 } | |
597 } | |
598 | |
599 bool IsInfoLevelEnabled() | |
600 { | |
601 return infoEnabled_; | |
602 } | |
603 | |
604 void EnableTraceLevel(bool enabled) | |
605 { | |
606 traceEnabled_ = enabled; | |
607 | |
608 if (enabled) | |
609 { | |
610 // Also enable the "INFO" level when trace-level debugging is enabled | |
611 infoEnabled_ = true; | |
612 } | |
613 } | |
614 | |
615 bool IsTraceLevelEnabled() | |
616 { | |
617 return traceEnabled_; | |
618 } | |
619 | |
620 | |
621 void SetTargetFolder(const std::string& path) | |
622 { | |
623 boost::mutex::scoped_lock lock(loggingStreamsMutex_); | |
624 if (loggingStreamsContext_.get() != NULL) | |
625 { | |
626 PrepareLogFolder(loggingStreamsContext_->file_, "" /* no suffix */, path); | |
627 CheckFile(loggingStreamsContext_->file_); | |
628 | |
629 loggingStreamsContext_->targetFile_.clear(); | |
630 loggingStreamsContext_->targetFolder_ = path; | |
631 loggingStreamsContext_->warning_ = loggingStreamsContext_->file_.get(); | |
632 loggingStreamsContext_->error_ = loggingStreamsContext_->file_.get(); | |
633 loggingStreamsContext_->info_ = loggingStreamsContext_->file_.get(); | |
634 } | |
635 } | |
636 | |
637 | |
638 void SetTargetFile(const std::string& path) | |
639 { | |
640 boost::mutex::scoped_lock lock(loggingStreamsMutex_); | |
641 | |
642 if (loggingStreamsContext_.get() != NULL) | |
643 { | |
644 loggingStreamsContext_->file_.reset(new std::ofstream(path.c_str(), std::fstream::app)); | |
645 CheckFile(loggingStreamsContext_->file_); | |
646 | |
647 loggingStreamsContext_->targetFile_ = path; | |
648 loggingStreamsContext_->targetFolder_.clear(); | |
649 loggingStreamsContext_->warning_ = loggingStreamsContext_->file_.get(); | |
650 loggingStreamsContext_->error_ = loggingStreamsContext_->file_.get(); | |
651 loggingStreamsContext_->info_ = loggingStreamsContext_->file_.get(); | |
652 } | |
653 } | |
654 | |
655 | |
656 InternalLogger::InternalLogger(LogLevel level, | |
657 const char* file, | |
658 int line) : | |
659 lock_(loggingStreamsMutex_, boost::defer_lock_t()), | |
660 level_(level), | |
661 stream_(&nullStream_) // By default, logging to "/dev/null" is simulated | |
662 { | |
663 if (pluginContext_ != NULL) | |
664 { | |
665 // We are logging using the Orthanc plugin SDK | |
666 | |
667 if (level == LogLevel_TRACE) | |
668 { | |
669 // No trace level in plugins, directly exit as the stream is | |
670 // set to "/dev/null" | |
671 return; | |
672 } | |
673 else | |
674 { | |
675 pluginStream_.reset(new std::stringstream); | |
676 stream_ = pluginStream_.get(); | |
677 } | |
678 } | |
679 else | |
680 { | |
681 // We are logging in a standalone application, not inside an Orthanc plugin | |
682 | |
683 if ((level == LogLevel_INFO && !infoEnabled_) || | |
684 (level == LogLevel_TRACE && !traceEnabled_)) | |
685 { | |
686 // This logging level is disabled, directly exit as the | |
687 // stream is set to "/dev/null" | |
688 return; | |
689 } | |
690 | |
691 std::string prefix; | |
692 GetLinePrefix(prefix, level, file, line); | |
693 | |
694 { | |
695 // We lock the global mutex. The mutex is locked until the | |
696 // destructor is called: No change in the output can be done. | |
697 lock_.lock(); | |
698 | |
699 if (loggingStreamsContext_.get() == NULL) | |
700 { | |
701 fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine\n"); | |
702 lock_.unlock(); | |
703 return; | |
704 } | |
705 | |
706 switch (level) | |
707 { | |
708 case LogLevel_ERROR: | |
709 stream_ = loggingStreamsContext_->error_; | |
710 break; | |
711 | |
712 case LogLevel_WARNING: | |
713 stream_ = loggingStreamsContext_->warning_; | |
714 break; | |
715 | |
716 case LogLevel_INFO: | |
717 case LogLevel_TRACE: | |
718 stream_ = loggingStreamsContext_->info_; | |
719 break; | |
720 | |
721 default: | |
722 throw OrthancException(ErrorCode_InternalError); | |
723 } | |
724 | |
725 if (stream_ == &nullStream_) | |
726 { | |
727 // The logging is disabled for this level, we can release | |
728 // the global mutex. | |
729 lock_.unlock(); | |
730 } | |
731 else | |
732 { | |
733 try | |
734 { | |
735 (*stream_) << prefix; | |
736 } | |
737 catch (...) | |
738 { | |
739 // Something is going really wrong, probably running out of | |
740 // memory. Fallback to a degraded mode. | |
741 stream_ = loggingStreamsContext_->error_; | |
742 (*stream_) << "E???? ??:??:??.?????? ] "; | |
743 } | |
744 } | |
745 } | |
746 } | |
747 } | |
748 | |
749 | |
750 InternalLogger::~InternalLogger() | |
751 { | |
752 if (pluginStream_.get() != NULL) | |
753 { | |
754 // We are logging through the Orthanc SDK | |
755 | |
756 std::string message = pluginStream_->str(); | |
757 | |
758 if (pluginContext_ != NULL) | |
759 { | |
760 switch (level_) | |
761 { | |
762 case LogLevel_ERROR: | |
763 pluginContext_->InvokeService(pluginContext_, _OrthancPluginService_LogError, message.c_str()); | |
764 break; | |
765 | |
766 case LogLevel_WARNING: | |
767 pluginContext_->InvokeService(pluginContext_, _OrthancPluginService_LogWarning, message.c_str()); | |
768 break; | |
769 | |
770 case LogLevel_INFO: | |
771 pluginContext_->InvokeService(pluginContext_, _OrthancPluginService_LogInfo, message.c_str()); | |
772 break; | |
773 | |
774 default: | |
775 break; | |
776 } | |
777 } | |
778 } | |
779 else if (stream_ != &nullStream_) | |
780 { | |
781 *stream_ << "\n"; | |
782 stream_->flush(); | |
783 } | |
784 } | |
785 | |
786 | |
787 void Flush() | |
788 { | |
789 if (pluginContext_ != NULL) | |
790 { | |
791 boost::mutex::scoped_lock lock(loggingStreamsMutex_); | |
792 | |
793 if (loggingStreamsContext_.get() != NULL && | |
794 loggingStreamsContext_->file_.get() != NULL) | |
795 { | |
796 loggingStreamsContext_->file_->flush(); | |
797 } | |
798 } | |
799 } | |
800 | |
801 | |
802 void SetErrorWarnInfoLoggingStreams(std::ostream& errorStream, | |
803 std::ostream& warningStream, | |
804 std::ostream& infoStream) | |
805 { | |
806 boost::mutex::scoped_lock lock(loggingStreamsMutex_); | |
807 | |
808 loggingStreamsContext_.reset(new LoggingStreamsContext); | |
809 loggingStreamsContext_->error_ = &errorStream; | |
810 loggingStreamsContext_->warning_ = &warningStream; | |
811 loggingStreamsContext_->info_ = &infoStream; | |
812 } | |
813 } | |
814 } | |
815 | |
816 | |
817 #endif // ORTHANC_ENABLE_LOGGING |