NumCpp  2.11.0
A Templatized Header Only C++ Implementation of the Python NumPy Library
Logger.hpp
Go to the documentation of this file.
1 #pragma once
29 
30 #ifndef NUMCPP_NO_USE_BOOST
31 
32 #include <filesystem>
33 #include <fstream>
34 #include <ostream>
35 #include <sstream>
36 #include <string>
37 
38 #include "boost/core/null_deleter.hpp"
39 #include "boost/log/attributes.hpp"
40 #include "boost/log/core/core.hpp"
41 #include "boost/log/expressions.hpp"
42 #include "boost/log/expressions/formatters/date_time.hpp"
43 #include "boost/log/sinks/sync_frontend.hpp"
44 #include "boost/log/sinks/text_ostream_backend.hpp"
45 #include "boost/log/sources/global_logger_storage.hpp"
46 #include "boost/log/sources/severity_logger.hpp"
47 #include "boost/log/support/date_time.hpp"
48 #include "boost/log/trivial.hpp"
49 #include "boost/log/utility/manipulators/add_value.hpp"
50 #include "boost/log/utility/setup/common_attributes.hpp"
51 #include "boost/make_shared.hpp"
52 #include "boost/shared_ptr.hpp"
53 
54 namespace nc::logger
55 {
59  BOOST_LOG_GLOBAL_LOGGER(fileLogger, boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level>)
60 
61 
64  BOOST_LOG_ATTRIBUTE_KEYWORD(lineId, "LineID", uint32_t)
65  BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "TimeStamp", boost::posix_time::ptime)
66  BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", boost::log::trivial::severity_level)
67  BOOST_LOG_ATTRIBUTE_KEYWORD(filename, "Filename", std::string)
68  BOOST_LOG_ATTRIBUTE_KEYWORD(functionName, "FunctionName", std::string)
69  BOOST_LOG_ATTRIBUTE_KEYWORD(lineNumber, "LineNumber", uint32_t)
70 
71  namespace detail
72  {
73  // just log messages with severity >= SEVERITY_THRESHOLD are written
74  constexpr boost::log::trivial::severity_level INIT_LOGLEVEL{ boost::log::trivial::severity_level::trace };
75 
76  // log file extension
77  constexpr char OUTPUT_LOG_FILE_EXT[] = "log";
78 
79  // typedefs
80  using text_sink = boost::log::sinks::synchronous_sink<boost::log::sinks::text_ostream_backend>;
81 
85  inline boost::shared_ptr<text_sink> sinkConsole{};
86  inline boost::shared_ptr<text_sink> sinkFile{};
87 
91  [[nodiscard]] inline boost::log::formatter createOutputFormat()
92  {
93  // specify the format of the log message
94  constexpr auto counterWidth = 7;
95  boost::log::formatter formatter =
96  boost::log::expressions::stream
97  << std::setw(counterWidth) << std::setfill('0') << lineId << std::setfill(' ') << " ["
98  << boost::log::expressions::format_date_time(timestamp, "%Y-%m-%d %H:%M:%S.%f") << "] "
99  << "[" << boost::log::trivial::severity << "] "
100  << "[" << filename << ":" << functionName << "():" << lineNumber << "] "
101  << boost::log::expressions::smessage;
102  return formatter;
103  }
104  } // namespace detail
105 
110  [[nodiscard]] inline BOOST_LOG_GLOBAL_LOGGER_INIT(fileLogger, boost::log::sources::severity_logger_mt)
111  {
112  boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level> logger;
113 
114  // add attributes
115  logger.add_attribute("LineID", boost::log::attributes::counter<uint32_t>(1));
116  logger.add_attribute("TimeStamp", boost::log::attributes::local_clock());
117 
118  detail::sinkConsole = boost::make_shared<detail::text_sink>();
119 
120  // add "console" output stream to our sink
121  detail::sinkConsole->locked_backend()->add_stream(
122  boost::shared_ptr<std::ostream>(&std::clog, boost::null_deleter()));
123 
124  // specify the format of the log message
125  const auto formatter = detail::createOutputFormat();
126 
127  // set the formatting
128  detail::sinkConsole->set_formatter(formatter);
129 
130  // just log messages with severity >= INIT_LOGLEVEL are written
131  detail::sinkConsole->set_filter(severity >= detail::INIT_LOGLEVEL);
132 
133  // "register" our sink
134  boost::log::core::get()->add_sink(detail::sinkConsole);
135 
136  return logger;
137  }
138 
146  inline void addOutputFileLog(std::filesystem::path logFileName)
147  {
148  logFileName = std::filesystem::absolute(logFileName.replace_extension(detail::OUTPUT_LOG_FILE_EXT));
149 
150  // create the parent directories as needed
151  const auto errorCode = [&]
152  {
153  auto error = std::error_code{};
154  std::filesystem::create_directories(logFileName.parent_path(), error);
155  return error;
156  }();
157  if (errorCode)
158  {
159  auto ss = std::stringstream{};
160  ss << "Failed to create " << logFileName << " -- " << errorCode.message();
161  throw std::runtime_error{ ss.str() };
162  }
163 
164  // add a text sink
165  detail::sinkFile = boost::make_shared<detail::text_sink>();
166 
167  // add a logfile stream to our sink
168  detail::sinkFile->locked_backend()->add_stream(boost::make_shared<std::ofstream>(logFileName));
169 
170  // specify the format of the log message
171  const auto formatter = detail::createOutputFormat();
172 
173  // set the formatting
174  detail::sinkFile->set_formatter(formatter);
175 
176  // just log messages with severity >= INIT_LOGLEVEL are written
177  detail::sinkFile->set_filter(severity >= detail::INIT_LOGLEVEL);
178 
179  // "register" our sink
180  boost::log::core::get()->add_sink(detail::sinkFile);
181  }
182 
188  inline void setLogLevel(boost::log::trivial::severity_level level)
189  {
190  detail::sinkConsole->set_filter(severity >= level);
191  if (detail::sinkFile)
192  {
193  detail::sinkFile->set_filter(severity >= level);
194  }
195  }
196 } // namespace nc::logger
197 
198 // just a helper macro used by the macros below - don't use it in your code
199 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
200 #define BOOST_LOGGER(severity) \
201  BOOST_LOG_SEV(nc::logger::fileLogger::get(), boost::log::trivial::severity) \
202  << boost::log::add_value("Filename", std::filesystem::path(__FILE__).filename().stem().string()) \
203  << boost::log::add_value("FunctionName", __FUNCTION__) \
204  << boost::log::add_value("LineNumber", uint32_t{ __LINE__ })
205 
206 // ===== log macros =====
207 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
208 #define LOG_TRACE BOOST_LOGGER(trace)
209 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
210 #define LOG_DEBUG BOOST_LOGGER(debug)
211 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
212 #define LOG_INFO BOOST_LOGGER(info)
213 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
214 #define LOG_WARNING BOOST_LOGGER(warning)
215 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
216 #define LOG_ERROR BOOST_LOGGER(error)
217 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
218 #define LOG_FATAL BOOST_LOGGER(fatal)
219 
220 #endif // #ifndef NUMCPP_NO_USE_BOOST
constexpr boost::log::trivial::severity_level INIT_LOGLEVEL
Definition: Logger.hpp:74
boost::shared_ptr< text_sink > sinkConsole
local variables to hold the sink pointers
Definition: Logger.hpp:85
boost::shared_ptr< text_sink > sinkFile
Definition: Logger.hpp:86
boost::log::formatter createOutputFormat()
function to define the format of the output
Definition: Logger.hpp:91
boost::log::sinks::synchronous_sink< boost::log::sinks::text_ostream_backend > text_sink
Definition: Logger.hpp:80
constexpr char OUTPUT_LOG_FILE_EXT[]
Definition: Logger.hpp:77
Definition: BinaryLogger.hpp:45
BOOST_LOG_GLOBAL_LOGGER_INIT(fileLogger, boost::log::sources::severity_logger_mt)
Global intializer and constructor for the global logger Sets the initial sink to console backend and ...
Definition: Logger.hpp:110
void addOutputFileLog(std::filesystem::path logFileName)
Function to add the name of the output log file.
Definition: Logger.hpp:146
void setLogLevel(boost::log::trivial::severity_level level)
Function to set the severity level to report back to console and log file.
Definition: Logger.hpp:188
dtype trace(const NdArray< dtype > &inArray, int16 inOffset=0, Axis inAxis=Axis::ROW) noexcept
Definition: trace.hpp:47