Compare commits

...

21 Commits

Author SHA1 Message Date
Alexey Rybalchenko
71aac1199a Add GitHub CI workflow 2025-07-02 13:28:30 +02:00
Alexey Rybalchenko
2a4be75246 Add LOGFD and LOGPD macros 2025-07-02 13:28:30 +02:00
Alexey Rybalchenko
290070cbcf Use prefixed macros in case non-prefixed ones are undefined 2025-07-02 13:28:30 +02:00
Alexey Rybalchenko
832376101d add install/ to git ignore 2025-07-02 13:28:30 +02:00
Alexey Rybalchenko
cd9e392ce0 CMake: remove C from project versions 2025-05-19 12:40:32 +02:00
Alexey Rybalchenko
27527ad87b Add critical severity level between fatal and error 2025-02-06 15:20:41 +01:00
Dennis Klein
f3d68fb4ba build: Adopt all CMake policies up to 3.30 2024-08-20 15:56:57 +02:00
Giulio Eulisse
0ae9a697b4 Avoid extra allocation when creating the LogMetaData
By using a std::string_view for LogMetaData strings we avoid an implicit
memory allocation when passing __file__, etc. which are char const*
(notice this is also the case for the standardized
std::source_location::file_name etc).
2024-05-23 19:47:55 +02:00
Giulio Eulisse
fdbc047591 Bump minimum required C++ standard to C++17 2024-05-23 19:47:55 +02:00
Alexey Rybalchenko
ea4067c474 Update CI nodes 2024-02-22 10:31:38 +01:00
Alexey Rybalchenko
067dcc0e26 Update CI nodes 2024-02-21 13:54:16 +01:00
Alexey Rybalchenko
0ab390c465 Avoid semicolon insertion when modifying linker flags 2024-02-19 11:36:33 +01:00
Alexey Rybalchenko
56b90a7445 Avoid "Unknown severity" message also for uppercase fatal 2022-06-28 11:23:57 +02:00
Giulio Eulisse
7fc05f3808 Avoid "Unknown severity" message for fatal 2022-06-28 11:23:57 +02:00
Dennis Klein
d93fb0870b ci: Update macOS builds 2022-04-17 06:10:15 +02:00
Alexey Rybalchenko
953eac19c8 Add 'detail' severity between debug and info 2022-04-12 11:00:41 +02:00
Alexey Rybalchenko
9a6644c931 Adapt to fmt's deprecation of format_to memory buffer overload 2021-11-26 11:23:42 +01:00
Alexey Rybalchenko
27040ea292 Deprecate uppercase severity names 2021-11-25 14:29:18 +01:00
David Rohr
6545d0efa2 Include fmt/ostream.h, needed for on the fly std::ostream usage 2021-11-15 10:52:33 +01:00
Dennis Klein
159a21c24b ci: Add macos-11-arm64 (apple-clang-13) build 2021-10-01 17:10:13 +02:00
Dennis Klein
2494a9e85a Revert "Deprecate uppercase severity names"
This reverts commit ba7da2f79a.
2021-09-21 12:54:42 +02:00
15 changed files with 279 additions and 214 deletions

85
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,85 @@
name: CI
on:
push:
branches: [ master, dev ]
pull_request:
branches: [ master, dev ]
jobs:
build-linux:
runs-on: ubuntu-latest
strategy:
matrix:
fedora: [38, 39, 40]
include:
- fedora: 38
gcc: 13
- fedora: 39
gcc: 13
- fedora: 40
gcc: 14
container: ghcr.io/fairrootgroup/fairmq-dev/fedora-${{ matrix.fedora }}
steps:
- uses: actions/checkout@v4
- name: Install additional dependencies
run: |
dnf install -y fmt-devel || true
- name: Configure
run: |
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DDISABLE_COLOR=ON \
-DUSE_EXTERNAL_FMT=ON \
-DUSE_BOOST_PRETTY_FUNCTION=ON
- name: Build
run: cmake --build build
- name: Test
run: |
cd build
ctest -V --output-on-failure
build-macos:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-13, macos-14, macos-15]
steps:
- uses: actions/checkout@v4
- name: Cache Homebrew packages
uses: actions/cache@v4
with:
path: |
~/Library/Caches/Homebrew
/usr/local/Homebrew/Library/Taps
key: ${{ runner.os }}-${{ matrix.os }}-brew-${{ hashFiles('.github/workflows/ci.yml') }}
restore-keys: |
${{ runner.os }}-${{ matrix.os }}-brew-
- name: Install dependencies
run: |
brew install cmake ninja boost fmt
- name: Configure
run: |
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DDISABLE_COLOR=ON \
-DUSE_EXTERNAL_FMT=ON \
-DUSE_BOOST_PRETTY_FUNCTION=ON
- name: Build
run: cmake --build build
- name: Test
run: |
cd build
ctest -V --output-on-failure

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
build/
.vscode
install/

View File

