Logging
The ACTS logging facility supports several severity levels which allow you to
control the amount of information displayed at run-time. Logger objects can
easily be created using the Acts::getDefaultLogger()
function which
should be sufficient to get you started. In case you need more customized debug
output, you can make use of the output decorators defined in
Acts::Logging
or even write your own implementation of
Acts::Logging::OutputDecorator
. In order to add debug messages to your
program, you should use the provided macros for the different severity levels:
ACTS_VERBOSE(...);
ACTS_DEBUG(...);
ACTS_INFO(...);
ACTS_WARNING(...);
ACTS_ERROR(...);
ACTS_FATAL(...);
These macros correspond to the available log levels:
-
enum Acts::Logging::Level
Values:
-
enumerator VERBOSE
-
enumerator DEBUG
-
enumerator INFO
-
enumerator WARNING
-
enumerator ERROR
-
enumerator FATAL
-
enumerator MAX
-
enumerator VERBOSE
The macros require that a function logger
returning a Acts::Logger
object is available in the scope in which the macros are used:
const Logger& logger() const;
Inside classes
containing an Acts::Logger
object as member variable, this could be
achieved by providing a private class method called logger()
(for an example
see e.g. Acts::CylinderVolumeBuilder::logger()
). Inside free functions
or member methods with local logger objects, the macros are also usable, since
Acts::Logger
is callable and returns a reference to itself.
Code example illustrating the usage:
-
std::unique_ptr<const Logger> Acts::getDefaultLogger(const std::string &name, const Logging::Level &lvl, std::ostream *log_stream = &std::cout)
get default debug output logger
This function returns a pointer to a Logger instance with the following decorations enabled:
time stamps
name of logging instance
debug level
- Parameters:
name – [in] name of the logger instance
lvl – [in] debug threshold level
log_stream – [in] output stream used for printing debug messages
- Returns:
pointer to logging instance
#include <fstream>
#include <memory>
#include "Acts/Utilities/Logger.hpp"
void myFunction() {
// open the logfile
std::ofstream logfile("log.txt");
// set up a logger instance for >= INFO messages, streaming into the log file
std::unique_ptr<const Acts::Logger> logger
= Acts::getDefaultLogger("MyLogger", Acts::Logging::INFO, &logfile);
// make sure the ACTS debug macros can work with your logger
ACTS_VERBOSE("This message will not appear in the logfile.");
ACTS_INFO("But this one will: Hello World!");
// do not forget to close the logfile
logfile.close();
}
Logger integration
In case you are using ACTS in another framework which comes with its own logging facility (e.g. Gaudi) you can pipe the logging output from ACTS tools and algorithms to your framework’s logging system by supplying different implementations of:
Acts::Logging::OutputFilterPolicy
(for mapping logging levels)Acts::Logging::OutputPrintPolicy
(for passing the Acts output to your internal logging system)
There are two approaches to logger integration:
Overriding Acts::getDefaultLogger. This has the downside that log levels cannot be controlled from top-level experiment specific code. This means that it is non-trivial to steer the log level of an e.g. Gaudi algorithm via the
OutputLevel
property, and have the ACTS code respect this log level. It is therefore now discouraged to use this approach.Note
ACTS code has iteratively moved to not construct loggers via
Acts::getDefaultLogger()
as much as possible, in favor of using a const-reference toActs::Logger
. The latter can be defaulted to a dummy logger usingActs::getDummyLogger()
. It is more suitable to pass into functions that might be called from other ACTS functions (rather than construction a local logger viagetDefaultLogger
, or creating logger instances on the fly).Passing logger instances to high level components, and rely on ACTS code to pass them into lower level classes / functions.
Overriding Acts::getDefaultLogger
Attention
Using this mechanism is now discouraged for integration with an experiment framework.
Since ACTS makes extensive use of Acts::getDefaultLogger()
to provide
sufficient information for debugging, you might want to provide a modified
implementation of this function (using your output filter and printing
policies) to also pipe this output to your framework. You can use the following
approach using the possibility to inject custom code by preloading shared
libraries with LD_PRELOAD
. You need to provide an appropriate implementation
for a function of the following signature into a separate source file and
compile it in a shared library
namespace Acts {
std::unique_ptr<const Logger> getDefaultLogger(const std::string&,
const Logging::Level&,
std::ostream*);
}
Then you can run your executable, which uses ACTS tools and algorithms, in the following way (tested under Unix)
$ LD_PRELOAD=<YOUR_SHARED_LIBRARY> path/to/your/executable
Logging thresholds
Generally, log levels in ACTS are only of informative value: even
Acts::Logging::Level::ERROR
and Acts::Logging::Level::FATAL
will only print a
messages, and not terminate execution.
This is desirable in an experiment context, where jobs should not immediately terminate when ACTS encounters something that is logged as an error. In a test context, however, this behavior is not optimal: the tests should ensure in known configurations errors do not occur, or only in specific circumstances. To solve this, ACTS implements an optional log threshold mechanism.
The threshold mechanism is steered via two CMake options:
ACTS_ENABLE_LOG_FAILURE_THRESHOLD
and ACTS_LOG_FAILURE_THRESHOLD
. Depending
on their configuration, the logging can operate in three modes:
No log failure threshold exists, log levels are informative only. This is the default behavior.
A compile-time log failure threshold is set. If
ACTS_ENABLE_LOG_FAILURE_THRESHOLD=ON
andACTS_LOG_FAILURE_THRESHOLD=<LEVEL>
are set, the logger code will compile in a fixed check if the log level of a particular message exceeds<LEVEL>
. If that is the case, an exception of typeActs::Logging::ThresholdFailure
is thrown.A runtime log failure threshold is set. If only
ACTS_ENABLE_LOG_FAILURE_THRESHOLD=ON
and no fixed threshold level is set, the logger code will compile in a check of a global runtime threshold variable.
Note
If only ACTS_LOG_FAILURE_THRESHOLD
is set,
ACTS_ENABLE_LOG_FAILURE_THRESHOLD
will be set automatically, i.e. a
compile-time threshold will be set
Two functions exist to interact with the failure threshold:
-
Level Acts::Logging::getFailureThreshold()
Get debug level above which an exception will be thrown after logging.
All messages with a debug level equal or higher than the return value of this function will cause an exception to be thrown after log emission.
Note
Depending on preprocessor settings
ACTS_ENABLE_LOG_FAILURE_THRESHOLD
andACTS_LOG_FAILURE_THRESHOLD
, this operations is either constexpr or a runtime operation.
-
void Acts::Logging::setFailureThreshold(Level level)
Set debug level above which an exception will be thrown after logging.
All messages with a debug level equal or higher than
level
will cause an exception to be thrown after log emission.Note
This function is only available if
ACTS_LOG_FAILURE_THRESHOLD
is unset, i.e. no compile-time threshold is used. Otherwise an exception is thrown.Warning
The runtime log failure threshold is global state, therefore this function is not threadsafe. The intention is that this level is set once, before multi-threaded execution begins, and then not modified before the end of the job.