Logging Guidelines
CORSIKA provides a logging interface built around spdlog which uses the fmt library for easy string formatting similar to Python f-strings.
There are two different styles for logging: a runtime-removable interface
(logging::info("Message")
or logger->info("Message")
) and a
compile-time-removable interface built around C macros
(CORSIKA_LOG_INFO("message")
or CORSIKA_LOGGER_INFO(logger, "message")
). The
advantage of the macro-based logging API is that it can be completely removed at
compile-time for improved performance when for heavy logging uses.
By default, logging calls without a specific logger (i.e logging::warn("A warning message!")
) will use the global corsika
logger; in general, this
should only be used by core CORSIKA framework and not by any physics processes.
For example, all of the below examples with use the global corsika
logger.
logging::info("Welcome to the CORSIKA8 logging!");
logging::error("Some error message with arg: {}", 1);
logging::warn("Easy padding in numbers like {:08d}", 12);
logging::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
logging::info("Support for floats {:03.2f}", 1.23456);
logging::info("Positional args are {1} {0}..", "too", "supported");
logging::info("{:<30}", "left aligned");
// you can change the log level at runtime to filter messages from individual loggers.
logging::set_level(logging::level::debug); // Set global log level to debug
CORSIKA_LOG_DEBUG("This message should be displayed.."); // these macro messages will be removed at compile-time
CORSIKA_LOG_TRACE("This message should be displayed.."); // this will also be removed
Further examples of how to format log messages can be found here, and here.
All processes should create their own logger with the get_logger("name")
function in the corsika/framework/logging/Logging.hpp
header file where name
is the lowercase name of this process. get_logger
returns a smart pointer
to the logger and this should be stored in the process for fast access i.e.
auto logger{get_logger("process_name")};
Unlike the examples above that are free functions, you should use methods of this instance to log messages. For example,
logger->error("This is an error message using my custom process logger!");
logger->info("Binary example: {}", logging::to_hex(buf));
logger->warn("Another binary example:{:n}", logging::to_hex(std::begin(buf), std::begin(buf) + 10));
CORSIKA_LOGGER_DEBUG(logger, "A compile-time removable log message!"); // note: CORSIKA_LOGG*ER* not CORSIKA_LOG
Level Guides (or how to choose the right logging level)
The following log levels are provided (in the order defined by spdlog
):
trace
, debug
, info
, warn
, error
, and critical
. The following
guidelines determine how to choose the appropriate log level for a given message:
- For messages that at most once or twice per event and contain information that
is not essential to the user (e.g. initialization, start parameters, some
statistics), use
logging::info("message")
orlogger->info("message")
. - While we endeavour to have no warnings in C8, if there is a warning state
(i.e. if a user entered a parameter that is outside a suitable or sane range)
that only occurs once or twice per event, use
logging::warn("message")
orlogger->warn("message")
. - For recoverable error states where something has gone wrong but the
simulation can continue, (i.e. this shower must be stopped but other showers
can continue, or a specific particle must be killed abnormally), use
logging::error("message")
orlogger->error("message")
. - For unrecoverable errors where the only correct thing to do is to
immediately quit CORSIKA, use
logging::critical("message")
orlogger->critical("message")
. Acritical
error message should always be followed by an exception to terminate the simulation. - For messages that occur several times per event (but not several times for
every particle) and contain detailed information, use
CORSIKA_LOG_DEBUG("message")
orCORSIKA_LOGGER_DEBUG(logger, "message")
. These messages are removed duringRelease
builds. - For messages that occur for every particle or many times per event, use
CORSIKA_LOG_TRACE("message")
orCORSIKA_LOGGER_TRACE(logger, "message")
. These are removed duringRelease
builds.
Change output log level
The level output can be dynamically changed between different thresholds by using:
logger->set_level(logging::level::critical);
with the obvious options of
logging::level::critical
logging::level::error
logging::level::warning
logging::level::info
logging::level::debug
logging::level::trace
Note, the when you used the macros, they are automatically removed for TRACE level in a build that has not set -DDEBUG
, thus in Release build this won't be directly accessible. And you have to re-compile the entire framework.