@ -1,5 +1,5 @@
################################################################################
# Copyright (C) 2018-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# Copyright (C) 2018-2024 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
@ -7,7 +7,7 @@
################################################################################
cmake_minimum_required(VERSION 3.9.4 FATAL_ERROR)
cmake_policy(VERSION 3.9...3.19)
cmake_policy(VERSION 3.9...3.30)
# Project ######################################################################
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
@ -16,7 +16,7 @@ include(FairFindPackage2)
get_git_version()
project(FairLogger VERSION ${PROJECT_VERSION} LANGUAGES C CXX)
project(FairLogger VERSION ${PROJECT_VERSION} LANGUAGES CXX)
message(STATUS "${BWhite}${PROJECT_NAME}${CR} ${PROJECT_GIT_VERSION} from ${PROJECT_DATE}")
set_fairlogger_defaults()
@ -54,7 +54,7 @@ add_library(FairLogger
logger/Logger.cxx
logger/Logger.h
)
target_compile_features(FairLogger PUBLIC cxx_std_14)
target_compile_features(FairLogger PUBLIC cxx_std_17)
if(USE_BOOST_PRETTY_FUNCTION)
target_link_libraries(FairLogger PUBLIC Boost::boost)

View File

@ -15,14 +15,10 @@ set(CTEST_USE_LAUNCHERS ON)
set(CTEST_CONFIGURATION_TYPE "RelWithDebInfo")
if(NOT NCPUS)
if(ENV{SLURM_CPUS_PER_TASK})
set(NCPUS $ENV{SLURM_CPUS_PER_TASK})
else()
include(ProcessorCount)
ProcessorCount(NCPUS)
if(NCPUS EQUAL 0)
set(NCPUS 1)
endif()
include(ProcessorCount)
ProcessorCount(NCPUS)
if(NCPUS EQUAL 0)
set(NCPUS 1)
endif()
endif()
@ -32,10 +28,10 @@ else()
set(CTEST_SITE $ENV{CTEST_SITE})
endif()
if ("$ENV{LABEL}" STREQUAL "")
if ("$ENV{CTEST_BUILD_NAME}" STREQUAL "")
set(CTEST_BUILD_NAME "build")
else()
set(CTEST_BUILD_NAME $ENV{LABEL})
set(CTEST_BUILD_NAME $ENV{CTEST_BUILD_NAME})
endif()
ctest_start(Continuous)

73
Jenkinsfile vendored
View File

@ -1,73 +0,0 @@
#!groovy
def jobMatrix(String prefix, String type, List specs) {
def nodes = [:]
for (spec in specs) {
job = "${spec.os}-${spec.ver}-${spec.arch}-${spec.compiler}"
def label = "${type}/${job}"
def selector = "${spec.os}-${spec.ver}-${spec.arch}"
def os = spec.os
def ver = spec.ver
def check = spec.check
nodes[label] = {
node(selector) {
githubNotify(context: "${prefix}/${label}", description: 'Building ...', status: 'PENDING')
try {
deleteDir()
checkout scm
def jobscript = 'job.sh'
def ctestcmd = "ctest -S FairLoggerTest.cmake -V --output-on-failure"
sh "echo \"set -e\" >> ${jobscript}"
sh "echo \"export LABEL=\\\"\${JOB_BASE_NAME} ${label}\\\"\" >> ${jobscript}"
if (selector =~ /^macos/) {
sh "echo \"${ctestcmd}\" >> ${jobscript}"
sh "cat ${jobscript}"
sh "bash ${jobscript}"
} else {
def containercmd = "singularity exec -B/shared ${env.SINGULARITY_CONTAINER_ROOT}/fairlogger/${os}.${ver}.sif bash -l -c \\\"${ctestcmd}\\\""
sh """\
echo \"echo \\\"*** Job started at .......: \\\$(date -R)\\\"\" >> ${jobscript}
echo \"echo \\\"*** Job ID ...............: \\\${SLURM_JOB_ID}\\\"\" >> ${jobscript}
echo \"echo \\\"*** Compute node .........: \\\$(hostname -f)\\\"\" >> ${jobscript}
echo \"unset http_proxy\" >> ${jobscript}
echo \"unset HTTP_PROXY\" >> ${jobscript}
echo \"${containercmd}\" >> ${jobscript}
"""
sh "cat ${jobscript}"
sh "test/ci/slurm-submit.sh \"FairLogger \${JOB_BASE_NAME} ${label}\" ${jobscript}"
}
deleteDir()
githubNotify(context: "${prefix}/${label}", description: 'Success', status: 'SUCCESS')
} catch (e) {
deleteDir()
githubNotify(context: "${prefix}/${label}", description: 'Error', status: 'ERROR')
throw e
}
}
}
}
return nodes
}
pipeline{
agent none
stages {
stage("Run CI Matrix") {
steps{
script {
def builds = jobMatrix('alfa-ci', 'build', [
[os: 'fedora', ver: '32', arch: 'x86_64', compiler: 'gcc-10'],
[os: 'fedora', ver: '33', arch: 'x86_64', compiler: 'gcc-10'],
[os: 'fedora', ver: '34', arch: 'x86_64', compiler: 'gcc-11'],
[os: 'macos', ver: '11', arch: 'x86_64', compiler: 'apple-clang-12'],
])
parallel(builds)
}
}
}
}
}

View File

