ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
Logging

Detailed Description

Subsystem for logging and message handling.

The ACTS logging system provides flexible, hierarchical logging with multiple severity levels and decorators. 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.

Logging Levels

The logging system supports the following severity levels (from lowest to highest):

  • VERBOSE: Detailed diagnostic trace information.
  • DEBUG: Debug information during development.
  • INFO: General information messages.
  • WARNING: Non-critical error conditions.
  • ERROR: Error conditions which require follow-up.
  • FATAL: Unrecoverable error conditions.

Using Logging Macros

When a logger accessible via the logger() method, see Logging Patterns, use these macros to perform the actual logging:

ACTS_VERBOSE("Detailed trace information");
ACTS_DEBUG("Debug info: " << variable);
ACTS_INFO("Operation completed");
ACTS_WARNING("Potential issue detected");
ACTS_ERROR("Operation failed: " << errorMsg);
ACTS_FATAL("Critical failure");

The macros support stream-style formatting with << operators.

Logging Patterns

ACTS provides several patterns for integrating logging into your code, each suited for different use cases.

Member Logger Pattern

Use this pattern when a class needs persistent logging throughout its lifetime. The logger is stored as a member variable and passed to the constructor.

Best for:

  • Classes that perform ongoing work with logging needs
  • Components that need consistent logger identity
  • Objects with well-defined lifetimes
  • Allowing caller to control logging configuration
struct MyClass {
std::unique_ptr<const Acts::Logger> m_logger;
const Acts::Logger &logger() const { return *m_logger; }
MyClass(std::unique_ptr<const Acts::Logger> logger)
: m_logger(std::move(logger)) {}
void doWork() { ACTS_INFO("Doing work in MyClass"); }
};
// Usage
obj.doWork();

Key characteristics:

  • Logger stored as std::unique_ptr<const Acts::Logger>
  • Provides logger() accessor method returning const reference
  • Constructor accepts std::unique_ptr<const Acts::Logger> by value and moves it
  • Caller creates logger with getDefaultLogger() or other logger factory
  • ACTS logging macros work directly in member functions
  • Ownership transferred to the class instance

Const Reference Argument Pattern

Use this pattern when a function or algorithm should accept a logger from the caller, providing maximum flexibility.

Best for:

  • Standalone functions and algorithms
  • Places where it's inconvenient to store a member logger
// Usage with custom logger
auto customLogger = Acts::getDefaultLogger("Processor", Acts::Logging::DEBUG);
processSomething(42, *customLogger);
// Usage with default (dummy) logger
processSomething(100);

Key characteristics:

  • Logger passed as const Acts::Logger& parameter
  • Often has default value using getDummyLogger()
  • Allows caller to choose logging behavior
  • Supports dependency injection for testing

getDummyLogger Pattern

Use this pattern when logging is optional or should be disabled by default. In contract to getDefaultLogger, this function returns a logger that discards all messages, resulting in negligible runtime overhead. It is useful in cases where you don't want to default to logging to std::cout, but not all call-sites give you easy access to a logger.

Best for:

  • Optional logging that can be enabled when debugging
  • Functions where most callers don't have a logger
// Call without logging overhead
optionalLogging();
// Or provide a real logger when needed
auto debugLogger = Acts::getDefaultLogger("Debug", Acts::Logging::VERBOSE);
optionalLogging(*debugLogger);

Key characteristics:

  • Returns a global dummy logger that discards all output
  • negligible runtime overhead when used (messages not processed)
  • Common default for function parameters
  • Can be overridden with real logger when needed

getDefaultLogger Factory Function

Use this function to create standalone loggers with standard formatting (timestamp, component name, log level). Note that the loggers returned by this function will always look to standard output streams (e.g. std::cout).

Advanced Topics

Custom Output Streams

Acts::getDefaultLogger accepts an optional output stream parameter:

// Create a logger that writes to a file instead of stdout
std::ofstream logFile("mylog.txt");
auto fileLogger =

Logger Cloning

Loggers can be cloned to create independent instances with optional modifications to the name and/or log level. This is particularly useful when creating sub-component loggers or when you need multiple loggers with similar configurations.

// Create a base logger
auto baseLogger = Acts::getDefaultLogger("Fitter", Acts::Logging::INFO);
// Clone with same name and level
auto clonedLogger = baseLogger->clone();
// Clone with a different name
auto renamedLogger = baseLogger->clone("NewFitter");
// Clone with a different log level (keeps same name)
auto verboseClone = baseLogger->clone(Acts::Logging::VERBOSE);
// Clone with both new name and new level
auto customClone = baseLogger->clone("CustomFitter", Acts::Logging::DEBUG);
// Clone with a suffix appended to the name
auto actorLogger = baseLogger->cloneWithSuffix("Actor");
// Result: logger named "FitterActor" with INFO level
// Clone with a suffix and different level
auto debugActorLogger =
baseLogger->cloneWithSuffix("Actor", Acts::Logging::DEBUG);
// Result: logger named "FitterActor" with DEBUG level
// Common pattern: Create sub-component loggers
auto updaterLogger = baseLogger->cloneWithSuffix("Updater");
auto smootherLogger = baseLogger->cloneWithSuffix("Smoother");

