changeset 2954:d924f9bb61cc

taking advantage of details in OrthancException
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 03 Dec 2018 14:35:34 +0100
parents 210d5afd8f2b
children bbfd95a0c429
files Core/Compression/DeflateBaseCompressor.cpp Core/Compression/GzipCompressor.cpp Core/Compression/ZipWriter.cpp Core/Compression/ZlibCompressor.cpp Core/DicomNetworking/DicomServer.cpp Core/DicomNetworking/DicomUserConnection.cpp Core/DicomNetworking/Internals/FindScp.cpp Core/DicomNetworking/RemoteModalityParameters.cpp Core/DicomParsing/DicomModification.cpp Core/DicomParsing/FromDcmtkBridge.cpp Core/DicomParsing/Internals/DicomImageDecoder.cpp Core/DicomParsing/ParsedDicomFile.cpp Core/Enumerations.cpp Core/HttpClient.cpp Core/HttpServer/HttpContentNegociation.cpp Core/HttpServer/HttpOutput.cpp Core/HttpServer/MongooseServer.cpp Core/Images/ImageAccessor.cpp Core/Images/JpegReader.cpp Core/Images/JpegWriter.cpp Core/JobsEngine/GenericJobUnserializer.cpp Core/JobsEngine/JobsRegistry.cpp Core/Lua/LuaContext.cpp Core/Lua/LuaFunctionCall.cpp Core/OrthancException.h Core/Pkcs11.cpp Core/RestApi/RestApiOutput.cpp Core/SharedLibrary.cpp Core/SystemToolbox.cpp Core/Toolbox.cpp Core/WebServiceParameters.cpp NEWS
diffstat 32 files changed, 250 insertions(+), 249 deletions(-) [+]
line wrap: on
line diff
--- a/Core/Compression/DeflateBaseCompressor.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/Compression/DeflateBaseCompressor.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -45,8 +45,8 @@
   {
     if (level >= 10)
     {
-      LOG(ERROR) << "Zlib compression level must be between 0 (no compression) and 9 (highest compression)";
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
+      throw OrthancException(ErrorCode_ParameterOutOfRange,
+                             "Zlib compression level must be between 0 (no compression) and 9 (highest compression)");
     }
 
     compressionLevel_ = level;
@@ -63,8 +63,7 @@
 
     if (compressedSize < sizeof(uint64_t))
     {
-      LOG(ERROR) << "The compressed buffer is ill-formed";
-      throw OrthancException(ErrorCode_CorruptedFile);
+      throw OrthancException(ErrorCode_CorruptedFile, "The compressed buffer is ill-formed");
     }
 
     uint64_t size;
--- a/Core/Compression/GzipCompressor.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/Compression/GzipCompressor.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -271,8 +271,8 @@
       // The uncompressed size was not that properly guess, presumably
       // because of a file size over 4GB. Should fallback to
       // stream-based decompression.
-      LOG(ERROR) << "The uncompressed size of a gzip-encoded buffer was not properly guessed";
-      throw OrthancException(ErrorCode_NotImplemented);
+      throw OrthancException(ErrorCode_NotImplemented,
+                             "The uncompressed size of a gzip-encoded buffer was not properly guessed");
     }
   }
 }
--- a/Core/Compression/ZipWriter.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/Compression/ZipWriter.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -124,8 +124,8 @@
 
     if (path_.size() == 0)
     {
-      LOG(ERROR) << "Please call SetOutputPath() before creating the file";
-      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+      throw OrthancException(ErrorCode_BadSequenceOfCalls,
+                             "Please call SetOutputPath() before creating the file");
     }
 
     hasFileInZip_ = false;
