src/core/utils/log.h

Provides a logger and macros for convenient access. More…

Namespaces

Name
allpix
Helper class to hold support layers for a detector model.

Classes

Name
class allpix::DefaultLogger
Logger of the framework to inform the user of process.

Types

Name
enum class LogLevel { FATAL = 0, STATUS, ERROR, WARNING, INFO, DEBUG, NONE, TRACE, PRNG}
Logging detail level.
enum class LogFormat { SHORT = 0, DEFAULT, LONG}
Format of the logger.
using DefaultLogger Log

Functions

Name
void SUPPRESS_STREAM(std::ostream & stream)
Suppress a stream from writing any output.
void RELEASE_STREAM(std::ostream & stream)
Release an suppressed stream so it can write again.

Defines

Name
CONCAT_IMPL(x, y)
Macros to generate and retrieve line-specific local variables to hold the logging count of a message.
CONCAT(x, y)
Macros to generate and retrieve line-specific local variables to hold the logging count of a message.
GENERATE_LOG_VAR(Count)
Macros to generate and retrieve line-specific local variables to hold the logging count of a message.
GET_LOG_VARIABLE()
Macros to generate and retrieve line-specific local variables to hold the logging count of a message.
FILE_NAME
Base name of the file without the directory.
IFLOG(level)
Execute a block only if the reporting level is high enough.
LOG(level)
Create a logging stream if the reporting level is high enough.
LOG_PROGRESS(level, identifier)
Create a logging stream that overwrites the line if the previous message has the same identifier.
LOG_ONCE(level)
Create a logging stream if the reporting level is high enough and this message has not yet been logged.
LOG_N(level, max_log_count)
Create a logging stream if the reporting level is high enough and this message has not yet been logged more than max_log_count times.
SUPPRESS_STREAM_EXCEPT(level, stream)
Suppress a stream from writing output unless logging is below allpix::LogLevel.

Detailed Description

Provides a logger and macros for convenient access.

Copyright: Copyright (c) 2016-2024 CERN and the Allpix Squared authors. This software is distributed under the terms of the MIT License, copied verbatim in the file “LICENSE.md”. In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an Intergovernmental Organization or submit itself to any jurisdiction. SPDX-License-Identifier: MIT

Types Documentation

enum LogLevel

Enumerator Value Description
FATAL 0 Fatal problems that terminate the framework (typically exceptions)
STATUS Only critical progress information.
ERROR Critical problems that usually lead to fatal errors.
WARNING Possible issue that could lead to unexpected results.
INFO General information about processes (should not be called in run function)
DEBUG Detailed information about physics process.
NONE Indicates the log level has not been set (cannot be selected by the user)
TRACE Software debugging information about what part is currently running.
PRNG Logging level printing every pseudo-random number requested.

Logging detail level.

enum LogFormat

Enumerator Value Description
SHORT 0 Only include a single character for the log level, the section header and the message.
DEFAULT Also include the time and a full logging level description.
LONG All of the above and also information about the file and line where the message was defined.

Format of the logger.

using Log

using allpix::Log = typedef DefaultLogger;

Functions Documentation

function SUPPRESS_STREAM

inline void SUPPRESS_STREAM(
    std::ostream & stream
)

Suppress a stream from writing any output.

Parameters:

  • stream The stream to suppress

function RELEASE_STREAM

inline void RELEASE_STREAM(
    std::ostream & stream
)

Release an suppressed stream so it can write again.

Parameters:

  • stream The stream to release

Macros Documentation

define CONCAT_IMPL

#define CONCAT_IMPL(
    x,
    y
)
x##y

Macros to generate and retrieve line-specific local variables to hold the logging count of a message.

Note: the double concat macro is needed to ensure LINE is evaluated, see https://stackoverflow.com/a/19666216/17555746

define CONCAT

#define CONCAT(
    x,
    y
)
CONCAT_IMPL(x, y)

Macros to generate and retrieve line-specific local variables to hold the logging count of a message.

Note: the double concat macro is needed to ensure LINE is evaluated, see https://stackoverflow.com/a/19666216/17555746

define GENERATE_LOG_VAR

#define GENERATE_LOG_VAR(
    Count
)
    static std::atomic<int> CONCAT(local___FUNCTION__, __LINE__) { Count }

Macros to generate and retrieve line-specific local variables to hold the logging count of a message.

