MARLEY (Model of Argon Reaction Low Energy Yields) v2.0.0
A Monte Carlo event generator for tens-of-MeV neutrino interactions
Loading...
Searching...
No Matches
Logger.hh
1
4//
5// This file is part of MARLEY (Model of Argon Reaction Low Energy Yields)
6//
7// MARLEY is free software: you can redistribute it and/or modify it under the
8// terms of version 3 of the GNU General Public License as published by the
9// Free Software Foundation.
10//
11// For the full text of the license please see COPYING or
12// visit http://opensource.org/licenses/GPL-3.0
13//
14// Please respect the MCnet academic usage guidelines. See GUIDELINES
15// or visit https://www.montecarlonet.org/GUIDELINES for details.
16
17#pragma once
18#include <algorithm>
19#include <fstream>
20#include <memory>
21#include <mutex>
22#include <sstream>
23#include <unordered_map>
24#include <vector>
25
26// Define numerical values for the severity levels in a form that can be
27// understood by the preprocessor (enums aren't available yet)
28#define MARLEY_LOGGER_LEVEL_TRACE 0
29#define MARLEY_LOGGER_LEVEL_DEBUG 1
30#define MARLEY_LOGGER_LEVEL_INFO 2
31#define MARLEY_LOGGER_LEVEL_NOTICE 3
32#define MARLEY_LOGGER_LEVEL_WARN 4
33#define MARLEY_LOGGER_LEVEL_ERROR 5
34#define MARLEY_LOGGER_LEVEL_FATAL 6
35
36// Double-expansion helper that allows a severity level token (e.g., INFO) to
37// be assigned to MARLEY_COMPILED_LOG_LEVEL and matched to one of the numerical
38// values above. This is used below to enable numerical comparison in
39// MARLEY_LOG_IMPL without needing to reference the numerical values above
40// when configuring CMake or GNU Make.
41#define MARLEY_LOG_LEVEL_NUM(level) MARLEY_LOG_LEVEL_NUM_IMPL(level)
42#define MARLEY_LOG_LEVEL_NUM_IMPL(level) MARLEY_LOGGER_LEVEL_##level
43
44// Default to maximum severity of INFO (this can be overriden via injection
45// of a different definition for this macro at compile time). Anything below
46// this is blocked from execution at compile time, preventing
47// debugging messages from impairing runtime performance when they are not
48// enabled.
49#ifndef MARLEY_COMPILED_LOG_LEVEL
50 #define MARLEY_COMPILED_LOG_LEVEL INFO
51#endif
52
53// Main user-facing macro (accepts one or two arguments depending on
54// whether a category is specified)
55#define MARLEY_LOG(...) \
56 MARLEY_LOG_SELECT(__VA_ARGS__, \
57 MARLEY_LOG_2, \
58 MARLEY_LOG_1) \
59 (__VA_ARGS__)
60
61#define MARLEY_LOG_SELECT(_1,_2,NAME,...) NAME
62
63#define MARLEY_LOG_1(level) MARLEY_LOG_IMPL(level,"")
64#define MARLEY_LOG_2(level, category) MARLEY_LOG_IMPL(level,category)
65
66#define MARLEY_LOG_IMPL(level, category) \
67 ( MARLEY_LOG_LEVEL_NUM(MARLEY_COMPILED_LOG_LEVEL) \
68 <= MARLEY_LOGGER_LEVEL_##level ) && \
69 marley::Logger::Instance().log( marley::Logger::LogLevel::level, category )
70
71// Forward declare some MARLEY classes and their operator<< functions so that
72// we can stream them to the Logger
73namespace marley {
75 class JSON;
76 class Parity;
77 class Target;
78 class TargetAtom;
79}
80
81std::ostream& operator<<( std::ostream& out,
82 const marley::HauserFeshbachDecay& hfd );
83
84std::ostream& operator<<( std::ostream& os, const marley::JSON& json );
85std::ostream& operator<<( std::ostream& out, const marley::Parity& p );
86std::ostream& operator<<( std::ostream& out, const marley::Target& t );
87std::ostream& operator<<( std::ostream& out, const marley::TargetAtom& ta );
88
89namespace marley {
90
94 class Logger {
95
96 public:
97
102 enum class LogLevel {
103 TRACE = MARLEY_LOGGER_LEVEL_TRACE,
104 DEBUG = MARLEY_LOGGER_LEVEL_DEBUG,
105 INFO = MARLEY_LOGGER_LEVEL_INFO,
106 NOTICE = MARLEY_LOGGER_LEVEL_NOTICE,
107 WARN = MARLEY_LOGGER_LEVEL_WARN,
108 ERROR = MARLEY_LOGGER_LEVEL_ERROR,
109 FATAL = MARLEY_LOGGER_LEVEL_FATAL,
110 };
111
112 private:
113
116 const char* loglevel_to_str( LogLevel lev );
117
119 class OutStream {
120
121 friend class Logger;
122
123 public:
124
138 OutStream( std::shared_ptr< std::ostream > os,
139 LogLevel min, LogLevel max );
140
152 OutStream( std::ostream& os, LogLevel min, LogLevel max );
153
154 private:
155
158 std::shared_ptr< std::ostream > stream_;
159
161 LogLevel min_level_;
162
164 LogLevel max_level_;
165 };
166
167 public:
168
172 class Message {
173
174 public:
175
176 Message( std::vector< std::ostream* >& vec, std::mutex* mtx )
177 : osvec_( vec ), mtx_( mtx ) {}
178
179 // Copy constructors cannot be defaulted because the class owns
180 // a std::ostringstream, which has a deleted copy constructor.
181 // However, the stream can be moved, so we take advantage of this
182 // here to allow returning a Message by value.
183 Message( Message&& other ) = default;
184 Message& operator=( Message&& other ) = default;
185
186 // Allows conversion to bool to get the types to work in the MARLEY_LOG_IMPL macro.
187 // The return value is not intended to be used anywhere.
188 inline explicit operator bool() const { return true; }
189
190 inline ~Message() {
191 // If we have no active OutStreams, then just destroy the Message
192 // without any output
193 if ( osvec_.empty() ) return;
194 // Otherwise, append a new line, apply a lock to protect against
195 // activity from other threads, and write to each active OutStream
196 buffer_ << '\n';
197 std::string msg = buffer_.str();
198 std::lock_guard< std::mutex > lock( *mtx_ );
199 for ( auto& s : osvec_ ) *s << msg;
200 }
201
202 template< typename OutputType > Message&
203 operator<<( const OutputType& out )
204 {
205 // If we have no active OutStreams, then don't both to store the
206 // streaming output (since it will not be sent anywhere by the
207 // destructor
208 if ( !osvec_.empty() ) buffer_ << out;
209 return *this;
210 }
211
216 Message& operator<<( std::ostream& (*manip)(std::ostream&) );
217
219 Message& operator<<( std::ios_base& (*manip)(std::ios_base&) );
220
221 protected:
222
228 std::ostringstream buffer_;
229
231 std::vector< std::ostream* > osvec_;
232
235 std::mutex* mtx_;
236 };
237
239 Logger();
240
243 void configure( const marley::JSON& json );
244
245 static LogLevel string_to_loglevel( const std::string& str );
246
248 static Logger& Instance();
249
252 bool has_stream( const std::ostream& stream ) const;
253
258 Message log( LogLevel lev, const std::string& category = "" );
259
262 inline bool should_emit( const std::string& category, LogLevel lev );
263
266 LogLevel category_level( const std::string& category );
267
268 // Make the singleton Logger uncopyable and unmovable
270 Logger( const Logger& ) = delete;
272 Logger& operator=( const Logger& ) = delete;
274 Logger( Logger&& ) = delete;
276 Logger& operator=( Logger&& ) = delete;
277
278 private:
279
288 void add_stream( std::shared_ptr< std::ostream > stream,
289 LogLevel min, LogLevel max );
290
297 void add_stream( std::ostream& stream, LogLevel min, LogLevel max );
298
299 // @brief Returns a pointer to the given stream's OutStream object if
300 // it has been added to the Logger, or nullptr otherwise.
301 const OutStream* get_stream( const std::ostream* os ) const;
302
303 // @brief Returns a pointer to the given stream's OutStream object if
304 // it has been added to the Logger, or nullptr otherwise.
305 OutStream* get_stream( const std::ostream* os );
306
309 std::vector< OutStream > streams_;
310
314 LogLevel default_level_ = LogLevel::INFO;
315
318 std::unordered_map< std::string, LogLevel > category_map_;
319
325 std::unordered_map< std::string, LogLevel > resolved_level_cache_;
326
328 std::mutex mutex_;
329
331 static constexpr char CATEG_DELIM_ = '.';
332 };
333
334}
335
336// Inline function definitions
337inline bool marley::Logger::should_emit( const std::string& category,
338 LogLevel lev )
339{
340 LogLevel cl = this->category_level( category );
341 return ( lev >= cl );
342}
Monte Carlo implementation of the Hauser-Feshbach statistical model for decays of highly-excited nucl...
Temporary object used for forming logger messages.
Definition Logger.hh:172
std::ostringstream buffer_
Definition Logger.hh:228
std::vector< std::ostream * > osvec_
Active output streams that should receive the Message.
Definition Logger.hh:231
std::mutex * mtx_
Definition Logger.hh:235
Simple singleton logging class.
Definition Logger.hh:94
static Logger & Instance()
Get the singleton instance of the Logger class.
Definition Logger.cc:228
Logger(const Logger &)=delete
Deleted copy constructor.
Logger & operator=(const Logger &)=delete
Deleted copy assignment operator.
bool should_emit(const std::string &category, LogLevel lev)
Returns whether the logger should emit a message for the given category and level.
Definition Logger.hh:337
Logger()
Create the singleton Logger.
Definition Logger.cc:213
LogLevel category_level(const std::string &category)
Looks up the severity setting for the input category, including inheritance from the hierarchy.
Definition Logger.cc:333
void configure(const marley::JSON &json)
Initialize the Logger using settings expressed as a JSON object.
Definition Logger.cc:88
Message log(LogLevel lev, const std::string &category="")
Prepare the Logger to receive a log message via the << stream operator.
Definition Logger.cc:294
LogLevel
Defines the logging levels recognized by the marley::Logger.
Definition Logger.hh:102
Logger & operator=(Logger &&)=delete
Deleted move assignment operator.
bool has_stream(const std::ostream &stream) const
Returns true if stream is already registered with the Logger, or false otherwise.
Definition Logger.cc:233
Logger(Logger &&)=delete
Deleted move constructor.
Type-safe representation of a parity value (either +1 or -1)
Definition Parity.hh:25
An atomic target for a lepton scattering reaction.
Definition TargetAtom.hh:26
Description of a macroscopic target for scattering reactions.
Definition Target.hh:32