@@ -168,8 +168,8 @@
   {
     if (level >= 10)
     {
-      LOG(ERROR) << "ZIP compression level must be between 0 (no compression) and 9 (highest compression)";
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
+      throw OrthancException(ErrorCode_ParameterOutOfRange,
+                             "ZIP compression level must be between 0 (no compression) and 9 (highest compression)");
     }
 
     Close();
@@ -228,8 +228,7 @@
   {
     if (!hasFileInZip_)
     {
-      LOG(ERROR) << "Call first OpenFile()";
-      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+      throw OrthancException(ErrorCode_BadSequenceOfCalls, "Call first OpenFile()");
     }
 
     const size_t maxBytesInAStep = std::numeric_limits<int32_t>::max();
--- a/Core/Compression/ZlibCompressor.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/Compression/ZlibCompressor.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -117,8 +117,8 @@
 
     if (!HasPrefixWithUncompressedSize())
     {
-      LOG(ERROR) << "Cannot guess the uncompressed size of a zlib-encoded buffer";
-      throw OrthancException(ErrorCode_InternalError);
+      throw OrthancException(ErrorCode_InternalError,
+                             "Cannot guess the uncompressed size of a zlib-encoded buffer");
     }
 
     uint64_t uncompressedSize = ReadUncompressedSizePrefix(compressed, compressedSize);
--- a/Core/DicomNetworking/DicomServer.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/DicomNetworking/DicomServer.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -316,8 +316,8 @@
   {
     if (modalities_ == NULL)
     {
-      LOG(ERROR) << "No list of modalities was provided to the DICOM server";
-      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+      throw OrthancException(ErrorCode_BadSequenceOfCalls,
+                             "No list of modalities was provided to the DICOM server");
     }
     
     Stop();
@@ -327,8 +327,8 @@
       (NET_ACCEPTOR, OFstatic_cast(int, port_), /*opt_acse_timeout*/ 30, &pimpl_->network_);
     if (cond.bad())
     {
-      LOG(ERROR) << "cannot create network: " << cond.text();
-      throw OrthancException(ErrorCode_DicomPortInUse);
+      throw OrthancException(ErrorCode_DicomPortInUse,
+                             "cannot create network: " + std::string(cond.text()));
     }
 
     continue_ = true;
--- a/Core/DicomNetworking/DicomUserConnection.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/DicomNetworking/DicomUserConnection.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -164,8 +164,8 @@
   {
     if (cond.bad())
     {
-      LOG(ERROR) << "DicomUserConnection: " << std::string(cond.text());
-       throw OrthancException(ErrorCode_NetworkProtocol);
+      throw OrthancException(ErrorCode_NetworkProtocol,
+                             "DicomUserConnection: " + std::string(cond.text()));
     }
   }
 
@@ -173,8 +173,8 @@
   {
     if (!IsOpen())
     {
-      LOG(ERROR) << "DicomUserConnection: First open the connection";
-      throw OrthancException(ErrorCode_NetworkProtocol);
+      throw OrthancException(ErrorCode_NetworkProtocol,
+                             "DicomUserConnection: First open the connection");
     }
   }
 
--- a/Core/DicomNetworking/Internals/FindScp.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/DicomNetworking/Internals/FindScp.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -200,9 +200,9 @@
           assert(data.modalities_ != NULL);
           if (!data.modalities_->LookupAETitle(modality, *data.remoteAet_))
           {
-            LOG(ERROR) << "Modality with AET \"" << *data.remoteAet_
-                       << "\" is not defined in the \"DicomModalities\" configuration option";
-            throw OrthancException(ErrorCode_UnknownModality);
+            throw OrthancException(ErrorCode_UnknownModality,
+                                   "Modality with AET \"" + (*data.remoteAet_) +
+                                   "\" is not defined in the \"DicomModalities\" configuration option");
           }
 
           
--- a/Core/DicomNetworking/RemoteModalityParameters.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/DicomNetworking/RemoteModalityParameters.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -87,8 +87,9 @@
     if (value <= 0 || 
         value >= 65535)
     {
-      LOG(ERROR) << "A TCP port number must be in range [1..65534], but found: " << value;
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
+      throw OrthancException(ErrorCode_ParameterOutOfRange,
+                             "A TCP port number must be in range [1..65534], but found: " +
+                             boost::lexical_cast<std::string>(value));
     }
   }
 
--- a/Core/DicomParsing/DicomModification.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/DicomParsing/DicomModification.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -256,8 +256,8 @@
       {
         if (!identifierGenerator_->Apply(mapped, original, level, currentSource_))
         {
-          LOG(ERROR) << "Unable to generate an anonymized ID";
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+          throw OrthancException(ErrorCode_InternalError,
+                                 "Unable to generate an anonymized ID");
         }
       }
 
@@ -873,28 +873,28 @@
     // Sanity checks at the patient level
     if (level_ == ResourceType_Patient && !IsReplaced(DICOM_TAG_PATIENT_ID))
     {
-      LOG(ERROR) << "When modifying a patient, her PatientID is required to be modified";
-      throw OrthancException(ErrorCode_BadRequest);
+      throw OrthancException(ErrorCode_BadRequest,
+                             "When modifying a patient, her PatientID is required to be modified");
     }
 
     if (!allowManualIdentifiers_)
     {
       if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID))
       {
-        LOG(ERROR) << "When modifying a patient, the StudyInstanceUID cannot be manually modified";
-        throw OrthancException(ErrorCode_BadRequest);
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying a patient, the StudyInstanceUID cannot be manually modified");
       }
 
       if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID))
       {
-        LOG(ERROR) << "When modifying a patient, the SeriesInstanceUID cannot be manually modified";
-        throw OrthancException(ErrorCode_BadRequest);
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying a patient, the SeriesInstanceUID cannot be manually modified");
       }
 
       if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID))
       {
-        LOG(ERROR) << "When modifying a patient, the SopInstanceUID cannot be manually modified";
-        throw OrthancException(ErrorCode_BadRequest);
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying a patient, the SopInstanceUID cannot be manually modified");
       }
     }
 
@@ -902,22 +902,22 @@
     // Sanity checks at the study level
     if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_PATIENT_ID))
     {
-      LOG(ERROR) << "When modifying a study, the parent PatientID cannot be manually modified";
-      throw OrthancException(ErrorCode_BadRequest);
+      throw OrthancException(ErrorCode_BadRequest,
+                             "When modifying a study, the parent PatientID cannot be manually modified");
     }
 
     if (!allowManualIdentifiers_)
     {
       if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID))
       {
-        LOG(ERROR) << "When modifying a study, the SeriesInstanceUID cannot be manually modified";
-        throw OrthancException(ErrorCode_BadRequest);
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying a study, the SeriesInstanceUID cannot be manually modified");
       }
 
       if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID))
       {
-        LOG(ERROR) << "When modifying a study, the SopInstanceUID cannot be manually modified";
-        throw OrthancException(ErrorCode_BadRequest);
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying a study, the SopInstanceUID cannot be manually modified");
       }
     }
 
@@ -925,22 +925,22 @@
     // Sanity checks at the series level
     if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_PATIENT_ID))
     {
-      LOG(ERROR) << "When modifying a series, the parent PatientID cannot be manually modified";
-      throw OrthancException(ErrorCode_BadRequest);
+      throw OrthancException(ErrorCode_BadRequest,
+                             "When modifying a series, the parent PatientID cannot be manually modified");
     }
 
     if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID))
     {
-      LOG(ERROR) << "When modifying a series, the parent StudyInstanceUID cannot be manually modified";
-      throw OrthancException(ErrorCode_BadRequest);
+      throw OrthancException(ErrorCode_BadRequest,
+                             "When modifying a series, the parent StudyInstanceUID cannot be manually modified");
     }
 
     if (!allowManualIdentifiers_)
     {
       if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID))
       {
-        LOG(ERROR) << "When modifying a series, the SopInstanceUID cannot be manually modified";
-        throw OrthancException(ErrorCode_BadRequest);
+        throw OrthancException(ErrorCode_BadRequest,
+                               "When modifying a series, the SopInstanceUID cannot be manually modified");
       }
     }
 
@@ -948,20 +948,20 @@
     // Sanity checks at the instance level
     if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_PATIENT_ID))
     {
-      LOG(ERROR) << "When modifying an instance, the parent PatientID cannot be manually modified";
-      throw OrthancException(ErrorCode_BadRequest);
+      throw OrthancException(ErrorCode_BadRequest,
+                             "When modifying an instance, the parent PatientID cannot be manually modified");
     }
 
     if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID))
     {
-      LOG(ERROR) << "When modifying an instance, the parent StudyInstanceUID cannot be manually modified";
-      throw OrthancException(ErrorCode_BadRequest);
+      throw OrthancException(ErrorCode_BadRequest,
+                             "When modifying an instance, the parent StudyInstanceUID cannot be manually modified");
     }
 
     if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID))
     {
-      LOG(ERROR) << "When modifying an instance, the parent SeriesInstanceUID cannot be manually modified";
-      throw OrthancException(ErrorCode_BadRequest);
+      throw OrthancException(ErrorCode_BadRequest,
+                             "When modifying an instance, the parent SeriesInstanceUID cannot be manually modified");
     }
 
 