Note: the double concat macro is needed to ensure LINE is evaluated, see https://stackoverflow.com/a/19666216/17555746

define GET_LOG_VARIABLE

#define GET_LOG_VARIABLE(
    
)
CONCAT(local___FUNCTION__, __LINE__)

Macros to generate and retrieve line-specific local variables to hold the logging count of a message.

Note: the double concat macro is needed to ensure LINE is evaluated, see https://stackoverflow.com/a/19666216/17555746

define FILE_NAME

#define __FILE_NAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

Base name of the file without the directory.

define IFLOG

#define IFLOG(
    level
)
if(allpix::LogLevel::level <= allpix::Log::getReportingLevel() && !allpix::Log::getStreams().empty())

Execute a block only if the reporting level is high enough.

Parameters:

  • level The minimum log level

define LOG

#define LOG(
    level
)
    if(allpix::LogLevel::level <= allpix::Log::getReportingLevel() && !allpix::Log::getStreams().empty())                   \
    allpix::Log().getStream(                                                                                                \
        allpix::LogLevel::level, __FILE_NAME__, std::string(static_cast<const char*>(__func__)), __LINE__)

Create a logging stream if the reporting level is high enough.

Parameters:

  • level The log level of the stream

define LOG_PROGRESS

#define LOG_PROGRESS(
    level,
    identifier
)
    if(allpix::LogLevel::level <= allpix::Log::getReportingLevel() && !allpix::Log::getStreams().empty())                   \
    allpix::Log().getProcessStream(                                                                                         \
        identifier, allpix::LogLevel::level, __FILE_NAME__, std::string(static_cast<const char*>(__func__)), __LINE__)

Create a logging stream that overwrites the line if the previous message has the same identifier.

Parameters:

  • level The log level of the stream
  • identifier Identifier for this stream to determine overwrites

define LOG_ONCE

#define LOG_ONCE(
    level
)
LOG_N(level, 1)

Create a logging stream if the reporting level is high enough and this message has not yet been logged.

Parameters:

  • level The log level of the stream

define LOG_N

#define LOG_N(
    level,
    max_log_count
)
GENERATE_LOG_VAR(max_log_count);                                                                                        \
    if(GET_LOG_VARIABLE() > 0)                                                                                              \
        if(allpix::LogLevel::level <= allpix::Log::getReportingLevel() && !allpix::Log::getStreams().empty())               \
    allpix::Log().getStream(                                                                                                \
        allpix::LogLevel::level, __FILE_NAME__, std::string(static_cast<const char*>(__func__)), __LINE__)                  \
        << ((--GET_LOG_VARIABLE() == 0) ? "[further messages suppressed] " : "")

Create a logging stream if the reporting level is high enough and this message has not yet been logged more than max_log_count times.

Parameters:

  • level The log level of the stream
  • max_log_count Maximum number of times this message is allowed to be logged

define SUPPRESS_STREAM_EXCEPT

#define SUPPRESS_STREAM_EXCEPT(
    level,
    stream
)
IFLOG(level);                                                                                                           \
    else SUPPRESS_STREAM(stream);

Suppress a stream from writing output unless logging is below allpix::LogLevel.

Parameters:

  • level The log level of the stream
  • stream Stream to suppress

Source code


#ifndef ALLPIX_LOG_H
#define ALLPIX_LOG_H

#ifdef WIN32
#define __func__ __FUNCTION__
#endif

#include <cstring>
#include <mutex>
#include <ostream>
#include <sstream>
#include <string>
#include <vector>

namespace allpix {
    enum class LogLevel {
        FATAL = 0, 
        STATUS,    
        ERROR,     
        WARNING,   
        INFO,      
        DEBUG,     
        NONE,      
        TRACE,     
        PRNG,      
    };
    enum class LogFormat {
        SHORT = 0, 
        DEFAULT,   
        LONG       
    };

    // TODO [DOC] This just be renamed to Log?
    class DefaultLogger {
    public:
        DefaultLogger();
        ~DefaultLogger();


        DefaultLogger(const DefaultLogger&) = delete;
        DefaultLogger& operator=(const DefaultLogger&) = delete;


        DefaultLogger(DefaultLogger&&) noexcept(false) = default;
        DefaultLogger& operator=(DefaultLogger&&) noexcept(false) = default;

        std::ostringstream& getStream(LogLevel level = LogLevel::INFO,
                                      const std::string& file = "",
                                      const std::string& function = "",
                                      uint32_t line = 0);

