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-2021 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 Lesser General Public License 9 * as published by the Free Software Foundation, either version 3 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this program. If not, see 19 * <http://www.gnu.org/licenses/>. 20 **/ 21 22 23 #pragma once 24 25 // To have ORTHANC_ENABLE_LOGGING defined if using the shared library 26 #include "OrthancFramework.h" 27 #include "Compatibility.h" 28 29 #include <iostream> 30 31 #if !defined(ORTHANC_ENABLE_LOGGING) 32 # error The macro ORTHANC_ENABLE_LOGGING must be defined 33 #endif 34 35 #if !defined(ORTHANC_ENABLE_LOGGING_STDIO) 36 # if ORTHANC_ENABLE_LOGGING == 1 37 # error The macro ORTHANC_ENABLE_LOGGING_STDIO must be defined 38 # else 39 # define ORTHANC_ENABLE_LOGGING_STDIO 0 40 # endif 41 #endif 42 43 44 namespace Orthanc 45 { 46 namespace Logging 47 { 48 enum LogLevel 49 { 50 LogLevel_ERROR, 51 LogLevel_WARNING, 52 LogLevel_INFO, 53 LogLevel_TRACE 54 }; 55 56 /** 57 * NB: The log level for each category is encoded as a bit 58 * mask. As a consequence, there can be up to 31 log categories 59 * (not 32, as the value GENERIC is reserved for the log commands 60 * that don't fall in a specific category). 61 **/ 62 enum LogCategory 63 { 64 LogCategory_GENERIC = (1 << 0), 65 LogCategory_PLUGINS = (1 << 1), 66 LogCategory_HTTP = (1 << 2), 67 LogCategory_SQLITE = (1 << 3), 68 LogCategory_DICOM = (1 << 4), 69 LogCategory_JOBS = (1 << 5), 70 LogCategory_LUA = (1 << 6), 71 }; 72 73 ORTHANC_PUBLIC const char* EnumerationToString(LogLevel level); 74 75 ORTHANC_PUBLIC LogLevel StringToLogLevel(const char* level); 76 77 // "pluginContext" must be of type "OrthancPluginContext" 78 ORTHANC_PUBLIC void InitializePluginContext(void* pluginContext); 79 80 ORTHANC_PUBLIC void Initialize(); 81 82 ORTHANC_PUBLIC void Finalize(); 83 84 ORTHANC_PUBLIC void Reset(); 85 86 ORTHANC_PUBLIC void Flush(); 87 88 ORTHANC_PUBLIC void EnableInfoLevel(bool enabled); 89 90 ORTHANC_PUBLIC void EnableTraceLevel(bool enabled); 91 92 ORTHANC_PUBLIC bool IsTraceLevelEnabled(); 93 94 ORTHANC_PUBLIC bool IsInfoLevelEnabled(); 95 96 ORTHANC_PUBLIC void SetCategoryEnabled(LogLevel level, 97 LogCategory category, 98 bool enabled); 99 100 ORTHANC_PUBLIC bool IsCategoryEnabled(LogLevel level, 101 LogCategory category); 102 103 ORTHANC_PUBLIC bool LookupCategory(LogCategory& target, 104 const std::string& category); 105 106 ORTHANC_PUBLIC unsigned int GetCategoriesCount(); 107 108 ORTHANC_PUBLIC const char* GetCategoryName(unsigned int i); 109 110 ORTHANC_PUBLIC const char* GetCategoryName(LogCategory category); 111 112 ORTHANC_PUBLIC void SetTargetFile(const std::string& path); 113 114 ORTHANC_PUBLIC void SetTargetFolder(const std::string& path); 115 116 struct ORTHANC_LOCAL NullStream : public std::ostream 117 { NullStreamNullStream118 NullStream() : 119 std::ios(0), 120 std::ostream(0) 121 { 122 } 123 124 template <typename T> 125 std::ostream& operator<< (const T& message) 126 { 127 return *this; 128 } 129 }; 130 } 131 } 132 133 134 135 /** 136 * NB: 137 * - The "VLOG(unused)" macro is for backward compatibility with 138 * Orthanc <= 1.8.0. 139 * - The "CLOG()" macro stands for "category log" (new in Orthanc 1.8.1) 140 **/ 141 142 #if defined(LOG) 143 # error The macro LOG cannot be defined beforehand 144 #endif 145 146 #if defined(VLOG) 147 # error The macro VLOG cannot be defined beforehand 148 #endif 149 150 #if defined(CLOG) 151 # error The macro CLOG cannot be defined beforehand 152 #endif 153 154 #if ORTHANC_ENABLE_LOGGING != 1 155 # define LOG(level) ::Orthanc::Logging::NullStream() 156 # define VLOG(unused) ::Orthanc::Logging::NullStream() 157 # define CLOG(level, category) ::Orthanc::Logging::NullStream() 158 #else /* ORTHANC_ENABLE_LOGGING == 1 */ 159 # define LOG(level) ::Orthanc::Logging::InternalLogger \ 160 (::Orthanc::Logging::LogLevel_ ## level, \ 161 ::Orthanc::Logging::LogCategory_GENERIC, __FILE__, __LINE__) 162 # define VLOG(unused) ::Orthanc::Logging::InternalLogger \ 163 (::Orthanc::Logging::LogLevel_TRACE, \ 164 ::Orthanc::Logging::LogCategory_GENERIC, __FILE__, __LINE__) 165 # define CLOG(level, category) ::Orthanc::Logging::InternalLogger \ 166 (::Orthanc::Logging::LogLevel_ ## level, \ 167 ::Orthanc::Logging::LogCategory_ ## category, __FILE__, __LINE__) 168 #endif 169 170 171 172 #if (ORTHANC_ENABLE_LOGGING == 1 && \ 173 ORTHANC_ENABLE_LOGGING_STDIO == 1) 174 // This is notably for WebAssembly 175 176 #include <boost/lexical_cast.hpp> 177 #include <boost/noncopyable.hpp> 178 #include <sstream> 179 180 namespace Orthanc 181 { 182 namespace Logging 183 { 184 class ORTHANC_PUBLIC InternalLogger : public boost::noncopyable 185 { 186 private: 187 LogLevel level_; 188 LogCategory category_; 189 std::stringstream messageStream_; 190 191 public: InternalLogger(LogLevel level,LogCategory category,const char * file,int line)192 InternalLogger(LogLevel level, 193 LogCategory category, 194 const char* file /* ignored */, 195 int line /* ignored */) : 196 level_(level), 197 category_(category) 198 { 199 } 200 201 // For backward binary compatibility with Orthanc Framework <= 1.8.0 InternalLogger(LogLevel level,const char * file,int line)202 InternalLogger(LogLevel level, 203 const char* file /* ignored */, 204 int line /* ignored */) : 205 level_(level), 206 category_(LogCategory_GENERIC) 207 { 208 } 209 210 ~InternalLogger(); 211 212 template <typename T> 213 std::ostream& operator<< (const T& message) 214 { 215 return messageStream_ << boost::lexical_cast<std::string>(message); 216 } 217 }; 218 } 219 } 220 221 #endif 222 223 224 225 #if (ORTHANC_ENABLE_LOGGING == 1 && \ 226 ORTHANC_ENABLE_LOGGING_STDIO == 0) 227 228 #include <boost/lexical_cast.hpp> 229 #include <boost/noncopyable.hpp> 230 #include <boost/thread/mutex.hpp> 231 #include <sstream> 232 233 namespace Orthanc 234 { 235 namespace Logging 236 { 237 class ORTHANC_PUBLIC InternalLogger : public boost::noncopyable 238 { 239 private: 240 boost::mutex::scoped_lock lock_; 241 LogLevel level_; 242 std::unique_ptr<std::stringstream> pluginStream_; 243 std::ostream* stream_; 244 245 void Setup(LogCategory category, 246 const char* file, 247 int line); 248 249 public: 250 InternalLogger(LogLevel level, 251 LogCategory category, 252 const char* file, 253 int line); 254 255 // For backward binary compatibility with Orthanc Framework <= 1.8.0 256 InternalLogger(LogLevel level, 257 const char* file, 258 int line); 259 260 ~InternalLogger(); 261 262 template <typename T> 263 std::ostream& operator<< (const T& message) 264 { 265 return (*stream_) << boost::lexical_cast<std::string>(message); 266 } 267 }; 268 269 /** 270 * Set custom logging streams for the error, warning and info 271 * logs. This function may not be called if a log file or folder 272 * has been set beforehand. All three references must be valid. 273 * 274 * Please ensure the supplied streams remain alive and valid as 275 * long as logging calls are performed. In order to prevent 276 * dangling pointer usage, it is mandatory to call 277 * Orthanc::Logging::Reset() before the stream objects are 278 * destroyed and the references become invalid. 279 * 280 * This function must only be used by unit tests. It is ignored if 281 * InitializePluginContext() was called. 282 **/ 283 ORTHANC_PUBLIC void SetErrorWarnInfoLoggingStreams(std::ostream& errorStream, 284 std::ostream& warningStream, 285 std::ostream& infoStream); 286 } 287 } 288 289 #endif 290