@@ -1082,10 +1082,10 @@
 
       if (!force && IsDatabaseKey(tag))
       {
-        LOG(ERROR) << "Marking tag \"" << name << "\" as to be "
-                   << (operation == DicomModification::TagOperation_Keep ? "kept" : "removed")
-                   << " requires the \"Force\" option to be set to true";
-        throw OrthancException(ErrorCode_BadRequest);
+        throw OrthancException(ErrorCode_BadRequest,
+                               "Marking tag \"" + name + "\" as to be " +
+                               (operation == DicomModification::TagOperation_Keep ? "kept" : "removed") +
+                               " requires the \"Force\" option to be set to true");
       }
 
       switch (operation)
@@ -1126,9 +1126,9 @@
 
       if (!force && IsDatabaseKey(tag))
       {
-        LOG(ERROR) << "Marking tag \"" << name << "\" as to be replaced "
-                   << "requires the \"Force\" option to be set to true";
-        throw OrthancException(ErrorCode_BadRequest);
+        throw OrthancException(ErrorCode_BadRequest,
+                               "Marking tag \"" + name + "\" as to be replaced " +
+                               "requires the \"Force\" option to be set to true");
       }
 
       target.Replace(tag, value, false);
@@ -1153,8 +1153,8 @@
     }
     else
     {
-      LOG(ERROR) << "Member \"" << member << "\" should be a Boolean value";
-      throw OrthancException(ErrorCode_BadFileFormat);
+      throw OrthancException(ErrorCode_BadFileFormat,
+                             "Member \"" + member + "\" should be a Boolean value");
     }
   }
 
@@ -1271,8 +1271,8 @@
   {
     if (identifierGenerator_ != NULL)
     {
-      LOG(ERROR) << "Cannot serialize a DicomModification with a custom identifier generator";
-      throw OrthancException(ErrorCode_InternalError);
+      throw OrthancException(ErrorCode_InternalError,
+                             "Cannot serialize a DicomModification with a custom identifier generator");
     }
 
     value = Json::objectValue;
--- a/Core/DicomParsing/FromDcmtkBridge.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/DicomParsing/FromDcmtkBridge.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -119,16 +119,16 @@
 
     if (!dictionary.loadDictionary(tmp.GetPath().c_str()))
     {
-      LOG(ERROR) << "Cannot read embedded dictionary. Under Windows, make sure that " 
-                 << "your TEMP directory does not contain special characters.";
-      throw OrthancException(ErrorCode_InternalError);
+      throw OrthancException(ErrorCode_InternalError,
+                             "Cannot read embedded dictionary. Under Windows, make sure that " 
+                             "your TEMP directory does not contain special characters.");
     }
 #else
     if (!dictionary.loadFromMemory(content))
     {
-      LOG(ERROR) << "Cannot read embedded dictionary. Under Windows, make sure that " 
-                 << "your TEMP directory does not contain special characters.";
-      throw OrthancException(ErrorCode_InternalError);
+      throw OrthancException(ErrorCode_InternalError,
+                             "Cannot read embedded dictionary. Under Windows, make sure that " 
+                             "your TEMP directory does not contain special characters.");
     }
 #endif
   }
@@ -289,8 +289,9 @@
     /* make sure data dictionary is loaded */
     if (!dcmDataDict.isDictionaryLoaded())
     {
-      LOG(ERROR) << "No DICOM dictionary loaded, check environment variable: " << DCM_DICT_ENVIRONMENT_VARIABLE;
-      throw OrthancException(ErrorCode_InternalError);
+      throw OrthancException(ErrorCode_InternalError,
+                             "No DICOM dictionary loaded, check environment variable: " +
+                             std::string(DCM_DICT_ENVIRONMENT_VARIABLE));
     }
 
     {
@@ -298,8 +299,8 @@
       DcmTag key(0x0010, 0x1030); // This is PatientWeight
       if (key.getEVR() != EVR_DS)
       {
-        LOG(ERROR) << "The DICOM dictionary has not been correctly read";
-        throw OrthancException(ErrorCode_InternalError);
+        throw OrthancException(ErrorCode_InternalError,
+                               "The DICOM dictionary has not been correctly read");
       }
     }
   }
@@ -370,8 +371,7 @@
         char buf[128];
         sprintf(buf, "Trying to register private tag (%04x,%04x), but it must have an odd group >= 0x0009",
                 tag.GetGroup(), tag.GetElement());
-        LOG(ERROR) << buf;
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
+        throw OrthancException(ErrorCode_ParameterOutOfRange, std::string(buf));
       }
 
       entry.reset(new DcmDictEntry(tag.GetGroup(),
@@ -392,8 +392,8 @@
 
       if (locker->findEntry(name.c_str()))
       {
-        LOG(ERROR) << "Cannot register two tags with the same symbolic name \"" << name << "\"";
-        throw OrthancException(ErrorCode_AlreadyExistingTag);
+        throw OrthancException(ErrorCode_AlreadyExistingTag,
+                               "Cannot register two tags with the same symbolic name \"" + name + "\"");
       }
 
       locker->addEntry(entry.release());
@@ -1673,9 +1673,9 @@
 
     if (!ok)
     {
-      LOG(ERROR) << "While creating a DICOM instance, tag (" << tag.Format()
-                 << ") has out-of-range value: \"" << *decoded << "\"";
-      throw OrthancException(ErrorCode_BadFileFormat);
+      throw OrthancException(ErrorCode_BadFileFormat,
+                             "While creating a DICOM instance, tag (" + tag.Format() +
+                             ") has out-of-range value: \"" + (*decoded) + "\"");
     }
   }
 
@@ -1800,8 +1800,9 @@
             (value.asString().length() != 0 &&
              !GetDicomEncoding(encoding, value.asCString())))
         {
-          LOG(ERROR) << "Unknown encoding while creating DICOM from JSON: " << value;
-          throw OrthancException(ErrorCode_BadRequest);
+          throw OrthancException(ErrorCode_BadRequest,
+                                 "Unknown encoding while creating DICOM from JSON: " +
+                                 value.toStyledString());
         }
 
         if (value.asString().length() == 0)
@@ -1924,8 +1925,9 @@
     result->transferInit();
     if (!result->read(is).good())
     {
-      LOG(ERROR) << "Cannot parse an invalid DICOM file (size: " << size << " bytes)";
-      throw OrthancException(ErrorCode_BadFileFormat);
+      throw OrthancException(ErrorCode_BadFileFormat,
+                             "Cannot parse an invalid DICOM file (size: " +
+                             boost::lexical_cast<std::string>(size) + " bytes)");
     }
 
     result->loadAllDataIntoMemory();
@@ -2044,8 +2046,8 @@
 
     if (output.type() != Json::objectValue)
     {
-      LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table";
-      throw OrthancException(ErrorCode_LuaBadOutput);
+      throw OrthancException(ErrorCode_LuaBadOutput,
+                             "Lua: IncomingFindRequestFilter must return a table");
     }
 
     Json::Value::Members members = output.getMemberNames();