Common Use Cases

Sub-component loggers: When a class has multiple internal components that need separate logging:

// Example: Class with multiple internal components that need separate logging
struct TrackFitter {
std::unique_ptr<const Acts::Logger> m_logger;
std::unique_ptr<const Acts::Logger> m_actorLogger;
std::unique_ptr<const Acts::Logger> m_updaterLogger;
explicit TrackFitter(std::unique_ptr<const Acts::Logger> logger)
: m_logger(std::move(logger)),
m_actorLogger(m_logger->cloneWithSuffix("Actor")),
m_updaterLogger(m_logger->cloneWithSuffix("Updater")) {}
};
// Creates loggers: "Fitter", "FitterActor", "FitterUpdater"

Per-component log levels: When building detectors or systems with different verbosity needs:

// Creating loggers with different verbosity levels for different components
auto baseDetectorLogger =
auto surfaceLogger =
baseDetectorLogger->clone("Surface", Acts::Logging::DEBUG);
auto volumeLogger =
baseDetectorLogger->clone("Volume", Acts::Logging::WARNING);

Testing: Creating test loggers with specific configurations:

// Creating test loggers with specific configurations
auto productionLogger =
auto testLogger = productionLogger->clone("Test", Acts::Logging::VERBOSE);

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:

There are two approaches to logger integration:

  1. Overriding getDefaultLogger (now discouraged). 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.

    Warning
    ACTS code has iteratively moved to not construct loggers via Acts::getDefaultLogger as much as possible, in favor of using a const-reference to Acts::Logger. The latter can be defaulted to a dummy logger using Acts::getDummyLogger. It is more suitable to pass into functions that might be called from other ACTS functions (rather than constructing a local logger via getDefaultLogger, or creating logger instances on the fly).

    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 LD_PRELOAD approach by providing 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 with:

    LD_PRELOAD=<YOUR_SHARED_LIBRARY> path/to/your/executable
  2. Passing logger instances to high level components (recommended), and rely on ACTS code to pass them into lower level classes / functions. This is the preferred approach as it allows proper control of log levels from top-level experiment code.

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 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:

  1. No log failure threshold exists, log levels are informative only. This is the default behavior.
  2. A compile-time log failure threshold is set. If ACTS_ENABLE_LOG_FAILURE_THRESHOLD=ON and ACTS_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 type Acts::Logging::ThresholdFailure is thrown.
  3. 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 main functions exist to interact with the failure threshold:

Topics

 Logging Macros
 Helper macros for logging with Acts::Logger.
 Logging Thresholds
 Functions and classes to manage logging failure thresholds.

Classes

class  Acts::Logger
 class for printing debug output More...
class  Acts::Logging::DefaultFilterPolicy
 default filter policy for debug messages More...
class  Acts::Logging::DefaultPrintPolicy
 default print policy for debug messages More...
class  Acts::Logging::LevelOutputDecorator
 decorate debug message with its debug level More...
class  Acts::Logging::NamedOutputDecorator
 decorate debug message with a name More...
class  Acts::Logging::OutputDecorator
 base class for decorating the debug output More...
class  Acts::Logging::OutputFilterPolicy
 abstract base class for filtering debug output More...
class  Acts::Logging::OutputPrintPolicy
 abstract base class for printing debug output More...
class  Acts::Logging::ThreadOutputDecorator
 decorate debug message with a thread ID More...
class  Acts::Logging::TimedOutputDecorator
 decorate debug message with a time stamp More...

Enumerations

enum  Acts::Logging::Level {
  Acts::Logging::VERBOSE = 0 , Acts::Logging::DEBUG , Acts::Logging::INFO , Acts::Logging::WARNING ,
  Acts::Logging::ERROR , Acts::Logging::FATAL , Acts::Logging::MAX
}
 constants steering the debug output More...

Functions

std::string_view Acts::Logging::levelName (Level level)
 Get the string name for a logging level.

Enumeration Type Documentation

◆ Level

constants steering the debug output

All messages with a debug level equal or higher than the currently set debug output level will be printed.

Enumerator
VERBOSE 

Detailed diagnostic trace information.

DEBUG 

Debug information during development.

INFO 

General information messages.

WARNING 

Non-critical error conditions.

ERROR 

Error conditions which require follow-up.

FATAL 

Unrecoverable error conditions.

MAX 

Filler level.

Function Documentation

◆ levelName()

std::string_view Acts::Logging::levelName ( Level level)

Get the string name for a logging level.

Parameters
levelThe logging level
Returns
String representation of the logging level