        std::ostringstream& getProcessStream(std::string identifier,
                                             LogLevel level = LogLevel::INFO,
                                             const std::string& file = "",
                                             const std::string& function = "",
                                             uint32_t line = 0);

        static void finish();

        static LogLevel getReportingLevel();
        static void setReportingLevel(LogLevel level);

        static LogLevel getLevelFromString(const std::string& level);
        static std::string getStringFromLevel(LogLevel level);

        static LogFormat getFormat();
        static void setFormat(LogFormat format);

        static LogFormat getFormatFromString(const std::string& format);
        static std::string getStringFromFormat(LogFormat format);

        static void addStream(std::ostream& stream);
        static void clearStreams();
        static const std::vector<std::ostream*>& getStreams();

        static void setSection(std::string header);
        static std::string getSection();

        static void setEventNum(uint64_t event_num);
        static uint64_t getEventNum();

    private:
        std::string get_current_date();

        static bool is_terminal(std::ostream& stream);

        // Output stream
        std::ostringstream os;

        // Number of exceptions to prevent abort
        int exception_count_{};
        // Saved value of the length of the header indent
        unsigned int indent_count_{};

        // Internal methods to store static values
        static std::string& get_section();
        static uint64_t& get_event_num();
        static LogLevel& get_reporting_level();
        static LogFormat& get_format();
        static std::vector<std::ostream*>& get_streams();

        // Name of the process to log or empty if a normal log message
        std::string identifier_{};
        static std::string last_message_;
        static std::string last_identifier_;

        static std::mutex write_mutex_;
    };

    using Log = DefaultLogger;

#ifndef __FILE_NAME__
#define __FILE_NAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#endif

#define IFLOG(level) if(allpix::LogLevel::level <= allpix::Log::getReportingLevel() && !allpix::Log::getStreams().empty())

#define LOG(level)                                                                                                          \
    if(allpix::LogLevel::level <= allpix::Log::getReportingLevel() && !allpix::Log::getStreams().empty())                   \
    allpix::Log().getStream(                                                                                                \
        allpix::LogLevel::level, __FILE_NAME__, std::string(static_cast<const char*>(__func__)), __LINE__)

#define LOG_PROGRESS(level, identifier)                                                                                     \
    if(allpix::LogLevel::level <= allpix::Log::getReportingLevel() && !allpix::Log::getStreams().empty())                   \
    allpix::Log().getProcessStream(                                                                                         \
        identifier, allpix::LogLevel::level, __FILE_NAME__, std::string(static_cast<const char*>(__func__)), __LINE__)

#define LOG_ONCE(level) LOG_N(level, 1)


#define CONCAT_IMPL(x, y) x##y
#define CONCAT(x, y) CONCAT_IMPL(x, y)
#define GENERATE_LOG_VAR(Count)                                                                                             \
    static std::atomic<int> CONCAT(local___FUNCTION__, __LINE__) { Count }
#define GET_LOG_VARIABLE() CONCAT(local___FUNCTION__, __LINE__)

#define LOG_N(level, max_log_count)                                                                                         \
    GENERATE_LOG_VAR(max_log_count);                                                                                        \
    if(GET_LOG_VARIABLE() > 0)                                                                                              \
        if(allpix::LogLevel::level <= allpix::Log::getReportingLevel() && !allpix::Log::getStreams().empty())               \
    allpix::Log().getStream(                                                                                                \
        allpix::LogLevel::level, __FILE_NAME__, std::string(static_cast<const char*>(__func__)), __LINE__)                  \
        << ((--GET_LOG_VARIABLE() == 0) ? "[further messages suppressed] " : "")

    // suppress a (logging) stream
    // TODO [doc] rewrite as a lowercase function in a namespace?
    inline void SUPPRESS_STREAM(std::ostream& stream) { stream.setstate(std::ios::failbit); }

#define SUPPRESS_STREAM_EXCEPT(level, stream)                                                                               \
    IFLOG(level);                                                                                                           \
    else SUPPRESS_STREAM(stream);

    // TODO [doc] rewrite as a lowercase function in a namespace?
    inline void RELEASE_STREAM(std::ostream& stream) { stream.clear(); }
} // namespace allpix

#endif /* ALLPIX_LOG_H */

Updated on 2025-02-27 at 14:14:46 +0000