@@ -2054,8 +2056,9 @@
     {
       if (output[members[i]].type() != Json::stringValue)
       {
-        LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table mapping names of DICOM tags to strings";
-        throw OrthancException(ErrorCode_LuaBadOutput);
+        throw OrthancException(ErrorCode_LuaBadOutput,
+                               "Lua: IncomingFindRequestFilter must return a table "
+                               "mapping names of DICOM tags to strings");
       }
 
       DicomTag tag(ParseTag(members[i]));
@@ -2186,8 +2189,8 @@
           std::string s = Toolbox::ConvertFromUtf8(newValue, encoding);
           if (element.putString(s.c_str()) != EC_Normal)
           {
-            LOG(ERROR) << "Cannot replace value of tag: " << tag.Format();
-            throw OrthancException(ErrorCode_InternalError);
+            throw OrthancException(ErrorCode_InternalError,
+                                   "Cannot replace value of tag: " + tag.Format());
           }
 
           break;
--- a/Core/DicomParsing/Internals/DicomImageDecoder.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/DicomParsing/Internals/DicomImageDecoder.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -633,8 +633,8 @@
                              &dataset, frame, startFragment, &uncompressed[0],
                              uncompressed.size(), decompressedColorModel).good())
       {
-        LOG(ERROR) << "Cannot decode a palette image";
-        throw OrthancException(ErrorCode_BadFileFormat);
+        throw OrthancException(ErrorCode_BadFileFormat,
+                               "Cannot decode a palette image");
       }
 
       return DecodeLookupTable(target, info, dataset,
@@ -648,8 +648,8 @@
                              &dataset, frame, startFragment, target->GetBuffer(), 
                              target->GetSize(), decompressedColorModel).good())
       {
-        LOG(ERROR) << "Cannot decode a non-palette image";
-        throw OrthancException(ErrorCode_BadFileFormat);
+        throw OrthancException(ErrorCode_BadFileFormat,
+                               "Cannot decode a non-palette image");
       }
 
       return target.release();
@@ -806,8 +806,8 @@
       }
     }
 
-    LOG(ERROR) << "Cannot decode a DICOM image with the built-in decoder";
-    throw OrthancException(ErrorCode_BadFileFormat);
+    throw OrthancException(ErrorCode_BadFileFormat,
+                           "Cannot decode a DICOM image with the built-in decoder");
   }
 
 
--- a/Core/DicomParsing/ParsedDicomFile.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/DicomParsing/ParsedDicomFile.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -292,8 +292,9 @@
 
           if (!cond.good())
           {
-            LOG(ERROR) << "Error while sending a DICOM field: " << cond.text();
-            throw OrthancException(ErrorCode_InternalError);
+            throw OrthancException(ErrorCode_InternalError,
+                                   "Error while sending a DICOM field: " +
+                                   std::string(cond.text()));
           }
 
           return true;
@@ -955,8 +956,8 @@
     }
     else if (tmp->IsBinary())
     {
-      LOG(ERROR) << "Invalid binary string in the SpecificCharacterSet (0008,0005) tag";
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
+      throw OrthancException(ErrorCode_ParameterOutOfRange,
+                             "Invalid binary string in the SpecificCharacterSet (0008,0005) tag");
     }
     else if (tmp->IsNull() ||
              tmp->GetContent().empty())
@@ -973,9 +974,9 @@
       }
       else
       {
-        LOG(ERROR) << "Unsupported value for the SpecificCharacterSet (0008,0005) tag: \""
-                   << tmp->GetContent() << "\"";        
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
+        throw OrthancException(ErrorCode_ParameterOutOfRange,
+                               "Unsupported value for the SpecificCharacterSet (0008,0005) tag: \"" +
+                               tmp->GetContent() + "\"");
       }
     }
 
@@ -1081,8 +1082,8 @@
         EmbedImage(mime, content);
         break;
 #else
-        LOG(ERROR) << "Orthanc was compiled without support of PNG";
-        throw OrthancException(ErrorCode_NotImplemented);
+        throw OrthancException(ErrorCode_NotImplemented,
+                               "Orthanc was compiled without support of PNG");
 #endif
 
       case MimeType_Jpeg:
@@ -1090,8 +1091,8 @@
         EmbedImage(mime, content);
         break;
 #else
-        LOG(ERROR) << "Orthanc was compiled without support of JPEG";
-        throw OrthancException(ErrorCode_NotImplemented);
+        throw OrthancException(ErrorCode_NotImplemented,
+                               "Orthanc was compiled without support of JPEG");
 #endif
 
       case MimeType_Pam:
@@ -1103,8 +1104,8 @@
         break;
 
       default:
-        LOG(ERROR) << "Unsupported MIME type for the content of a new DICOM file: " << mime;
-        throw OrthancException(ErrorCode_NotImplemented);
+        throw OrthancException(ErrorCode_NotImplemented,
+                               "Unsupported MIME type for the content of a new DICOM file: " + mime);
     }
 
     return true;
@@ -1369,8 +1370,7 @@
     if (pdf.size() < 5 ||  // (*)
         strncmp("%PDF-", pdf.c_str(), 5) != 0)
     {
-      LOG(ERROR) << "Not a PDF file";
-      throw OrthancException(ErrorCode_BadFileFormat);
+      throw OrthancException(ErrorCode_BadFileFormat, "Not a PDF file");
     }
 
     InvalidateCache();
--- a/Core/Enumerations.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/Enumerations.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -1373,8 +1373,7 @@
 
       if (throwIfUnsupported)
       {
-        LOG(ERROR) << s;
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
+        throw OrthancException(ErrorCode_ParameterOutOfRange, s);
       }
       else
       {
@@ -1510,8 +1509,8 @@
     }
     else
     {
-      LOG(ERROR) << "Unknown modality manufacturer: \"" << manufacturer << "\"";
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
+      throw OrthancException(ErrorCode_ParameterOutOfRange,
+                             "Unknown modality manufacturer: \"" + manufacturer + "\"");
     }
 
     if (obsolete)
--- a/Core/HttpClient.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/HttpClient.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -77,8 +77,9 @@
 #if ORTHANC_ENABLE_SSL == 1
     return GetHttpStatus(curl_easy_perform(curl), curl, status);
 #else
-    LOG(ERROR) << "Orthanc was compiled without SSL support, cannot make HTTPS request";
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
+                                    "Orthanc was compiled without SSL support, "
+                                    "cannot make HTTPS request");
 #endif
   }
 }
