NumCpp  2.12.1
A Templatized Header Only C++ Implementation of the Python NumPy Library
Logger.hpp
Go to the documentation of this file.
1
28#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
54namespace 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);
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