diff 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
line wrap: on
line diff
--- a/Core/Logging.cpp	Mon Jun 13 13:39:10 2016 +0200
+++ b/Core/Logging.cpp	Mon Jun 13 15:07:53 2016 +0200
@@ -47,6 +47,14 @@
     {
     }
 
+    void Reset()
+    {
+    }
+
+    void Flush()
+    {
+    }
+
     void EnableInfoLevel(bool enabled)
     {
     }
@@ -55,6 +63,10 @@
     {
     }
 
+    void SetTargetFile(const std::string& path)
+    {
+    }
+
     void SetTargetFolder(const std::string& path)
     {
     }
@@ -85,10 +97,12 @@
 
 namespace
 {
-  struct LoggingState
+  struct LoggingContext
   {
     bool infoEnabled_;
     bool traceEnabled_;
+    std::string  targetFile_;
+    std::string  targetFolder_;
 
     std::ostream* error_;
     std::ostream* warning_;
@@ -96,7 +110,7 @@
 
     std::auto_ptr<std::ofstream> file_;
 
-    LoggingState() : 
+    LoggingContext() : 
       infoEnabled_(false),
       traceEnabled_(false),
       error_(&std::cerr),
@@ -109,7 +123,7 @@
 
 
 
-static std::auto_ptr<LoggingState> loggingState_;
+static std::auto_ptr<LoggingContext> loggingContext_;
 static boost::mutex  loggingMutex_;
 
 
@@ -161,9 +175,9 @@
     }
 
 
-    static void PrepareLogFile(std::auto_ptr<std::ofstream>& file,
-                               const std::string& suffix,
-                               const std::string& directory)
+    static void PrepareLogFolder(std::auto_ptr<std::ofstream>& file,
+                                 const std::string& suffix,
+                                 const std::string& directory)
     {
       boost::filesystem::path log, link;
       GetLogPath(log, link, suffix, directory);
@@ -180,56 +194,125 @@
     void Initialize()
     {
       boost::mutex::scoped_lock lock(loggingMutex_);
-      loggingState_.reset(new LoggingState);
+      loggingContext_.reset(new LoggingContext);
     }
 
     void Finalize()
     {
       boost::mutex::scoped_lock lock(loggingMutex_);
-      loggingState_.reset(NULL);
+      loggingContext_.reset(NULL);
+    }
+
+    void Reset()
+    {
+      // Recover the old logging context
+      std::auto_ptr<LoggingContext> old;
+
+      {
+        boost::mutex::scoped_lock lock(loggingMutex_);
+        if (loggingContext_.get() == NULL)
+        {
+          return;
+        }
+        else
+        {
+          old = loggingContext_;
+
+          // Create a new logging context, 
+          loggingContext_.reset(new LoggingContext);
+        }
+      }
+      
+      EnableInfoLevel(old->infoEnabled_);
+      EnableTraceLevel(old->traceEnabled_);
+
+      if (!old->targetFolder_.empty())
+      {
+        SetTargetFolder(old->targetFolder_);
+      }
+      else if (!old->targetFile_.empty())
+      {
+        SetTargetFile(old->targetFile_);
+      }
     }
 
     void EnableInfoLevel(bool enabled)
     {
       boost::mutex::scoped_lock lock(loggingMutex_);
-      assert(loggingState_.get() != NULL);
+      assert(loggingContext_.get() != NULL);
 
-      loggingState_->infoEnabled_ = enabled;
+      loggingContext_->infoEnabled_ = enabled;
+      
+      if (!enabled)
+      {
+        // Also disable the "TRACE" level when info-level debugging is disabled
+        loggingContext_->traceEnabled_ = false;
+      }
     }
 
     void EnableTraceLevel(bool enabled)
     {
       boost::mutex::scoped_lock lock(loggingMutex_);
-      assert(loggingState_.get() != NULL);
+      assert(loggingContext_.get() != NULL);
 
-      loggingState_->traceEnabled_ = enabled;
+      loggingContext_->traceEnabled_ = enabled;
       
       if (enabled)
       {
         // Also enable the "INFO" level when trace-level debugging is enabled
-        loggingState_->infoEnabled_ = true;
+        loggingContext_->infoEnabled_ = true;
+      }
+    }
+
+
+    static void CheckFile(std::auto_ptr<std::ofstream>& f)
+    {
+      if (loggingContext_->file_.get() == NULL ||
+          !loggingContext_->file_->is_open())
+      {
+        throw OrthancException(ErrorCode_CannotWriteFile);
       }
     }
 
     void SetTargetFolder(const std::string& path)
     {
       boost::mutex::scoped_lock lock(loggingMutex_);
-      assert(loggingState_.get() != NULL);
+      assert(loggingContext_.get() != NULL);
+
+      PrepareLogFolder(loggingContext_->file_, "" /* no suffix */, path);
+      CheckFile(loggingContext_->file_);
 
-      PrepareLogFile(loggingState_->file_, "" /* no suffix */, path);
+      loggingContext_->targetFile_.clear();
+      loggingContext_->targetFolder_ = path;
+      loggingContext_->warning_ = loggingContext_->file_.get();
+      loggingContext_->error_ = loggingContext_->file_.get();
+      loggingContext_->info_ = loggingContext_->file_.get();
+    }
+
 
-      loggingState_->warning_ = loggingState_->file_.get();
-      loggingState_->error_ = loggingState_->file_.get();
-      loggingState_->info_ = loggingState_->file_.get();
+    void SetTargetFile(const std::string& path)
+    {
+      boost::mutex::scoped_lock lock(loggingMutex_);
+      assert(loggingContext_.get() != NULL);
+
+      loggingContext_->file_.reset(new std::ofstream(path.c_str(), std::fstream::app));
+      CheckFile(loggingContext_->file_);
+
+      loggingContext_->targetFile_ = path;
+      loggingContext_->targetFolder_.clear();
+      loggingContext_->warning_ = loggingContext_->file_.get();
+      loggingContext_->error_ = loggingContext_->file_.get();
+      loggingContext_->info_ = loggingContext_->file_.get();
     }
 
+
     InternalLogger::InternalLogger(const char* level,
                                    const char* file,
                                    int line) : 
       lock_(loggingMutex_), 
       stream_(&null_)  // By default, logging to "/dev/null" is simulated
     {
-      if (loggingState_.get() == NULL)
+      if (loggingContext_.get() == NULL)
       {
         fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine\n");
         return;
@@ -237,8 +320,8 @@
 
       LogLevel l = StringToLogLevel(level);
       
-      if ((l == LogLevel_Info  && !loggingState_->infoEnabled_) ||
-          (l == LogLevel_Trace && !loggingState_->traceEnabled_))
+      if ((l == LogLevel_Info  && !loggingContext_->infoEnabled_) ||
+          (l == LogLevel_Trace && !loggingContext_->traceEnabled_))
       {
         // This logging level is disabled, directly exit and unlock
         // the mutex to speed-up things. The stream is set to "/dev/null"
@@ -292,12 +375,12 @@
 
 
       // The header is computed, we now re-lock the mutex to access
-      // the stream objects. Pay attention that "loggingState_",
+      // the stream objects. Pay attention that "loggingContext_",
       // "infoEnabled_" or "traceEnabled_" might have changed while
       // the mutex was unlocked.
       lock_.lock();
 
-      if (loggingState_.get() == NULL)
+      if (loggingContext_.get() == NULL)
       {
         fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine\n");
         return;
@@ -306,25 +389,25 @@
       switch (l)
       {
         case LogLevel_Error:
-          stream_ = loggingState_->error_;
+          stream_ = loggingContext_->error_;
           break;
 
         case LogLevel_Warning:
-          stream_ = loggingState_->warning_;
+          stream_ = loggingContext_->warning_;
           break;
 
         case LogLevel_Info:
-          if (loggingState_->infoEnabled_)
+          if (loggingContext_->infoEnabled_)
           {
-            stream_ = loggingState_->info_;
+            stream_ = loggingContext_->info_;
           }
 
           break;
 
         case LogLevel_Trace:
-          if (loggingState_->traceEnabled_)
+          if (loggingContext_->traceEnabled_)
           {
-            stream_ = loggingState_->info_;
+            stream_ = loggingContext_->info_;
           }
 
           break;
@@ -360,6 +443,16 @@
     }
       
 
+    void Flush()
+    {
+      boost::mutex::scoped_lock lock(loggingMutex_);
+
+      if (loggingContext_.get() != NULL &&
+          loggingContext_->file_.get() != NULL)
+      {
+        loggingContext_->file_->flush();
+      }
+    }
   }
 }