@@ -220,15 +221,15 @@
   {
     if (code == CURLE_NOT_BUILT_IN)
     {
-      LOG(ERROR) << "Your libcurl does not contain a required feature, "
-                 << "please recompile Orthanc with -DUSE_SYSTEM_CURL=OFF";
-      throw OrthancException(ErrorCode_InternalError);
+      throw OrthancException(ErrorCode_InternalError,
+                             "Your libcurl does not contain a required feature, "
+                             "please recompile Orthanc with -DUSE_SYSTEM_CURL=OFF");
     }
 
     if (code != CURLE_OK)
     {
-      LOG(ERROR) << "libCURL error: " + std::string(curl_easy_strerror(code));
-      throw OrthancException(ErrorCode_NetworkProtocol);
+      throw OrthancException(ErrorCode_NetworkProtocol,
+                             "libCURL error: " + std::string(curl_easy_strerror(code)));
     }
 
     return code;
@@ -502,8 +503,8 @@
     if (!clientCertificateFile_.empty() &&
         pkcs11Enabled_)
     {
-      LOG(ERROR) << "Cannot enable both client certificates and PKCS#11 authentication";
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
+      throw OrthancException(ErrorCode_ParameterOutOfRange,
+                             "Cannot enable both client certificates and PKCS#11 authentication");
     }
 
     if (pkcs11Enabled_)
@@ -517,12 +518,13 @@
       }
       else
       {
-        LOG(ERROR) << "Cannot use PKCS#11 for a HTTPS request, because it has not been initialized";
-        throw OrthancException(ErrorCode_BadSequenceOfCalls);
+        throw OrthancException(ErrorCode_BadSequenceOfCalls,
+                               "Cannot use PKCS#11 for a HTTPS request, "
+                               "because it has not been initialized");
       }
 #else
-      LOG(ERROR) << "This version of Orthanc is compiled without support for PKCS#11";
-      throw OrthancException(ErrorCode_InternalError);
+      throw OrthancException(ErrorCode_InternalError,
+                             "This version of Orthanc is compiled without support for PKCS#11");
 #endif
     }
     else if (!clientCertificateFile_.empty())
@@ -544,8 +546,9 @@
         CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLKEY, clientCertificateKeyFile_.c_str()));
       }
 #else
-      LOG(ERROR) << "This version of Orthanc is compiled without OpenSSL support, cannot use HTTPS client authentication";
-      throw OrthancException(ErrorCode_InternalError);
+      throw OrthancException(ErrorCode_InternalError,
+                             "This version of Orthanc is compiled without OpenSSL support, "
+                             "cannot use HTTPS client authentication");
 #endif
     }
 
@@ -836,15 +839,15 @@
 
     if (!SystemToolbox::IsRegularFile(certificateFile))
     {
-      LOG(ERROR) << "Cannot open certificate file: " << certificateFile;
-      throw OrthancException(ErrorCode_InexistentFile);
+      throw OrthancException(ErrorCode_InexistentFile,
+                             "Cannot open certificate file: " + certificateFile);
     }
 
     if (!certificateKeyFile.empty() && 
         !SystemToolbox::IsRegularFile(certificateKeyFile))
     {
-      LOG(ERROR) << "Cannot open key file: " << certificateKeyFile;
-      throw OrthancException(ErrorCode_InexistentFile);
+      throw OrthancException(ErrorCode_InexistentFile,
+                             "Cannot open key file: " + certificateKeyFile);
     }
 
     clientCertificateFile_ = certificateFile;
@@ -862,8 +865,8 @@
               << (pin.empty() ? " (no PIN provided)" : " (PIN is provided)");
     GlobalParameters::GetInstance().InitializePkcs11(module, pin, verbose);    
 #else
-    LOG(ERROR) << "This version of Orthanc is compiled without support for PKCS#11";
-    throw OrthancException(ErrorCode_InternalError);
+    throw OrthancException(ErrorCode_InternalError,
+                           "This version of Orthanc is compiled without support for PKCS#11");
 #endif
   }
 }
--- a/Core/HttpServer/HttpContentNegociation.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/HttpServer/HttpContentNegociation.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -159,8 +159,9 @@
         }
         else
         {
-          LOG(ERROR) << "Quality parameter out of range in a HTTP request (must be between 0 and 1): " << value;
-          throw OrthancException(ErrorCode_BadRequest);
+          throw OrthancException(
+            ErrorCode_BadRequest,
+            "Quality parameter out of range in a HTTP request (must be between 0 and 1): " + value);
         }
       }
     }
--- a/Core/HttpServer/HttpOutput.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/HttpServer/HttpOutput.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -151,8 +151,9 @@
       }
       else
       {
-        LOG(ERROR) << "Because of keep-alive connections, the entire body must be sent at once or Content-Length must be given";
-        throw OrthancException(ErrorCode_BadSequenceOfCalls);
+        throw OrthancException(ErrorCode_BadSequenceOfCalls,
+                               "Because of keep-alive connections, the entire body must "
+                               "be sent at once or Content-Length must be given");
       }
     }
 
@@ -198,8 +199,8 @@
     if (hasContentLength_ &&
         contentPosition_ + length > contentLength_)
     {
-      LOG(ERROR) << "The body size exceeds what was declared with SetContentSize()";
-      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+      throw OrthancException(ErrorCode_BadSequenceOfCalls,
+                             "The body size exceeds what was declared with SetContentSize()");
     }
 
     if (length > 0)
@@ -233,15 +234,15 @@
         }
         else
         {
-          LOG(ERROR) << "The body size has not reached what was declared with SetContentSize()";
-          throw OrthancException(ErrorCode_BadSequenceOfCalls);
+          throw OrthancException(ErrorCode_BadSequenceOfCalls,
+                                 "The body size has not reached what was declared with SetContentSize()");
         }
 
         break;
 
       case State_WritingMultipart:
-        LOG(ERROR) << "Cannot invoke CloseBody() with multipart outputs";
-        throw OrthancException(ErrorCode_BadSequenceOfCalls);
+        throw OrthancException(ErrorCode_BadSequenceOfCalls,
+                               "Cannot invoke CloseBody() with multipart outputs");
 
       case State_Done:
         return;  // Ignore
@@ -296,8 +297,8 @@
         status == HttpStatus_401_Unauthorized ||
         status == HttpStatus_405_MethodNotAllowed)
     {
-      LOG(ERROR) << "Please use the dedicated methods to this HTTP status code in HttpOutput";
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
+      throw OrthancException(ErrorCode_ParameterOutOfRange,
+                             "Please use the dedicated methods to this HTTP status code in HttpOutput");
     }
     
     stateMachine_.SetHttpStatus(status);
