Version: SMASH-3.4
logging.h
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2023,2026
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #ifndef SRC_INCLUDE_SMASH_LOGGING_H_
11 #define SRC_INCLUDE_SMASH_LOGGING_H_
12 
13 #include <stdexcept>
14 #include <tuple>
15 
16 #include "einhard.hpp"
17 #include "yaml-cpp/yaml.h"
18 
19 #include "macros.h"
20 
21 namespace smash {
22 
23 /// Configuration object to set the verbosity of each area independently.
24 class Configuration;
25 
26 /** \addtogroup logging
27  * @{
28  *
29  * \brief The interfaces in this group are used for debug and informational
30  * console output.
31  *
32  * SMASH uses the \ref einhard logging library for debug and info/warn/error
33  * output to stdout. This library builds upon the C++ <a
34  * href="http://en.cppreference.com/w/cpp/io/basic_ostream">ostream</a> classes
35  * and thus uses stream operators for converting objects into a text
36  * representation.
37  *
38  * The \ref einhard library supports named output streams (which simply means
39  * they automatically add the name to the prefix string). We use this feature to
40  * define log areas in SMASH that can be configured independently. The \ref
41  * einhard::Logger class supports two options: colorization and verbosity. For
42  * colorization we stay with the default of auto-detecting a color-terminal. For
43  * verbosity we use a Configuration object to set the verbosity of each area
44  * independently. This way we have control over the amount of debug output at
45  * runtime and without the need to touch the code/recompile.
46  *
47  * To output something from your code do the following:
48  * \code
49  * logg[LAreaName].trace(source_location);
50  * logg[LAreaName].debug("particle", p);
51  * logg[LAreaName].warn("Something happened.");
52  * \endcode
53  *
54  * Note that `LAreaName` needs to be declared within the smash namespace of the
55  * respective file in a form of (using PauliBlocking as an example area):
56  * \code
57  * static constexpr int LPauliBlocking = LogArea::PauliBlocking::id;
58  * \endcode
59  *
60  * The einhard::Logger class supports two ways of writing to an output stream:
61  * Use stream operators or pass the list of objects for output as parameters.
62  * Thus \code
63  * log.debug("particle: ", p);
64  * \endcode and \code
65  * log.debug() << "particle: " << p;
66  * \endcode are equivalent (except for a small optimization opportunity in the
67  * former variant, that could make it slightly more efficient). You can see,
68  * though, that the former variant is more concise and often much easier to type
69  * than the stream operators.
70  */
71 
72 /**
73  * Declares the necessary interface to identify a new log area.
74  */
75 #define DECLARE_LOGAREA(id__, name__) \
76  struct name__ { \
77  static constexpr int id = id__; \
78  static constexpr const char *textual() { return #name__; } \
79  static constexpr int textual_length() { return sizeof(#name__) - 1; } \
80  }
81 
82 /**
83  * The namespace where log areas are declared.
84  *
85  * To add a new area add one more line with DECLARE_LOGAREA at the bottom: Pick
86  * the next number for the id and a name to identify it in the log and source
87  * code. Then add the name to the end of the AreaTuple and create a new logging
88  * key in the InputKeys object in the input_keys.h file.
89  */
90 namespace LogArea {
107 DECLARE_LOGAREA(16, List); // ListModus
124 
125 /**
126  * This type collects all existing log areas so they will be created with the
127  * correct log level automatically.
128  */
129 using AreaTuple =
136  RootSolver>;
137 } // namespace LogArea
138 
139 /**
140  * Called from main() right after the Configuration object is fully set up to
141  * create all logger objects (as defined by LogArea::AreaTuple) with the correct
142  * area names and log levels.
143  *
144  * \param config A configuration object with the log area names as toplevel
145  * keys.
146  */
147 void create_all_loggers(Configuration config);
148 
149 /**
150  * Hackery that is required to output the location in the source code where the
151  * log statement occurs.
152  */
153 #define SMASH_SOURCE_LOCATION \
154  __FILE__ ":" + std::to_string(__LINE__) + " (" + __func__ + ')'
155 
156 /**
157  * \return The default log level to use if no specific level is configured.
158  */
160 
161 /**
162  * Set the default log level (what will be returned from subsequent
163  * default_loglevel calls).
164  *
165  * \param level The new log level. See einhard::LogLevel.
166  */
168 
169 /** \internal
170  * Formatting helper.
171  *
172  * \tparam T Value that is being formatted.
173  */
174 template <typename T>
176  /// Value that is being formatted
177  const T &value;
178  /// Output width
179  const int width;
180  /// Precision that value is being formatted with
181  const int precision;
182  /// Unit that is attached at the end of value
183  const char *const unit;
184  /**
185  * Nicely formatted output.
186  * \param out Output stream
187  * \param h FormattingHelper with given output parameters.
188  */
189  friend std::ostream &operator<<(std::ostream &out,
190  const FormattingHelper &h) {
191  if (h.width > 0) {
192  out << std::setfill(' ') << std::setw(h.width);
193  }
194  if (h.precision >= 0) {
195  out << std::setprecision(h.precision);
196  }
197  out << h.value;
198  if (h.unit) {
199  out << ' ' << h.unit;
200  }
201  return out;
202  }
203 };
204 
205 /**
206  * Acts as a stream modifier for std::ostream to output an object with an
207  * optional suffix string and with a given field width and precision.
208  *
209  * \tparam T Value that is being formatted.
210  * \param value The object to be written to the stream.
211  * \param unit An optional suffix string, typically used for a unit. May be
212  * nullptr.
213  * \param width The field width to use for \p value.
214  * \param precision The precision to use for \p value.
215  */
216 template <typename T>
217 FormattingHelper<T> format(const T &value, const char *unit, int width = -1,
218  int precision = -1) {
219  return {value, width, precision, unit};
220 }
221 
222 /**
223  * Return the globally shared logger array.
224  *
225  * The array is initialized on first use to avoid static initialization order
226  * issues across translation units.
227  */
228 std::array<einhard::Logger<>, std::tuple_size<LogArea::AreaTuple>::value>
229  &get_loggers();
230 
231 /**
232  * An array that stores all pre-configured Logger objects.
233  *
234  * To access its elements use `logg[LAreaName]` where `LAreaName` is the
235  * respective area identifier declared in the smash namespace of the file
236  * containing the log statement.
237  *
238  * Note that `LAreaName` needs to be declared within the smash namespace of
239  * the respective file in a form of (using PauliBlocking as an example area):
240  * \code
241  * static constexpr int LPauliBlocking = LogArea::PauliBlocking::id;
242  * \endcode
243  */
244 inline std::array<einhard::Logger<>, std::tuple_size<LogArea::AreaTuple>::value>
246 
247 } // namespace smash
248 
249 namespace YAML {
250 /** \internal
251  * Enables YAML-cpp to auto-convert a YAML Node to and from an
252  * einhard::LogLevel.
253  */
254 template <>
256  /**
257  * Convert from einhard::LogLevel to YAML::Node.
258  *
259  * \param x Log level.
260  * \return Corresponding YAML node.
261  */
262  static Node encode(const einhard::LogLevel &x) {
263  return Node{einhard::getLogLevelString(x)};
264  }
265 
266  /**
267  * Convert from YAML::Node to einhard::LogLevel.
268  *
269  * \param[in] node YAML node.
270  * \param[out] x Where the corresponding log level will be stored if the
271  * conversion was successful.
272  * \return Whether the conversion was successful.
273  */
274  static bool decode(const Node &node, einhard::LogLevel &x) {
275  if (!node.IsScalar()) {
276  return false;
277  } else {
278  x = einhard::getLogLevel(node.Scalar());
279  return true;
280  }
281  }
282 };
283 } // namespace YAML
284 
285 // @}
286 
287 #endif // SRC_INCLUDE_SMASH_LOGGING_H_
Interface to the SMASH configuration files.
This is the main include file for Einhard.
const T & value
Value that is being formatted.
Definition: logging.h:177
const int width
Output width.
Definition: logging.h:179
std::tuple< Main, Experiment, Box, Collider, Sphere, Action, InputParser, ParticleType, FindScatter, Clock, DecayModes, Resonances, ScatterAction, Distributions, Propagation, Grid, List, Nucleus, Density, PauliBlocking, Tmn, Fpe, Lattice, Pythia, GrandcanThermalizer, CrossSections, Output, HyperSurfaceCrossing, InitialConditions, ScatterActionMulti, Configuration, Potentials, RootSolver > AreaTuple
This type collects all existing log areas so they will be created with the correct log level automati...
Definition: logging.h:136
const char *const unit
Unit that is attached at the end of value.
Definition: logging.h:183
#define DECLARE_LOGAREA(id__, name__)
Declares the necessary interface to identify a new log area.
Definition: logging.h:75
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > & logg
An array that stores all pre-configured Logger objects.
Definition: logging.h:245
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > & get_loggers()
Return the globally shared logger array.
Definition: logging.cc:30
void set_default_loglevel(einhard::LogLevel level)
Set the default log level (what will be returned from subsequent default_loglevel calls).
Definition: logging.cc:25
static bool decode(const Node &node, einhard::LogLevel &x)
Convert from YAML::Node to einhard::LogLevel.
Definition: logging.h:274
const int precision
Precision that value is being formatted with.
Definition: logging.h:181
friend std::ostream & operator<<(std::ostream &out, const FormattingHelper &h)
Nicely formatted output.
Definition: logging.h:189
static Node encode(const einhard::LogLevel &x)
Convert from einhard::LogLevel to YAML::Node.
Definition: logging.h:262
FormattingHelper< T > format(const T &value, const char *unit, int width=-1, int precision=-1)
Acts as a stream modifier for std::ostream to output an object with an optional suffix string and wit...
Definition: logging.h:217
einhard::LogLevel default_loglevel()
Definition: logging.cc:23
void create_all_loggers(Configuration config)
Called from main() right after the Configuration object is fully set up to create all logger objects ...
Definition: logging.cc:115
This namespace contains all objects required for logging using Einhard.
Definition: einhard.hpp:97
LogLevel getLogLevel(const std::string &level)
Compares the string level against the strings for LogLevel and returns the one it matches.
LogLevel
Specification of the message severity.
Definition: einhard.hpp:109
const char * getLogLevelString() noexcept
Retrieve a human readable representation of the given log level value.
Definition: action.h:24
Convert from YAML::Node to SMASH-readable (C++) format and vice versa.
Definition: configuration.h:42
Log area tag type.
Definition: logging.h:96
Log area tag type.
Definition: logging.h:93
Log area tag type.
Definition: logging.h:100
Log area tag type.
Definition: logging.h:94
Log area tag type.
Definition: logging.h:121
Log area tag type.
Definition: logging.h:116
Log area tag type.
Definition: logging.h:101
Log area tag type.
Definition: logging.h:109
Log area tag type.
Definition: logging.h:104
Log area tag type.
Definition: logging.h:92
Log area tag type.
Definition: logging.h:99
Log area tag type.
Definition: logging.h:112
Log area tag type.
Definition: logging.h:106
Log area tag type.
Definition: logging.h:97
Log area tag type.
Definition: logging.h:113
Log area tag type.
Definition: logging.h:107
Log area tag type.
Definition: logging.h:91
Log area tag type.
Definition: logging.h:108
Log area tag type.
Definition: logging.h:117
Log area tag type.
Definition: logging.h:98
Log area tag type.
Definition: logging.h:110
Log area tag type.
Definition: logging.h:122
Log area tag type.
Definition: logging.h:105
Log area tag type.
Definition: logging.h:114
Log area tag type.
Definition: logging.h:102
Log area tag type.
Definition: logging.h:123
Log area tag type.
Definition: logging.h:103
Log area tag type.
Definition: logging.h:95
Log area tag type.
Definition: logging.h:111