@ -68,9 +68,11 @@ A number of additional logging macros are provided:
- `LOGV(severity, verbosity)` Log the line with the provided verbosity, e.g. `LOG(info, veryhigh) << "abcd";`
- `LOGF(severity, ...)` The arguments are given to `fmt::printf`, which formats the string using a [printf syntax](https://fmt.dev/dev/api.html#printf-formatting) and the result is logged, e.g. `LOGF(info, "Hello %s!", "world");`
- `LOGP(severity, ...)` The arguments are given to `fmt::format`, which formats the string using a [Python-like syntax](https://fmt.dev/dev/syntax.html) and the result is logged, e.g. `LOGP(info, "Hello {}!", "world");`
- `LOGPD(severity, ...)` Same as `LOGP`, but accepts dynamic severity (runtime variable), e.g. `LOGPD(dynamicSeverity, "Hello {}!", "world");`
- `LOGFD(severity, ...)` Same as `LOGF`, but accepts dynamic severity (runtime variable), e.g. `LOGFD(dynamicSeverity, "Hello %s!", "world");`
- `LOGN(severity)` Logs an empty line, e.g. `LOGN(info);`
- `LOG_IF(severity, condition)` Logs the line if the provided condition if true
- `LOGD(severity, file, line, f)` Logs the line with the provided file, line and function parameters (only if the active verbosity allows it).
- `LOGD(severity, file, line, f)` Logs the line with the provided file, line and function parameters (accepts severity as a variable), e.g. `LOGD(dynamicSeverity, "main.cpp", "42", "main");`
## 3. Severity
@ -93,12 +95,14 @@ where severity level is one of the following:
"debug2",
"debug1",
"debug",
"detail",
"info",
"state",
"warn",
"important",
"alarm",
"error",
"critical",
"fatal",
```
@ -222,7 +226,7 @@ If only output from custom sinks is desirable, console/file sinks must be deacti
## Naming conflicts?
By default, `<fairlogger/Logger.h>` defines unprefixed macros: `LOG`, `LOGV`, `LOGF`, `LOGP`, `LOGN`, `LOGD`, `LOG_IF`.
By default, `<fairlogger/Logger.h>` defines unprefixed macros: `LOG`, `LOGV`, `LOGF`, `LOGP`, `LOGPD`, `LOGFD`, `LOGN`, `LOGD`, `LOG_IF`.
Define an option `FAIR_NO_LOG*` to prevent the above unprefixed macros to be defined, e.g.

View File

@ -94,7 +94,7 @@ macro(set_fairlogger_defaults)
endif()
# Handle C++ standard level
set(PROJECT_MIN_CXX_STANDARD 14)
set(PROJECT_MIN_CXX_STANDARD 17)
if(CMAKE_CXX_STANDARD LESS PROJECT_MIN_CXX_STANDARD)
message(FATAL_ERROR "A minimum CMAKE_CXX_STANDARD of ${PROJECT_MIN_CXX_STANDARD} is required.")
endif()
@ -128,8 +128,8 @@ macro(set_fairlogger_defaults)
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_LIBDIR}" isSystemDir)
if("${isSystemDir}" STREQUAL "-1")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
list(APPEND CMAKE_EXE_LINKER_FLAGS "-Wl,--enable-new-dtags")
list(APPEND CMAKE_SHARED_LINKER_FLAGS "-Wl,--enable-new-dtags")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,--enable-new-dtags")
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -Wl,--enable-new-dtags")
list(APPEND CMAKE_INSTALL_RPATH "$ORIGIN/../${PROJECT_INSTALL_LIBDIR}")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
list(APPEND CMAKE_INSTALL_RPATH "@loader_path/../${PROJECT_INSTALL_LIBDIR}")

View File

@ -1,11 +1,12 @@
/********************************************************************************
* Copyright (C) 2014-2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include "Logger.h"
#include <string_view>
#if FMT_VERSION < 60000
#include <fmt/time.h>
@ -15,6 +16,7 @@
#include <cstdio> // printf
#include <iostream>
#include <iterator> // std::back_inserter
using namespace std;
@ -43,55 +45,59 @@ const string Logger::fProcessName = program_invocation_short_name;
const string Logger::fProcessName = "?";
#endif
const unordered_map<string, Verbosity> Logger::fVerbosityMap =
const unordered_map<string_view, Verbosity> Logger::fVerbosityMap =
{
{ "veryhigh", Verbosity::veryhigh },
{ "high", Verbosity::high },
{ "medium", Verbosity::medium },
{ "low", Verbosity::low },
{ "verylow", Verbosity::verylow },
{ "VERYHIGH", Verbosity::veryhigh },
{ "HIGH", Verbosity::high },
{ "MEDIUM", Verbosity::medium },
{ "LOW", Verbosity::low },
{ "VERYLOW", Verbosity::verylow },
{ "user1", Verbosity::user1 },
{ "user2", Verbosity::user2 },
{ "user3", Verbosity::user3 },
{ "user4", Verbosity::user4 }
{ {"veryhigh"}, Verbosity::veryhigh },
{ {"high"}, Verbosity::high },
{ {"medium"}, Verbosity::medium },
{ {"low"}, Verbosity::low },
{ {"verylow"}, Verbosity::verylow },
{ {"VERYHIGH"}, Verbosity::veryhigh },
{ {"HIGH"}, Verbosity::high },
{ {"MEDIUM"}, Verbosity::medium },
{ {"LOW"}, Verbosity::low },
{ {"VERYLOW"}, Verbosity::verylow },
{ {"user1"}, Verbosity::user1 },
{ {"user2"}, Verbosity::user2 },
{ {"user3"}, Verbosity::user3 },
{ {"user4"}, Verbosity::user4 }
};
const unordered_map<string, Severity> Logger::fSeverityMap =
const unordered_map<string_view, Severity> Logger::fSeverityMap =
{
{ "nolog", Severity::nolog },
{ "NOLOG", Severity::nolog },
{ "error", Severity::error },
{ "ERROR", Severity::error },
{ "alarm", Severity::alarm },
{ "important", Severity::important },
{ "warn", Severity::warn },
{ "WARN", Severity::warn },
{ "warning", Severity::warn },
{ "WARNING", Severity::warn },
{ "state", Severity::state },
{ "STATE", Severity::state },
{ "info", Severity::info },
{ "INFO", Severity::info },
{ "debug", Severity::debug },
{ "DEBUG", Severity::debug },
{ "debug1", Severity::debug1 },
{ "DEBUG1", Severity::debug1 },
{ "debug2", Severity::debug2 },
{ "DEBUG2", Severity::debug2 },
{ "debug3", Severity::debug3 },
{ "DEBUG3", Severity::debug3 },
{ "debug4", Severity::debug4 },
{ "DEBUG4", Severity::debug4 },
{ "trace", Severity::trace },
{ "TRACE", Severity::trace }
{ {"nolog"}, Severity::nolog },
{ {"NOLOG"}, Severity::nolog },
{ {"fatal"}, Severity::fatal },
{ {"FATAL"}, Severity::fatal },
{ {"critical"}, Severity::critical },
{ {"error"}, Severity::error },
{ {"ERROR"}, Severity::error },
{ {"alarm"}, Severity::alarm },
{ {"important"}, Severity::important },
{ {"warn"}, Severity::warn },
{ {"WARN"}, Severity::warn },
{ {"warning"}, Severity::warn },
{ {"WARNING"}, Severity::warn },
{ {"state"}, Severity::state },
{ {"STATE"}, Severity::state },
{ {"info"}, Severity::info },
{ {"INFO"}, Severity::info },
{ {"detail"}, Severity::detail },
{ {"debug"}, Severity::debug },
{ {"DEBUG"}, Severity::debug },
{ {"debug1"}, Severity::debug1 },
{ {"DEBUG1"}, Severity::debug1 },
{ {"debug2"}, Severity::debug2 },
{ {"DEBUG2"}, Severity::debug2 },
{ {"debug3"}, Severity::debug3 },
{ {"DEBUG3"}, Severity::debug3 },
{ {"debug4"}, Severity::debug4 },
{ {"DEBUG4"}, Severity::debug4 },
{ {"trace"}, Severity::trace },
{ {"TRACE"}, Severity::trace }
};
const array<string, 14> Logger::fSeverityNames =
const array<string_view, 16> Logger::fSeverityNames =
{
{
"NOLOG",
@ -101,17 +107,19 @@ const array<string, 14> Logger::fSeverityNames =
"DEBUG2",
"DEBUG1",
"DEBUG",
"DETAIL",
"INFO",
"STATE",
"WARN",
"IMPORTANT",
"ALARM",
"ERROR",
"CRITICAL",
"FATAL"
}
};
const array<string, 9> Logger::fVerbosityNames =
const array<string_view, 9> Logger::fVerbosityNames =
{
{
"verylow",
@ -139,12 +147,11 @@ map<Verbosity, VSpec> Logger::fVerbosities =
{ Verbosity::user4, VSpec::Make(VSpec::Info::severity) }
};
Logger::Logger(Severity severity, Verbosity verbosity, const string& file, const string& line, const string& func)
Logger::Logger(Severity severity, Verbosity verbosity, std::string_view file, std::string_view line, std::string_view func)
: fTimeCalculated(false)
{
if (!fIsDestructed) {
size_t pos = file.rfind("/");
// fInfos.timestamp is filled conditionally
// fInfos.us is filled conditionally
fInfos.process_name = fProcessName;
@ -160,27 +167,27 @@ Logger::Logger(Severity severity, Verbosity verbosity, const string& file, const
for (const auto info : spec.fInfos) {
switch (info) {
case VSpec::Info::process_name:
fmt::format_to(fBWPrefix, "[{}]", fInfos.process_name);
fmt::format_to(std::back_inserter(fBWPrefix), "[{}]", fInfos.process_name);
break;
case VSpec::Info::timestamp_us:
FillTimeInfos();
fmt::format_to(fBWPrefix, "[{:%H:%M:%S}.{:06}]", fmt::localtime(fInfos.timestamp), fInfos.us.count());
fmt::format_to(std::back_inserter(fBWPrefix), "[{:%H:%M:%S}.{:06}]", fmt::localtime(fInfos.timestamp), fInfos.us.count());
break;
case VSpec::Info::timestamp_s:
FillTimeInfos();
fmt::format_to(fBWPrefix, "[{:%H:%M:%S}]", fmt::localtime(fInfos.timestamp));
fmt::format_to(std::back_inserter(fBWPrefix), "[{:%H:%M:%S}]", fmt::localtime(fInfos.timestamp));
break;
case VSpec::Info::severity:
fmt::format_to(fBWPrefix, "[{}]", fInfos.severity_name);
fmt::format_to(std::back_inserter(fBWPrefix), "[{}]", fInfos.severity_name);
break;
case VSpec::Info::file_line_function:
fmt::format_to(fBWPrefix, "[{}:{}:{}]", fInfos.file, fInfos.line, fInfos.func);
fmt::format_to(std::back_inserter(fBWPrefix), "[{}:{}:{}]", fInfos.file, fInfos.line, fInfos.func);
break;
case VSpec::Info::file_line:
fmt::format_to(fBWPrefix, "[{}:{}]", fInfos.file, fInfos.line);
fmt::format_to(std::back_inserter(fBWPrefix), "[{}:{}]", fInfos.file, fInfos.line);
break;
case VSpec::Info::file:
fmt::format_to(fBWPrefix, "[{}]", fInfos.file);
fmt::format_to(std::back_inserter(fBWPrefix), "[{}]", fInfos.file);
break;
default:
break;
@ -188,7 +195,7 @@ Logger::Logger(Severity severity, Verbosity verbosity, const string& file, const
}
if (spec.fSize > 0) {
fmt::format_to(fBWPrefix, " ");
fmt::format_to(std::back_inserter(fBWPrefix), " ");
}
}
@ -196,27 +203,27 @@ Logger::Logger(Severity severity, Verbosity verbosity, const string& file, const
for (const auto info : spec.fInfos) {
switch (info) {
case VSpec::Info::process_name:
fmt::format_to(fColorPrefix, "[{}]", ColorOut(Color::fgBlue, fInfos.process_name));
fmt::format_to(std::back_inserter(fColorPrefix), "[{}]", ColorOut(Color::fgBlue, fInfos.process_name));
break;
case VSpec::Info::timestamp_us:
FillTimeInfos();
fmt::format_to(fColorPrefix, "[{}{:%H:%M:%S}.{:06}{}]", startColor(Color::fgCyan), fmt::localtime(fInfos.timestamp), fInfos.us.count(), endColor());
fmt::format_to(std::back_inserter(fColorPrefix), "[{}{:%H:%M:%S}.{:06}{}]", startColor(Color::fgCyan), fmt::localtime(fInfos.timestamp), fInfos.us.count(), endColor());
break;
case VSpec::Info::timestamp_s:
FillTimeInfos();
fmt::format_to(fColorPrefix, "[{}{:%H:%M:%S}{}]", startColor(Color::fgCyan), fmt::localtime(fInfos.timestamp), endColor());
fmt::format_to(std::back_inserter(fColorPrefix), "[{}{:%H:%M:%S}{}]", startColor(Color::fgCyan), fmt::localtime(fInfos.timestamp), endColor());
break;
case VSpec::Info::severity:
fmt::format_to(fColorPrefix, "[{}]", GetColoredSeverityString(fInfos.severity));
fmt::format_to(std::back_inserter(fColorPrefix), "[{}]", GetColoredSeverityString(fInfos.severity));
break;
case VSpec::Info::file_line_function:
fmt::format_to(fColorPrefix, "[{}:{}:{}]", ColorOut(Color::fgBlue, fInfos.file), ColorOut(Color::fgYellow, fInfos.line), ColorOut(Color::fgBlue, fInfos.func));
fmt::format_to(std::back_inserter(fColorPrefix), "[{}:{}:{}]", ColorOut(Color::fgBlue, fInfos.file), ColorOut(Color::fgYellow, fInfos.line), ColorOut(Color::fgBlue, fInfos.func));
break;
case VSpec::Info::file_line:
fmt::format_to(fColorPrefix, "[{}:{}]", ColorOut(Color::fgBlue, fInfos.file), ColorOut(Color::fgYellow, fInfos.line));
fmt::format_to(std::back_inserter(fColorPrefix), "[{}:{}]", ColorOut(Color::fgBlue, fInfos.file), ColorOut(Color::fgYellow, fInfos.line));
break;
case VSpec::Info::file:
fmt::format_to(fColorPrefix, "[{}]", ColorOut(Color::fgBlue, fInfos.file));
fmt::format_to(std::back_inserter(fColorPrefix), "[{}]", ColorOut(Color::fgBlue, fInfos.file));
break;
default:
break;
@ -224,7 +231,7 @@ Logger::Logger(Severity severity, Verbosity verbosity, const string& file, const
}
if (spec.fSize > 0) {
fmt::format_to(fColorPrefix, " ");
fmt::format_to(std::back_inserter(fColorPrefix), " ");
}
}
@ -284,12 +291,14 @@ string Logger::GetColoredSeverityString(Severity severity)
switch (severity) {
case Severity::nolog: return "\033[01;39mNOLOG\033[0m"; break;
case Severity::fatal: return "\033[01;31mFATAL\033[0m"; break;
case Severity::critical: return "\033[01;31mCRITICAL\033[0m"; break;
case Severity::error: return "\033[01;31mERROR\033[0m"; break;
case Severity::alarm: return "\033[01;33mALARM\033[0m"; break;
case Severity::important: return "\033[01;32mIMPORTANT\033[0m"; break;
case Severity::warn: return "\033[01;33mWARN\033[0m"; break;
case Severity::state: return "\033[01;35mSTATE\033[0m"; break;
case Severity::info: return "\033[01;32mINFO\033[0m"; break;
case Severity::detail: return "\033[01;32mDETAIL\033[0m"; break;
case Severity::debug: return "\033[01;34mDEBUG\033[0m"; break;
case Severity::debug1: return "\033[01;34mDEBUG1\033[0m"; break;
case Severity::debug2: return "\033[01;34mDEBUG2\033[0m"; break;

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -26,6 +26,7 @@
#include <fmt/core.h>
#include <fmt/printf.h>
#include <fmt/ostream.h>
#pragma GCC diagnostic pop
@ -44,6 +45,7 @@
#include <time.h> // time_t
#include <type_traits> // is_same
#include <unordered_map>
#include <string_view>
#include <utility> // pair
namespace fair
@ -58,29 +60,31 @@ enum class Severity : int
debug2 = 4,
debug1 = 5,
debug = 6,
info = 7,
state = 8,
warn = 9,
important = 10,
alarm = 11,
error = 12,
fatal = 13,
detail = 7,
info = 8,
state = 9,
warn = 10,
important = 11,
alarm = 12,
error = 13,
critical = 14,
fatal = 15,
// aliases
warning = warn,
// backwards-compatibility
NOLOG [[deprecated("Use 'nolog' instead")]] = nolog,
TRACE [[deprecated("Use 'trace' instead")]] = trace,
DEBUG4 [[deprecated("Use 'debug4' instead")]] = debug4,
DEBUG3 [[deprecated("Use 'debug3' instead")]] = debug3,
DEBUG2 [[deprecated("Use 'debug2' instead")]] = debug2,
DEBUG1 [[deprecated("Use 'debug1' instead")]] = debug1,
DEBUG [[deprecated("Use 'debug' instead")]] = debug,
INFO [[deprecated("Use 'info' instead")]] = info,
STATE [[deprecated("Use 'state' instead")]] = state,
WARNING [[deprecated("Use 'warning' instead")]] = warn,
WARN [[deprecated("Use 'warn' instead")]] = warn,
ERROR [[deprecated("Use 'error' instead")]] = error,
FATAL [[deprecated("Use 'fatal' instead")]] = fatal
NOLOG __attribute__((deprecated("Use LOG(nolog) instead (lowercase severity name)."))) = nolog,
FATAL __attribute__((deprecated("Use LOG(fatal) instead (lowercase severity name)."))) = fatal,
ERROR __attribute__((deprecated("Use LOG(error) instead (lowercase severity name)."))) = error,
WARN __attribute__((deprecated("Use LOG(warn) instead (lowercase severity name)."))) = warn,
WARNING __attribute__((deprecated("Use LOG(warning) instead (lowercase severity name)."))) = warn,
STATE __attribute__((deprecated("Use LOG(state) instead (lowercase severity name)."))) = state,
INFO __attribute__((deprecated("Use LOG(info) instead (lowercase severity name)."))) = info,
DEBUG __attribute__((deprecated("Use LOG(debug) instead (lowercase severity name)."))) = debug,
DEBUG1 __attribute__((deprecated("Use LOG(debug1) instead (lowercase severity name)."))) = debug1,
DEBUG2 __attribute__((deprecated("Use LOG(debug2) instead (lowercase severity name)."))) = debug2,
DEBUG3 __attribute__((deprecated("Use LOG(debug3) instead (lowercase severity name)."))) = debug3,
DEBUG4 __attribute__((deprecated("Use LOG(debug4) instead (lowercase severity name)."))) = debug4,
TRACE __attribute__((deprecated("Use LOG(trace) instead (lowercase severity name)."))) = trace
};
// verbosity levels:
@ -173,19 +177,19 @@ struct LogMetaData
{
std::time_t timestamp;
std::chrono::microseconds us;
std::string process_name;
std::string file;
std::string line;
std::string func;
std::string severity_name;
std::string_view process_name;
std::string_view file;
std::string_view line;
std::string_view func;
std::string_view severity_name;
fair::Severity severity;
};
class Logger
{
public:
Logger(Severity severity, Verbosity verbosity, const std::string& file, const std::string& line, const std::string& func);
Logger(Severity severity, const std::string& file, const std::string& line, const std::string& func)
Logger(Severity severity, Verbosity verbosity, std::string_view file, std::string_view line, std::string_view func);
Logger(Severity severity, std::string_view file, std::string_view line, std::string_view func)
: Logger(severity, fVerbosity, file, line, func)
{}
virtual ~Logger() noexcept(false);
@ -242,7 +246,7 @@ class Logger
static std::string startColor(Color color) { return fmt::format("\033[01;{}m", static_cast<int>(color)); }
static std::string endColor() { return "\033[0m"; }
static std::string ColorOut(Color c, const std::string& s) { return fmt::format("\033[01;{}m{}\033[0m", static_cast<int>(c), s); }
static std::string ColorOut(Color c, std::string_view s) { return fmt::format("\033[01;{}m{}\033[0m", static_cast<int>(c), s); }
static std::string GetColoredSeverityString(Severity severity);
static void SetConsoleSeverity(const Severity severity);
@ -283,8 +287,8 @@ class Logger
static void RemoveFileSink();
static std::string SeverityName(Severity s) { return fSeverityNames.at(static_cast<size_t>(s)); }
static std::string VerbosityName(Verbosity v) { return fVerbosityNames.at(static_cast<size_t>(v)); }
static std::string_view SeverityName(Severity s) { return fSeverityNames.at(static_cast<size_t>(s)); }
static std::string_view VerbosityName(Verbosity v) { return fVerbosityNames.at(static_cast<size_t>(v)); }
static void OnFatal(std::function<void()> func);
@ -320,10 +324,10 @@ class Logger
Logger& operator<<(std::ios_base& (*manip) (std::ios_base&));
Logger& operator<<(std::ostream& (*manip) (std::ostream&));
static const std::unordered_map<std::string, Verbosity> fVerbosityMap;
static const std::unordered_map<std::string, Severity> fSeverityMap;
static const std::array<std::string, 14> fSeverityNames;
static const std::array<std::string, 9> fVerbosityNames;
static const std::unordered_map<std::string_view, Verbosity> fVerbosityMap;
static const std::unordered_map<std::string_view, Severity> fSeverityMap;
static const std::array<std::string_view, 16> fSeverityNames;
static const std::array<std::string_view, 9> fVerbosityNames;
// protection for use after static destruction took place
static bool fIsDestructed;
@ -390,16 +394,16 @@ inline std::ostream& operator<<(std::ostream& os, const Verbosity& v) { return o
#undef LOGV
#define LOGV FAIR_LOGV
#endif
// allow user of this header file to prevent definition of the LOGF macro, by defining FAIR_NO_LOGF before including this header
#ifndef FAIR_NO_LOGF
#undef LOGF
#define LOGF FAIR_LOGF
#endif
// allow user of this header file to prevent definition of the LOGP macro, by defining FAIR_NO_LOGP before including this header
#ifndef FAIR_NO_LOGP
#undef LOGP
#define LOGP FAIR_LOGP
#endif
// allow user of this header file to prevent definition of the LOGF macro, by defining FAIR_NO_LOGF before including this header
#ifndef FAIR_NO_LOGF
#undef LOGF
#define LOGF FAIR_LOGF
#endif
// allow user of this header file to prevent definition of the LOGN macro, by defining FAIR_NO_LOGN before including this header
#ifndef FAIR_NO_LOGN
#undef LOGN
@ -415,6 +419,16 @@ inline std::ostream& operator<<(std::ostream& os, const Verbosity& v) { return o
#undef LOG_IF
#define LOG_IF FAIR_LOG_IF
#endif
// allow user of this header file to prevent definition of the LOGPD macro, by defining FAIR_NO_LOGPD before including this header
#ifndef FAIR_NO_LOGPD
#undef LOGPD
#define LOGPD FAIR_LOGPD
#endif
// allow user of this header file to prevent definition of the LOGFD macro, by defining FAIR_NO_LOGFD before including this header
#ifndef FAIR_NO_LOGFD
#undef LOGFD
#define LOGFD FAIR_LOGFD
#endif
// Log line if the provided severity is below or equals the configured one
#define FAIR_LOG(severity) \
@ -429,8 +443,19 @@ inline std::ostream& operator<<(std::ostream& os, const Verbosity& v) { return o
fair::Logger(fair::Severity::severity, fair::Verbosity::verbosity, MSG_ORIGIN)
// Log with fmt- or printf-like formatting
#define FAIR_LOGP(severity, ...) LOG(severity) << fmt::format(__VA_ARGS__)
#define FAIR_LOGF(severity, ...) LOG(severity) << fmt::sprintf(__VA_ARGS__)
#define FAIR_LOGP(severity, ...) FAIR_LOG(severity) << fmt::format(__VA_ARGS__)
#define FAIR_LOGF(severity, ...) FAIR_LOG(severity) << fmt::sprintf(__VA_ARGS__)
// Log with fmt- or printf-like formatting (dynamic severity)
#define FAIR_LOGPD(severity, ...) \
for (bool fairLOggerunLikelyvariable3 = false; !fair::Logger::SuppressSeverity(severity) && !fairLOggerunLikelyvariable3; fairLOggerunLikelyvariable3 = true) \
for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \
fair::Logger(severity, MSG_ORIGIN) << fmt::format(__VA_ARGS__)
#define FAIR_LOGFD(severity, ...) \
for (bool fairLOggerunLikelyvariable3 = false; !fair::Logger::SuppressSeverity(severity) && !fairLOggerunLikelyvariable3; fairLOggerunLikelyvariable3 = true) \
for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \
fair::Logger(severity, MSG_ORIGIN) << fmt::sprintf(__VA_ARGS__)
// Log an empty line
#define FAIR_LOGN(severity) \
@ -447,6 +472,6 @@ inline std::ostream& operator<<(std::ostream& os, const Verbosity& v) { return o
#define FAIR_LOG_IF(severity, condition) \
for (bool fairLOggerunLikelyvariable4 = false; !fair::Logger::SuppressSeverity(fair::Severity::severity) && !fairLOggerunLikelyvariable4; fairLOggerunLikelyvariable4 = true) \
for (bool fairLOggerunLikelyvariable2 = false; condition && !fairLOggerunLikelyvariable2; fairLOggerunLikelyvariable2 = true) \
LOG(severity)
FAIR_LOG(severity)
#endif // FAIR_LOGGER_H

View File

@ -32,5 +32,10 @@ endfunction()
container(OS fedora VERSION 32)
container(OS fedora VERSION 33)
container(OS fedora VERSION 34)
container(OS fedora VERSION 35)
container(OS fedora VERSION 36)
container(OS fedora VERSION 37)
container(OS fedora VERSION 38)
container(OS fedora VERSION 39)
add_custom_target(all-containers DEPENDS ${containers})

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2015-2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -38,7 +38,7 @@ int main()
Logger::SetConsoleSeverity(Severity::fatal);
cout << "initial severity >" << Logger::GetConsoleSeverity() << "<" << endl << endl;
array<Severity, 14> severitiesUp{{ Severity::nolog, Severity::trace, Severity::debug4, Severity::debug3, Severity::debug2, Severity::debug1, Severity::debug, Severity::info, Severity::state, Severity::warn, Severity::important, Severity::alarm, Severity::error, Severity::fatal }};
array<Severity, 16> severitiesUp{{ Severity::nolog, Severity::trace, Severity::debug4, Severity::debug3, Severity::debug2, Severity::debug1, Severity::debug, Severity::detail, Severity::info, Severity::state, Severity::warn, Severity::important, Severity::alarm, Severity::error, Severity::critical, Severity::fatal }};
#ifdef FAIR_MIN_SEVERITY
for (unsigned int i = static_cast<int>(Severity::FAIR_MIN_SEVERITY); i < severitiesUp.size(); ++i) {
#else
@ -57,7 +57,7 @@ int main()
Logger::SetConsoleSeverity(Severity::fatal);
cout << "initial severity >" << Logger::GetConsoleSeverity() << "<" << endl << endl;
array<Severity, 14> severitiesDown{{ Severity::error, Severity::alarm, Severity::important, Severity::warn, Severity::state, Severity::info, Severity::debug, Severity::debug1, Severity::debug2, Severity::debug3, Severity::debug4, Severity::trace, Severity::nolog, Severity::fatal }};
array<Severity, 16> severitiesDown{{ Severity::critical, Severity::error, Severity::alarm, Severity::important, Severity::warn, Severity::state, Severity::info, Severity::detail, Severity::debug, Severity::debug1, Severity::debug2, Severity::debug3, Severity::debug4, Severity::trace, Severity::nolog, Severity::fatal }};
#ifdef FAIR_MIN_SEVERITY
for (unsigned int i = 0; i < severitiesDown.size() - static_cast<int>(Severity::FAIR_MIN_SEVERITY) - 1; ++i) {
#else

View File

@ -24,12 +24,14 @@ void printEverySeverity()
LOG(debug2) << "debug2 message, counter: " << i++;
LOG(debug1) << "debug1 message, counter: " << i++;
LOG(debug) << "debug message, counter: " << i++;
LOG(detail) << "detail message, counter: " << i++;
LOG(info) << "info message, counter: " << i++;
LOG(state) << "state message, counter: " << i++;
LOG(warn) << "warning message, counter: " << i++;
LOG(important) << "important message, counter: " << i++;
LOG(alarm) << "alarm message, counter: " << i++;
LOG(error) << "error message, counter: " << i++;
LOG(critical) << "critical message, counter: " << i++;
LOG(fatal) << "fatal message, counter: " << i++;
}

View File

@ -51,6 +51,13 @@ int main()
CheckOutput(ToStr(R"(^\[.*\]\[\d{2}:\d{2}:\d{2}\.\d{6}\]\[FATAL\]\[a:4:b\])", " c\n$"), []() {
LOGD(Severity::fatal, "a", "4", "b") << "c";
});
// Test dynamic severity macros
Logger::SetVerbosity(Verbosity::verylow);
Severity dynamicSeverity = Severity::fatal;
CheckOutput("^Hello dynamic world :-\\)!\n$", [&]() { LOGPD(dynamicSeverity, "Hello {} {}!", "dynamic world", ":-)"); });
CheckOutput("^Hello dynamic world :-\\)!\n$", [&]() { LOGFD(dynamicSeverity, "Hello %s %s!", "dynamic world", ":-)"); });
} catch (runtime_error& rte) {
cout << rte.what() << endl;
return 1;

View File

@ -13,19 +13,21 @@ using namespace fair;
void printEverySeverity()
{
LOG(nolog) << "nolog message, counter: ";
LOG(trace) << "trace message, counter: ";
LOG(debug4) << "debug4 message, counter: ";
LOG(debug3) << "debug3 message, counter: ";
LOG(debug2) << "debug2 message, counter: ";
LOG(debug1) << "debug1 message, counter: ";
LOG(debug) << "debug message, counter: ";
LOG(info) << "info message, counter: ";
LOG(state) << "state message, counter: ";
LOG(warn) << "warning message, counter: ";
LOG(important) << "important message, counter: ";
LOG(alarm) << "alarm message, counter: ";
LOG(error) << "error message, counter: ";
LOG(nolog) << "nolog message ";
LOG(trace) << "trace message ";
LOG(debug4) << "debug4 message ";
LOG(debug3) << "debug3 message ";
LOG(debug2) << "debug2 message ";
LOG(debug1) << "debug1 message ";
LOG(debug) << "debug message ";
LOG(detail) << "detail message ";
LOG(info) << "info message ";
LOG(state) << "state message ";
LOG(warn) << "warning message ";
LOG(important) << "important message ";
LOG(alarm) << "alarm message ";
LOG(error) << "error message ";
LOG(critical) << "critical message ";
}
void silentlyPrintAllVerbositiesWithSeverity(Severity sev)

View File

@ -27,12 +27,14 @@ uint32_t printEverySeverity(uint32_t i)
LOG(debug2) << "debug2 message, counter: " << i++;
LOG(debug1) << "debug1 message, counter: " << i++;
LOG(debug) << "debug message, counter: " << i++;
LOG(detail) << "detail message, counter: " << i++;
LOG(info) << "info message, counter: " << i++;
LOG(state) << "state message, counter: " << i++;
LOG(warn) << "warning message, counter: " << i++;
LOG(important) << "important message, counter: " << i++;
LOG(alarm) << "alarm message, counter: " << i++;
LOG(error) << "error message, counter: " << i++;
LOG(critical) << "critical message, counter: " << i++;
LOG(fatal) << "fatal message, counter: " << i++;
return i;