@@ -408,8 +409,8 @@
 
     if (keepAlive_)
     {
-      LOG(ERROR) << "Multipart answers are not implemented together with keep-alive connections";
-      throw OrthancException(ErrorCode_NotImplemented);
+      throw OrthancException(ErrorCode_NotImplemented,
+                             "Multipart answers are not implemented together with keep-alive connections");
     }
 
     if (state_ != State_WritingHeader)
@@ -433,9 +434,9 @@
     {
       if (!Toolbox::StartsWith(*it, "Set-Cookie: "))
       {
-        LOG(ERROR) << "The only headers that can be set in multipart answers "
-                   << "are Set-Cookie (here: " << *it << " is set)";
-        throw OrthancException(ErrorCode_BadSequenceOfCalls);
+        throw OrthancException(ErrorCode_BadSequenceOfCalls,
+                               "The only headers that can be set in multipart answers "
+                               "are Set-Cookie (here: " + *it + " is set)");
       }
 
       header += *it;
--- a/Core/HttpServer/MongooseServer.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/HttpServer/MongooseServer.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -813,8 +813,8 @@
         // Now convert native exceptions as OrthancException
         catch (boost::bad_lexical_cast&)
         {
-          LOG(ERROR) << "Syntax error in some user-supplied data";
-          throw OrthancException(ErrorCode_BadParameterType);
+          throw OrthancException(ErrorCode_BadParameterType,
+                                 "Syntax error in some user-supplied data");
         }
         catch (std::runtime_error&)
         {
@@ -823,13 +823,13 @@
         }
         catch (std::bad_alloc&)
         {
-          LOG(ERROR) << "The server hosting Orthanc is running out of memory";
-          throw OrthancException(ErrorCode_NotEnoughMemory);
+          throw OrthancException(ErrorCode_NotEnoughMemory,
+                                 "The server hosting Orthanc is running out of memory");
         }
         catch (...)
         {
-          LOG(ERROR) << "An unhandled exception was generated inside the HTTP server";
-          throw OrthancException(ErrorCode_InternalError);
+          throw OrthancException(ErrorCode_InternalError,
+                                 "An unhandled exception was generated inside the HTTP server");
         }
       }
       catch (OrthancException& e)
--- a/Core/Images/ImageAccessor.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/Images/ImageAccessor.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -107,11 +107,8 @@
   {
     if (readOnly_)
     {
-#if ORTHANC_ENABLE_LOGGING == 1
-      LOG(ERROR) << "Trying to write on a read-only image";
-#endif
-
-      throw OrthancException(ErrorCode_ReadOnly);
+      throw OrthancException(ErrorCode_ReadOnly,
+                             "Trying to write to a read-only image");
     }
 
     return buffer_;
@@ -135,11 +132,8 @@
   {
     if (readOnly_)
     {
-#if ORTHANC_ENABLE_LOGGING == 1
-      LOG(ERROR) << "Trying to write on a read-only image";
-#endif
-
-      throw OrthancException(ErrorCode_ReadOnly);
+      throw OrthancException(ErrorCode_ReadOnly,
+                             "Trying to write to a read-only image");
     }
 
     if (buffer_ != NULL)
@@ -299,10 +293,8 @@
   {
     if (readOnly_)
     {
-#if ORTHANC_ENABLE_LOGGING == 1
-      LOG(ERROR) << "Trying to modify the format of a read-only image";
-#endif
-      throw OrthancException(ErrorCode_ReadOnly);
+      throw OrthancException(ErrorCode_ReadOnly,
+                             "Trying to modify the format of a read-only image");
     }
 
     if (::Orthanc::GetBytesPerPixel(format) != ::Orthanc::GetBytesPerPixel(format_))
--- a/Core/Images/JpegReader.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/Images/JpegReader.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -121,8 +121,9 @@
     {
       jpeg_destroy_decompress(&cinfo);
       fclose(fp);
-      LOG(ERROR) << "Error during JPEG decoding: " << jerr.GetMessage();
-      throw OrthancException(ErrorCode_InternalError);
+
+      throw OrthancException(ErrorCode_InternalError,
+                             "Error during JPEG decoding: " + jerr.GetMessage());
     }
 
     // Below this line, we are under the scope of a "setjmp"
@@ -159,8 +160,8 @@
     if (setjmp(jerr.GetJumpBuffer())) 
     {
       jpeg_destroy_decompress(&cinfo);
-      LOG(ERROR) << "Error during JPEG decoding: " << jerr.GetMessage();
-      throw OrthancException(ErrorCode_InternalError);
+      throw OrthancException(ErrorCode_InternalError,
+                             "Error during JPEG decoding: " + jerr.GetMessage());
     }
 
     // Below this line, we are under the scope of a "setjmp"
--- a/Core/Images/JpegWriter.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/Images/JpegWriter.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -149,8 +149,8 @@
        */
       jpeg_destroy_compress(&cinfo);
       fclose(fp);
-      LOG(ERROR) << "Error during JPEG encoding: " << jerr.GetMessage();
-      throw OrthancException(ErrorCode_InternalError);
+      throw OrthancException(ErrorCode_InternalError,
+                             "Error during JPEG encoding: " + jerr.GetMessage());
     }
 
     // Do not allocate data on the stack below this line!
@@ -193,8 +193,8 @@
         free(data);
       }
 
-      LOG(ERROR) << "Error during JPEG encoding: " << jerr.GetMessage();
-      throw OrthancException(ErrorCode_InternalError);
+      throw OrthancException(ErrorCode_InternalError,
+                             "Error during JPEG encoding: " + jerr.GetMessage());
     }
 
     // Do not allocate data on the stack below this line!
--- a/Core/JobsEngine/GenericJobUnserializer.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/JobsEngine/GenericJobUnserializer.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -55,8 +55,8 @@
     }
     else
     {
-      LOG(ERROR) << "Cannot unserialize job of type: " << type;
-      throw OrthancException(ErrorCode_BadFileFormat);
+      throw OrthancException(ErrorCode_BadFileFormat,
+                             "Cannot unserialize job of type: " + type);
     }
   }
 
@@ -71,8 +71,8 @@
     }
     else
     {
-      LOG(ERROR) << "Cannot unserialize operation of type: " << type;
-      throw OrthancException(ErrorCode_BadFileFormat);
+      throw OrthancException(ErrorCode_BadFileFormat,
+                             "Cannot unserialize operation of type: " + type);
     }
   }
 
@@ -91,8 +91,8 @@
     }
     else
     {
-      LOG(ERROR) << "Cannot unserialize value of type: " << type;
-      throw OrthancException(ErrorCode_BadFileFormat);
+      throw OrthancException(ErrorCode_BadFileFormat,
+                             "Cannot unserialize value of type: " + type);
     }
   }
 }
--- a/Core/JobsEngine/JobsRegistry.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/JobsEngine/JobsRegistry.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -672,9 +672,11 @@
           break;
         
         default:
-          LOG(ERROR) << "A job should not be loaded from state: "
-                     << EnumerationToString(handler->GetState());
-          throw OrthancException(ErrorCode_InternalError);
+        {
+          std::string details = ("A job should not be loaded from state: " +
+                                 std::string(EnumerationToString(handler->GetState())));
+          throw OrthancException(ErrorCode_InternalError, details);
+        }
       }
 
       LOG(INFO) << "New job submitted with priority " << priority << ": " << id;
--- a/Core/Lua/LuaContext.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/Lua/LuaContext.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -587,8 +587,7 @@
 
       std::string description(lua_tostring(lua_, -1));
       lua_pop(lua_, 1); /* pop error message from the stack */
-      LOG(ERROR) << "Error while executing Lua script: " << description;
-      throw OrthancException(ErrorCode_CannotExecuteLua);
+      throw OrthancException(ErrorCode_CannotExecuteLua, description);
     }
 
     if (output != NULL)
--- a/Core/Lua/LuaFunctionCall.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/Lua/LuaFunctionCall.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -105,9 +105,8 @@
           
       std::string description(lua_tostring(context_.lua_, -1));
       lua_pop(context_.lua_, 1); /* pop error message from the stack */
-      LOG(ERROR) << description;
 
-      throw OrthancException(ErrorCode_CannotExecuteLua);
+      throw OrthancException(ErrorCode_CannotExecuteLua, description);
     }
 
     if (lua_gettop(context_.lua_) < numOutputs)
--- a/Core/OrthancException.h	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/OrthancException.h	Mon Dec 03 14:35:34 2018 +0100
@@ -78,7 +78,9 @@
       httpStatus_(ConvertErrorCodeToHttpStatus(errorCode)),
       details_(new std::string(details))
     {
+#if ORTHANC_ENABLE_LOGGING == 1
       LOG(ERROR) << EnumerationToString(errorCode_) << ": " << details;
+#endif
     }
 
     OrthancException(ErrorCode errorCode,
@@ -95,7 +97,9 @@
       httpStatus_(httpStatus),
       details_(new std::string(details))
     {
+#if ORTHANC_ENABLE_LOGGING == 1
       LOG(ERROR) << EnumerationToString(errorCode_) << ": " << details;
+#endif
     }
 
     ErrorCode GetErrorCode() const
--- a/Core/Pkcs11.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/Pkcs11.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -187,17 +187,17 @@
       ENGINE* engine = ENGINE_new();
       if (!engine)
       {
-        LOG(ERROR) << "Cannot create an OpenSSL engine for PKCS#11";
-        throw OrthancException(ErrorCode_InternalError);
+        throw OrthancException(ErrorCode_InternalError,
+                               "Cannot create an OpenSSL engine for PKCS#11");
       }
 
       // Create a PKCS#11 context using libp11
       context_ = pkcs11_new();
       if (!context_)
       {
-        LOG(ERROR) << "Cannot create a libp11 context for PKCS#11";
         ENGINE_free(engine);
-        throw OrthancException(ErrorCode_InternalError);
+        throw OrthancException(ErrorCode_InternalError,
+                               "Cannot create a libp11 context for PKCS#11");
       }
 
       if (!ENGINE_set_id(engine, PKCS11_ENGINE_ID) ||
@@ -223,10 +223,10 @@
           // Make OpenSSL know about our PKCS#11 engine
           !ENGINE_add(engine))
       {
-        LOG(ERROR) << "Cannot initialize the OpenSSL engine for PKCS#11";
         pkcs11_finish(context_);
         ENGINE_free(engine);
-        throw OrthancException(ErrorCode_InternalError);
+        throw OrthancException(ErrorCode_InternalError,
+                               "Cannot initialize the OpenSSL engine for PKCS#11");
       }
 
       // If the "ENGINE_add" worked, it gets a structural
@@ -253,28 +253,29 @@
     {
       if (pkcs11Initialized_)
       {
-        LOG(ERROR) << "The PKCS#11 engine has already been initialized";
-        throw OrthancException(ErrorCode_BadSequenceOfCalls);
+        throw OrthancException(ErrorCode_BadSequenceOfCalls,
+                               "The PKCS#11 engine has already been initialized");
       }
 
       if (module.empty() ||
           !SystemToolbox::IsRegularFile(module))
       {
-        LOG(ERROR) << "The PKCS#11 module must be a path to one shared library (DLL or .so)";
-        throw OrthancException(ErrorCode_InexistentFile);
+        throw OrthancException(
+          ErrorCode_InexistentFile,
+          "The PKCS#11 module must be a path to one shared library (DLL or .so)");
       }
 
       ENGINE* engine = LoadEngine();
       if (!engine)
       {
-        LOG(ERROR) << "Cannot create an OpenSSL engine for PKCS#11";
-        throw OrthancException(ErrorCode_InternalError);
+        throw OrthancException(ErrorCode_InternalError,
+                               "Cannot create an OpenSSL engine for PKCS#11");
       }
 
       if (!ENGINE_ctrl_cmd_string(engine, "MODULE_PATH", module.c_str(), 0))
       {
-        LOG(ERROR) << "Cannot configure the OpenSSL dynamic engine for PKCS#11";
-        throw OrthancException(ErrorCode_InternalError);
+        throw OrthancException(ErrorCode_InternalError,
+                               "Cannot configure the OpenSSL dynamic engine for PKCS#11");
       }
 
       if (verbose)
@@ -285,14 +286,14 @@
       if (!pin.empty() &&
           !ENGINE_ctrl_cmd_string(engine, "PIN", pin.c_str(), 0)) 
       {
-        LOG(ERROR) << "Cannot set the PIN code for PKCS#11";
-        throw OrthancException(ErrorCode_InternalError);
+        throw OrthancException(ErrorCode_InternalError,
+                               "Cannot set the PIN code for PKCS#11");
       }
   
       if (!ENGINE_init(engine))
       {
-        LOG(ERROR) << "Cannot initialize the OpenSSL dynamic engine for PKCS#11";
-        throw OrthancException(ErrorCode_InternalError);
+        throw OrthancException(ErrorCode_InternalError,
+                               "Cannot initialize the OpenSSL dynamic engine for PKCS#11");
       }
 
       LOG(WARNING) << "The PKCS#11 engine has been successfully initialized";
--- a/Core/RestApi/RestApiOutput.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/RestApi/RestApiOutput.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -100,8 +100,8 @@
       output_.SetContentType(MIME_XML_UTF8);
       output_.Answer(s);
 #else
-      LOG(ERROR) << "Orthanc was compiled without XML support";
-      throw OrthancException(ErrorCode_InternalError);
+      throw OrthancException(ErrorCode_InternalError,
+                             "Orthanc was compiled without XML support");
 #endif
     }
     else
--- a/Core/SharedLibrary.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/SharedLibrary.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -119,8 +119,9 @@
   
     if (result == NULL)
     {
-      LOG(ERROR) << "Shared library does not expose function \"" << name << "\"";
-      throw OrthancException(ErrorCode_SharedLibrary);
+      throw OrthancException(
+        ErrorCode_SharedLibrary,
+        "Shared library does not expose function \"" + name + "\"");
     }
     else
     {
--- a/Core/SystemToolbox.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/SystemToolbox.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -216,8 +216,8 @@
   {
     if (!IsRegularFile(path))
     {
-      LOG(ERROR) << "The path does not point to a regular file: " << path;
-      throw OrthancException(ErrorCode_RegularFileExpected);
+      throw OrthancException(ErrorCode_RegularFileExpected,
+                             "The path does not point to a regular file: " + path);
     }
 
     boost::filesystem::ifstream f;
@@ -244,8 +244,8 @@
   {
     if (!IsRegularFile(path))
     {
-      LOG(ERROR) << "The path does not point to a regular file: " << path;
-      throw OrthancException(ErrorCode_RegularFileExpected);
+      throw OrthancException(ErrorCode_RegularFileExpected,
+                             "The path does not point to a regular file: " + path);
     }
 
     boost::filesystem::ifstream f;
@@ -484,11 +484,7 @@
     if (pid == -1)
     {
       // Error in fork()
-#if ORTHANC_ENABLE_LOGGING == 1
-      LOG(ERROR) << "Cannot fork a child process";
-#endif
-
-      throw OrthancException(ErrorCode_SystemCommand);
+      throw OrthancException(ErrorCode_SystemCommand, "Cannot fork a child process");
     }
     else if (pid == 0)
     {
@@ -507,11 +503,9 @@
 
     if (status != 0)
     {
-#if ORTHANC_ENABLE_LOGGING == 1
-      LOG(ERROR) << "System command failed with status code " << status;
-#endif
-
-      throw OrthancException(ErrorCode_SystemCommand);
+      throw OrthancException(ErrorCode_SystemCommand,
+                             "System command failed with status code " +
+                             boost::lexical_cast<std::string>(status));
     }
   }
 
--- a/Core/Toolbox.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/Toolbox.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -1392,8 +1392,8 @@
     if (!ok &&
         !SetGlobalLocale(NULL))
     {
-      LOG(ERROR) << "Cannot initialize global locale";
-      throw OrthancException(ErrorCode_InternalError);
+      throw OrthancException(ErrorCode_InternalError,
+                             "Cannot initialize global locale");
     }
 
   }
@@ -1409,8 +1409,8 @@
   {
     if (globalLocale_.get() == NULL)
     {
-      LOG(ERROR) << "No global locale was set, call Toolbox::InitializeGlobalLocale()";
-      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+      throw OrthancException(ErrorCode_BadSequenceOfCalls,
+                             "No global locale was set, call Toolbox::InitializeGlobalLocale()");
     }
 
     /**
--- a/Core/WebServiceParameters.cpp	Mon Dec 03 11:49:39 2018 +0100
+++ b/Core/WebServiceParameters.cpp	Mon Dec 03 14:35:34 2018 +0100
@@ -92,8 +92,7 @@
     if (!Toolbox::StartsWith(url, "http://") &&
         !Toolbox::StartsWith(url, "https://"))
     {
-      LOG(ERROR) << "Bad URL: " << url;
-      throw OrthancException(ErrorCode_BadFileFormat);
+      throw OrthancException(ErrorCode_BadFileFormat, "Bad URL: " + url);
     }
 
     // Add trailing slash if needed
@@ -142,8 +141,9 @@
 
     if (certificateKeyPassword.empty())
     {
-      LOG(ERROR) << "The password for the HTTPS certificate is not provided: " << certificateFile;
-      throw OrthancException(ErrorCode_BadFileFormat);      
+      throw OrthancException(
+        ErrorCode_BadFileFormat,
+        "The password for the HTTPS certificate is not provided: " + certificateFile);
     }
 
     certificateFile_ = certificateFile;
@@ -173,8 +173,8 @@
     }
     else if (peer.size() == 2)
     {
-      LOG(ERROR) << "The HTTP password is not provided";
-      throw OrthancException(ErrorCode_BadFileFormat);
+      throw OrthancException(ErrorCode_BadFileFormat,
+                             "The HTTP password is not provided");
     }
     else if (peer.size() == 3)
     {
@@ -364,8 +364,9 @@
   {
     if (IsReservedKey(key))
     {
-      LOG(ERROR) << "Cannot use this reserved key to name an user property: " << key;
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
+      throw OrthancException(
+        ErrorCode_ParameterOutOfRange,
+        "Cannot use this reserved key to name an user property: " + key);
     }
     else
     {
@@ -488,15 +489,15 @@
     {
       if (!SystemToolbox::IsRegularFile(certificateFile_))
       {
-        LOG(ERROR) << "Cannot open certificate file: " << certificateFile_;
-        throw OrthancException(ErrorCode_InexistentFile);
+        throw OrthancException(ErrorCode_InexistentFile,
+                               "Cannot open certificate file: " + certificateFile_);
       }
 
       if (!certificateKeyFile_.empty() && 
           !SystemToolbox::IsRegularFile(certificateKeyFile_))
       {
-        LOG(ERROR) << "Cannot open key file: " << certificateKeyFile_;
-        throw OrthancException(ErrorCode_InexistentFile);
+        throw OrthancException(ErrorCode_InexistentFile,
+                               "Cannot open key file: " + certificateKeyFile_);
       }
     }
   }
--- a/NEWS	Mon Dec 03 11:49:39 2018 +0100
+++ b/NEWS	Mon Dec 03 14:35:34 2018 +0100
@@ -26,6 +26,7 @@
 * POST-ing a DICOM file to "/instances" also answers the patient/study/series ID
 * GET "/modalities/..." now returns a JSON object instead of a JSON array
 * New options to URI "/queries/.../answers": "?expand" and "?simplify"
+* New "Details" field in HTTP answers on error (cf. "HttpDescribeErrors" option)
 
 Maintenance
 -----------