Compare commits

..

25 Commits

Author SHA1 Message Date
Alexey Rybalchenko
c6594934d4 Fix unrelocatable stuff 2021-03-07 10:13:35 +01:00
David Rohr
bcfe438862 Use for instead of if syntax to avoid compiler warnings 2020-08-25 18:53:01 +02:00
Alexey Rybalchenko
4b3e6d3837 Always define FAIR_MIN_SEVERITY 2020-07-17 11:40:15 +02:00
Alexey Rybalchenko
b30cacab12 Adjust regex expressions 2020-07-17 11:40:15 +02:00
Alexey Rybalchenko
c8d59d11fb Add test for cycle methods 2020-07-17 11:40:15 +02:00
Alexey Rybalchenko
a737a1de9c Add output operator for severities, verbosities 2020-07-17 11:40:15 +02:00
Alexey Rybalchenko
1cb941021c Add getters for file & custom sink severity 2020-07-17 11:40:15 +02:00
Alexey Rybalchenko
de1014dabb Add unit tests 2020-07-17 11:40:15 +02:00
Alexey Rybalchenko
ce64f628b0 Remove NDEBUG check 2020-07-17 11:40:15 +02:00
Alexey Rybalchenko
35ebc10204 Consider FAIR_MIN_SEVERITY when setting severities 2020-07-17 11:40:15 +02:00
Alexey Rybalchenko
1253bbbac8 Throw if removing non-existing sink or adding existing 2020-07-17 11:40:15 +02:00
Alexey Rybalchenko
e9bd3f2b62 InitFileSink(): return name of the created file 2020-07-17 11:40:15 +02:00
Alexey Rybalchenko
1f3b2a2c82 Minor formatting 2020-07-17 11:40:15 +02:00
Alexey Rybalchenko
2b37d0147e make GetColoredSeverityString public 2020-07-17 11:40:15 +02:00
Alexey Rybalchenko
f0cbe0bd47 Move Logging() to header 2020-07-17 11:40:15 +02:00
Alexey Rybalchenko
5f7197d987 Fix file sink and update fMinSeverity on its removal 2020-07-17 11:40:15 +02:00
Alexey Rybalchenko
b1cb6f8a99 Add CMake variable to control FAIR_MIN_SEVERITY 2020-07-17 11:40:15 +02:00
Alexey Rybalchenko
56780689fc Exchange the meaning of LOGP and LOGF 2020-06-22 09:49:07 +02:00
Alexey Rybalchenko
8446c6db0c Update docs 2020-06-18 11:30:34 +02:00
Alexey Rybalchenko
a0ff4eba50 Fixes for the updated severity order 2020-06-18 10:56:00 +02:00
David Rohr
cfe0f9dc53 Suppress LOG messages with debug severity or less at compile time for release builds 2020-06-18 10:56:00 +02:00
Alexey Rybalchenko
cdf887f5da Support fmt >=6.0.0 2020-03-03 12:53:23 +01:00
Alexey Rybalchenko
6555aa1dc0 Update README.md
Co-Authored-By: Dennis Klein <dennis.klein.github@gmail.com>
2020-03-03 09:53:01 +01:00
Alexey Rybalchenko
d1f73fe9f0 Use prefixed macro names, allow suppressing unprefixed 2020-03-03 09:53:01 +01:00
Dennis Klein
86ab87de7b CMake: Do not install the test executable 2019-12-17 19:16:25 +01:00
15 changed files with 1119 additions and 395 deletions

View File

@@ -7,7 +7,7 @@
################################################################################ ################################################################################
cmake_minimum_required(VERSION 3.9.4 FATAL_ERROR) cmake_minimum_required(VERSION 3.9.4 FATAL_ERROR)
cmake_policy(VERSION 3.9...3.14) cmake_policy(VERSION 3.9...3.15)
# Project ###################################################################### # Project ######################################################################
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
@@ -75,10 +75,14 @@ else()
list(APPEND FAIRLOGGER_INSTALL_INCLUDE_DIRS ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_INCDIR}/bundled) list(APPEND FAIRLOGGER_INSTALL_INCLUDE_DIRS ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_INCDIR}/bundled)
endif() endif()
if(DEFINED FAIR_MIN_SEVERITY)
target_compile_definitions(FairLogger PUBLIC "FAIR_MIN_SEVERITY=${FAIR_MIN_SEVERITY}")
endif()
target_include_directories(FairLogger target_include_directories(FairLogger
PUBLIC PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/logger> $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/logger>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
) )
set_target_properties(FairLogger PROPERTIES set_target_properties(FairLogger PROPERTIES
VERSION ${PROJECT_GIT_VERSION} VERSION ${PROJECT_GIT_VERSION}
@@ -86,8 +90,22 @@ set_target_properties(FairLogger PROPERTIES
) )
if(BUILD_TESTING) if(BUILD_TESTING)
add_executable(loggerTest test/loggerTest.cxx) add_executable(cycleTest test/cycle.cxx)
target_link_libraries(loggerTest FairLogger pthread) target_link_libraries(cycleTest FairLogger)
add_executable(loggerTest test/logger.cxx)
target_link_libraries(loggerTest FairLogger)
add_executable(macrosTest test/macros.cxx)
target_link_libraries(macrosTest FairLogger)
add_executable(nologTest test/nolog.cxx)
target_link_libraries(nologTest FairLogger)
add_executable(severityTest test/severity.cxx)
target_link_libraries(severityTest FairLogger)
add_executable(sinksTest test/sinks.cxx)
target_link_libraries(sinksTest FairLogger)
add_executable(threadsTest test/threads.cxx)
target_link_libraries(threadsTest FairLogger pthread)
add_executable(verbosityTest test/verbosity.cxx)
target_link_libraries(verbosityTest FairLogger)
endif() endif()
################################################################################ ################################################################################
@@ -100,7 +118,6 @@ if(NOT USE_EXTERNAL_FMT)
endif() endif()
install(TARGETS install(TARGETS
FairLogger FairLogger
${test_targets}
${fmt_target} ${fmt_target}
EXPORT ${PROJECT_EXPORT_SET} EXPORT ${PROJECT_EXPORT_SET}
@@ -128,7 +145,14 @@ install_cmake_package()
# Testing ###################################################################### # Testing ######################################################################
if(BUILD_TESTING) if(BUILD_TESTING)
add_test(NAME loggerTest COMMAND $<TARGET_FILE:loggerTest>) add_test(NAME cycle COMMAND $<TARGET_FILE:cycleTest>)
add_test(NAME logger COMMAND $<TARGET_FILE:loggerTest>)
add_test(NAME macros COMMAND $<TARGET_FILE:macrosTest>)
add_test(NAME nolog COMMAND $<TARGET_FILE:nologTest>)
add_test(NAME severity COMMAND $<TARGET_FILE:severityTest>)
add_test(NAME sinks COMMAND $<TARGET_FILE:sinksTest>)
add_test(NAME threads COMMAND $<TARGET_FILE:threadsTest>)
add_test(NAME verbosity COMMAND $<TARGET_FILE:verbosityTest>)
endif() endif()
################################################################################ ################################################################################
@@ -213,6 +237,12 @@ else()
endif() endif()
message(STATUS " ${BWhite}tests${CR} ${testing_summary}") message(STATUS " ${BWhite}tests${CR} ${testing_summary}")
message(STATUS " ") message(STATUS " ")
if(DEFINED FAIR_MIN_SEVERITY)
message(STATUS " ${Cyan}FAIR_MIN_SEVERITY${CR} ${BGreen}${FAIR_MIN_SEVERITY}${CR} (change with ${BMagenta}-DFAIR_MIN_SEVERITY=...${CR})")
else()
message(STATUS " ${Cyan}FAIR_MIN_SEVERITY${CR} not defined${CR}, enabling all severities (change with ${BMagenta}-DFAIR_MIN_SEVERITY=...${CR})")
endif()
message(STATUS " ")
message(STATUS " ${Cyan}INSTALL PREFIX${CR} ${BGreen}${CMAKE_INSTALL_PREFIX}${CR} (change with ${BMagenta}-DCMAKE_INSTALL_PREFIX=...${CR})") message(STATUS " ${Cyan}INSTALL PREFIX${CR} ${BGreen}${CMAKE_INSTALL_PREFIX}${CR} (change with ${BMagenta}-DCMAKE_INSTALL_PREFIX=...${CR})")
message(STATUS " ") message(STATUS " ")
################################################################################ ################################################################################

View File

@@ -42,7 +42,7 @@ If FairLogger is built with `-DUSE_BOOST_PRETTY_FUNCTION=ON` and/or `-DUSE_EXTER
```cmake ```cmake
find_package(FairLogger) find_package(FairLogger)
foreach(dep IN LISTS FairLogger_PACKAGE_DEPENDENCIES) foreach(dep IN LISTS FairLogger_PACKAGE_DEPENDENCIES)
find_package(${dep} ${FairLogger_${dep}_VERSION}) find_package(${dep} ${FairLogger_${dep}_VERSION})
endforeach() endforeach()
``` ```
@@ -66,8 +66,8 @@ All log calls go through the provided LOG(severity) macro. Output through this m
A number of additional logging macros are provided: A number of additional logging macros are provided:
- `LOGV(severity, verbosity)` Log the line with the provided verbosity, e.g. `LOG(info, veryhigh) << "abcd";` - `LOGV(severity, verbosity)` Log the line with the provided verbosity, e.g. `LOG(info, veryhigh) << "abcd";`
- `LOGF(severity, ...)` The arguments are given to `fmt::format` and the result is logged, e.g. `LOGF(info, "Hello {}!", "world");` - `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::printf` and the result is logged, e.g. `LOGP(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");`
- `LOGN(severity)` Logs an empty line, e.g. `LOGN(info);` - `LOGN(severity)` Logs an empty line, e.g. `LOGN(info);`
- `LOG_IF(severity, condition)` Logs the line if the provided condition if true - `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 (only if the active verbosity allows it).
@@ -87,21 +87,32 @@ where severity level is one of the following:
```C++ ```C++
"nolog", "nolog",
"fatal",
"error",
"warn",
"state",
"info",
"debug",
"debug1",
"debug2",
"debug3",
"debug4",
"trace", "trace",
"debug4",
"debug3",
"debug2",
"debug1",
"debug",
"info",
"state",
"warn",
"error",
"fatal",
``` ```
Logger will log the chosen severity and all above it (except "nolog", which deactivates logging for that sink completely). Fatal severity is always logged. Logger will log the chosen severity and all above it (except "nolog", which deactivates logging for that sink completely). Fatal severity is always logged.
## 3.1 Compile-time severity switch
The minimum severity level can be configured at compile time via definition of `FAIR_MIN_SEVERITY`:
```
cmake -DFAIR_MIN_SEVERITY=warn ..
```
The above would only log severities equal to or above `warn`.
When `FAIR_MIN_SEVERITY` is not provided all severities are enabled.
## 4. Verbosity ## 4. Verbosity
The log verbosity is controlled via: The log verbosity is controlled via:
@@ -115,8 +126,8 @@ it is same for all sinks, and is one of the following values: `verylow`, `low`,
verylow: message verylow: message
low: [severity] message low: [severity] message
medium: [HH:MM:SS][severity] message medium: [HH:MM:SS][severity] message
high: [process name][HH:MM:SS][severity] message high: [process_name][HH:MM:SS][severity] message
veryhigh: [process name][HH:MM:SS:µS][severity][file:line:function] message veryhigh: [process_name][HH:MM:SS:µS][severity][file:line:function] message
user1: [severity] message user1: [severity] message
user2: [severity] message user2: [severity] message
user3: [severity] message user3: [severity] message
@@ -135,12 +146,12 @@ The `fair::Logger::VerbositySpec` object can e.g. be created like this:
```C++ ```C++
auto spec = fair::VerbositySpec::Make(VerbositySpec::Info::timestamp_s, auto spec = fair::VerbositySpec::Make(VerbositySpec::Info::timestamp_s,
VerbositySpec::Info::process_name); VerbositySpec::Info::process_name);
// results in [HH:MM:SS][process name] message // results in [HH:MM:SS][process_name] message
``` ```
| **Argument** | **Result** | | **Argument** | **Result** |
| --- | --- | | --- | --- |
| `fair::VerbositySpec::Info::process_name` | `[process name]` | | `fair::VerbositySpec::Info::process_name` | `[process_name]` |
| `fair::VerbositySpec::Info::timestamp_s` | `[HH:MM:SS]` | | `fair::VerbositySpec::Info::timestamp_s` | `[HH:MM:SS]` |
| `fair::VerbositySpec::Info::timestamp_us` | `[HH:MM:SS:µS]` | | `fair::VerbositySpec::Info::timestamp_us` | `[HH:MM:SS:µS]` |
| `fair::VerbositySpec::Info::severity` | `[severity]` | | `fair::VerbositySpec::Info::severity` | `[severity]` |
@@ -207,8 +218,20 @@ Here is an example adding a custom sink for all severities ("trace" and above).
If only output from custom sinks is desirable, console/file sinks must be deactivated by setting their severity to `"nolog"`. If only output from custom sinks is desirable, console/file sinks must be deactivated by setting their severity to `"nolog"`.
## Naming conflicts?
By default, `<fairlogger/Logger.h>` defines unprefixed macros: `LOG`, `LOGV`, `LOGF`, `LOGP`, `LOGN`, `LOGD`, `LOG_IF`.
Define an option `FAIR_NO_LOG*` to prevent the above unprefixed macros to be defined, e.g.
```C++
#define FAIR_NO_LOG
#define FAIR_NO_LOGF
#include <fairlogger/Logger.h>
```
## License ## License
GNU Lesser General Public Licence (LGPL) version 3, see [LICENSE](LICENSE). GNU Lesser General Public Licence (LGPL) version 3, see [LICENSE](LICENSE).
Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH Copyright (C) 2017-2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH

View File

@@ -15,8 +15,8 @@ set(@PROJECT_NAME@_GIT_DATE @PROJECT_GIT_DATE@)
set_and_check(@PROJECT_NAME@_PREFIX @PACKAGE_CMAKE_INSTALL_PREFIX@) set_and_check(@PROJECT_NAME@_PREFIX @PACKAGE_CMAKE_INSTALL_PREFIX@)
set(@PROJECT_NAME@_BINDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT_INSTALL_BINDIR@) set(@PROJECT_NAME@_BINDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT_INSTALL_BINDIR@)
set(@PROJECT_NAME@_INCDIR @FAIRLOGGER_INSTALL_INCLUDE_DIRS@) set(@PROJECT_NAME@_INCDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@FAIRLOGGER_INSTALL_INCLUDE_DIRS@)
set(@PROJECT_NAME@_INCDIRS @FAIRLOGGER_INSTALL_INCLUDE_DIRS@) set(@PROJECT_NAME@_INCDIRS @PACKAGE_CMAKE_INSTALL_PREFIX@/@FAIRLOGGER_INSTALL_INCLUDE_DIRS@)
set_and_check(@PROJECT_NAME@_LIBDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT_INSTALL_LIBDIR@) set_and_check(@PROJECT_NAME@_LIBDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT_INSTALL_LIBDIR@)
set(@PROJECT_NAME@_CXX_STANDARD_REQUIRED @CMAKE_CXX_STANDARD_REQUIRED@) set(@PROJECT_NAME@_CXX_STANDARD_REQUIRED @CMAKE_CXX_STANDARD_REQUIRED@)

View File

@@ -7,7 +7,11 @@
********************************************************************************/ ********************************************************************************/
#include "Logger.h" #include "Logger.h"
#if FMT_VERSION < 60000
#include <fmt/time.h> #include <fmt/time.h>
#else
#include <fmt/chrono.h>
#endif
#include <cstdio> // printf #include <cstdio> // printf
#include <iostream> #include <iostream>
@@ -19,31 +23,12 @@ namespace fair
using VSpec = VerbositySpec; using VSpec = VerbositySpec;
string 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::error: return "\033[01;31mERROR\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::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;
case Severity::debug3: return "\033[01;34mDEBUG3\033[0m"; break;
case Severity::debug4: return "\033[01;34mDEBUG4\033[0m"; break;
case Severity::trace: return "\033[01;36mTRACE\033[0m"; break;
default: return "UNKNOWN"; break;
}
}
bool Logger::fColored = false; bool Logger::fColored = false;
fstream Logger::fFileStream; fstream Logger::fFileStream;
Verbosity Logger::fVerbosity = Verbosity::low; Verbosity Logger::fVerbosity = Verbosity::low;
Severity Logger::fConsoleSeverity = Severity::info; Severity Logger::fConsoleSeverity = Severity::FAIR_MIN_SEVERITY > Severity::info ? Severity::FAIR_MIN_SEVERITY : Severity::info;
Severity Logger::fMinSeverity = Severity::FAIR_MIN_SEVERITY > Severity::info ? Severity::FAIR_MIN_SEVERITY : Severity::info;
Severity Logger::fFileSeverity = Severity::nolog; Severity Logger::fFileSeverity = Severity::nolog;
Severity Logger::fMinSeverity = Severity::info;
function<void()> Logger::fFatalCallback; function<void()> Logger::fFatalCallback;
unordered_map<string, pair<Severity, function<void(const string& content, const LogMetaData& metadata)>>> Logger::fCustomSinks; unordered_map<string, pair<Severity, function<void(const string& content, const LogMetaData& metadata)>>> Logger::fCustomSinks;
mutex Logger::fMtx; mutex Logger::fMtx;
@@ -60,65 +45,65 @@ const string Logger::fProcessName = "?";
const unordered_map<string, Verbosity> Logger::fVerbosityMap = const unordered_map<string, Verbosity> Logger::fVerbosityMap =
{ {
{ "veryhigh", Verbosity::veryhigh }, { "veryhigh", Verbosity::veryhigh },
{ "high", Verbosity::high }, { "high", Verbosity::high },
{ "medium", Verbosity::medium }, { "medium", Verbosity::medium },
{ "low", Verbosity::low }, { "low", Verbosity::low },
{ "verylow", Verbosity::verylow }, { "verylow", Verbosity::verylow },
{ "VERYHIGH", Verbosity::veryhigh }, { "VERYHIGH", Verbosity::veryhigh },
{ "HIGH", Verbosity::high }, { "HIGH", Verbosity::high },
{ "MEDIUM", Verbosity::medium }, { "MEDIUM", Verbosity::medium },
{ "LOW", Verbosity::low }, { "LOW", Verbosity::low },
{ "VERYLOW", Verbosity::verylow }, { "VERYLOW", Verbosity::verylow },
{ "user1", Verbosity::user1 }, { "user1", Verbosity::user1 },
{ "user2", Verbosity::user2 }, { "user2", Verbosity::user2 },
{ "user3", Verbosity::user3 }, { "user3", Verbosity::user3 },
{ "user4", Verbosity::user4 } { "user4", Verbosity::user4 }
}; };
const unordered_map<string, Severity> Logger::fSeverityMap = const unordered_map<string, Severity> Logger::fSeverityMap =
{ {
{ "nolog", Severity::nolog }, { "nolog", Severity::nolog },
{ "NOLOG", Severity::nolog }, { "NOLOG", Severity::nolog },
{ "error", Severity::error }, { "error", Severity::error },
{ "ERROR", Severity::error }, { "ERROR", Severity::error },
{ "warn", Severity::warn }, { "warn", Severity::warn },
{ "WARN", Severity::warn }, { "WARN", Severity::warn },
{ "warning", Severity::warn }, { "warning", Severity::warn },
{ "WARNING", Severity::warn }, { "WARNING", Severity::warn },
{ "state", Severity::state }, { "state", Severity::state },
{ "STATE", Severity::state }, { "STATE", Severity::state },
{ "info", Severity::info }, { "info", Severity::info },
{ "INFO", Severity::info }, { "INFO", Severity::info },
{ "debug", Severity::debug }, { "debug", Severity::debug },
{ "DEBUG", Severity::debug }, { "DEBUG", Severity::debug },
{ "debug1", Severity::debug1 }, { "debug1", Severity::debug1 },
{ "DEBUG1", Severity::debug1 }, { "DEBUG1", Severity::debug1 },
{ "debug2", Severity::debug2 }, { "debug2", Severity::debug2 },
{ "DEBUG2", Severity::debug2 }, { "DEBUG2", Severity::debug2 },
{ "debug3", Severity::debug3 }, { "debug3", Severity::debug3 },
{ "DEBUG3", Severity::debug3 }, { "DEBUG3", Severity::debug3 },
{ "debug4", Severity::debug4 }, { "debug4", Severity::debug4 },
{ "DEBUG4", Severity::debug4 }, { "DEBUG4", Severity::debug4 },
{ "trace", Severity::trace }, { "trace", Severity::trace },
{ "TRACE", Severity::trace } { "TRACE", Severity::trace }
}; };
const array<string, 12> Logger::fSeverityNames = const array<string, 12> Logger::fSeverityNames =
{ {
{ {
"NOLOG", "NOLOG",
"FATAL", "TRACE",
"ERROR",
"WARN",
"STATE",
"INFO",
"DEBUG",
"DEBUG1",
"DEBUG2",
"DEBUG3",
"DEBUG4", "DEBUG4",
"TRACE" "DEBUG3",
"DEBUG2",
"DEBUG1",
"DEBUG",
"INFO",
"STATE",
"WARN",
"ERROR",
"FATAL"
} }
}; };
@@ -290,8 +275,31 @@ void Logger::LogEmptyLine()
// this call just to prevent any output to be added to the logger object // this call just to prevent any output to be added to the logger object
} }
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::error: return "\033[01;31mERROR\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::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;
case Severity::debug3: return "\033[01;34mDEBUG3\033[0m"; break;
case Severity::debug4: return "\033[01;34mDEBUG4\033[0m"; break;
case Severity::trace: return "\033[01;36mTRACE\033[0m"; break;
default: return "UNKNOWN"; break;
}
}
void Logger::SetConsoleSeverity(const Severity severity) void Logger::SetConsoleSeverity(const Severity severity)
{ {
if (severity < Severity::FAIR_MIN_SEVERITY && severity != Severity::nolog) {
cout << "Requested severity is higher than the enabled compile-time FAIR_MIN_SEVERITY (" << Severity::FAIR_MIN_SEVERITY << "), ignoring" << endl;
return;
}
fConsoleSeverity = severity; fConsoleSeverity = severity;
UpdateMinSeverity(); UpdateMinSeverity();
} }
@@ -313,6 +321,10 @@ Severity Logger::GetConsoleSeverity()
void Logger::SetFileSeverity(const Severity severity) void Logger::SetFileSeverity(const Severity severity)
{ {
if (severity < Severity::FAIR_MIN_SEVERITY && severity != Severity::nolog) {
cout << "Requested severity is higher than the enabled compile-time FAIR_MIN_SEVERITY (" << Severity::FAIR_MIN_SEVERITY << "), ignoring" << endl;
return;
}
fFileSeverity = severity; fFileSeverity = severity;
UpdateMinSeverity(); UpdateMinSeverity();
} }
@@ -329,8 +341,17 @@ void Logger::SetFileSeverity(const string& severityStr)
void Logger::SetCustomSeverity(const string& key, const Severity severity) void Logger::SetCustomSeverity(const string& key, const Severity severity)
{ {
fCustomSinks.at(key).first = severity; // TODO: range checks try {
UpdateMinSeverity(); if (severity < Severity::FAIR_MIN_SEVERITY && severity != Severity::nolog) {
cout << "Requested severity is higher than the enabled compile-time FAIR_MIN_SEVERITY (" << Severity::FAIR_MIN_SEVERITY << "), ignoring" << endl;
return;
}
fCustomSinks.at(key).first = severity;
UpdateMinSeverity();
} catch (const out_of_range& oor) {
LOG(error) << "No custom sink with id '" << key << "' found";
throw;
}
} }
void Logger::SetCustomSeverity(const string& key, const string& severityStr) void Logger::SetCustomSeverity(const string& key, const string& severityStr)
@@ -343,11 +364,21 @@ void Logger::SetCustomSeverity(const string& key, const string& severityStr)
} }
} }
Severity Logger::GetCustomSeverity(const std::string& key)
{
try {
return fCustomSinks.at(key).first;
} catch (const out_of_range& oor) {
LOG(error) << "No custom sink with id '" << key << "' found";
throw;
}
}
void Logger::CycleConsoleSeverityUp() void Logger::CycleConsoleSeverityUp()
{ {
int current = static_cast<int>(fConsoleSeverity); int current = static_cast<int>(fConsoleSeverity);
if (current == static_cast<int>(fSeverityNames.size()) - 1) { if (current == static_cast<int>(fSeverityNames.size()) - 1) {
SetConsoleSeverity(static_cast<Severity>(0)); SetConsoleSeverity(Severity::FAIR_MIN_SEVERITY);
} else { } else {
SetConsoleSeverity(static_cast<Severity>(current + 1)); SetConsoleSeverity(static_cast<Severity>(current + 1));
} }
@@ -355,7 +386,7 @@ void Logger::CycleConsoleSeverityUp()
stringstream ss; stringstream ss;
for (int i = 0; i < static_cast<int>(fSeverityNames.size()); ++i) { for (int i = 0; i < static_cast<int>(fSeverityNames.size()); ++i) {
ss << (i == newCurrent ? ">" : " ") << fSeverityNames.at(i) << (i == newCurrent ? "<" : " "); ss << (i == newCurrent ? "<" : " ") << fSeverityNames.at(i) << (i == newCurrent ? ">" : " ");
} }
ss << "\n\n"; ss << "\n\n";
@@ -365,7 +396,7 @@ void Logger::CycleConsoleSeverityUp()
void Logger::CycleConsoleSeverityDown() void Logger::CycleConsoleSeverityDown()
{ {
int current = static_cast<int>(fConsoleSeverity); int current = static_cast<int>(fConsoleSeverity);
if (current == 0) { if (current == static_cast<int>(Severity::FAIR_MIN_SEVERITY)) {
SetConsoleSeverity(static_cast<Severity>(fSeverityNames.size() - 1)); SetConsoleSeverity(static_cast<Severity>(fSeverityNames.size() - 1));
} else { } else {
SetConsoleSeverity(static_cast<Severity>(current - 1)); SetConsoleSeverity(static_cast<Severity>(current - 1));
@@ -374,7 +405,7 @@ void Logger::CycleConsoleSeverityDown()
stringstream ss; stringstream ss;
for (int i = 0; i < static_cast<int>(fSeverityNames.size()); ++i) { for (int i = 0; i < static_cast<int>(fSeverityNames.size()); ++i) {
ss << (i == newCurrent ? ">" : " ") << fSeverityNames.at(i) << (i == newCurrent ? "<" : " "); ss << (i == newCurrent ? "<" : " ") << fSeverityNames.at(i) << (i == newCurrent ? ">" : " ");
} }
ss << "\n\n"; ss << "\n\n";
@@ -393,7 +424,7 @@ void Logger::CycleVerbosityUp()
stringstream ss; stringstream ss;
for (int i = 0; i < static_cast<int>(fVerbosityNames.size()); ++i) { for (int i = 0; i < static_cast<int>(fVerbosityNames.size()); ++i) {
ss << (i == newCurrent ? ">" : " ") << fVerbosityNames.at(i) << (i == newCurrent ? "<" : " "); ss << (i == newCurrent ? "<" : " ") << fVerbosityNames.at(i) << (i == newCurrent ? ">" : " ");
} }
ss << "\n\n"; ss << "\n\n";
@@ -412,7 +443,7 @@ void Logger::CycleVerbosityDown()
stringstream ss; stringstream ss;
for (int i = 0; i < static_cast<int>(fVerbosityNames.size()); ++i) { for (int i = 0; i < static_cast<int>(fVerbosityNames.size()); ++i) {
ss << (i == newCurrent ? ">" : " ") << fVerbosityNames.at(i) << (i == newCurrent ? "<" : " "); ss << (i == newCurrent ? "<" : " ") << fVerbosityNames.at(i) << (i == newCurrent ? ">" : " ");
} }
ss << "\n\n"; ss << "\n\n";
@@ -421,27 +452,21 @@ void Logger::CycleVerbosityDown()
void Logger::UpdateMinSeverity() void Logger::UpdateMinSeverity()
{ {
fMinSeverity = (fConsoleSeverity <= fFileSeverity) ? fFileSeverity : fConsoleSeverity; if (fFileSeverity == Severity::nolog) {
fMinSeverity = fConsoleSeverity;
} else {
fMinSeverity = std::max(fConsoleSeverity, fFileSeverity);
}
for (auto& it : fCustomSinks) { for (auto& it : fCustomSinks) {
if (fMinSeverity <= it.second.first) { if (fMinSeverity == Severity::nolog) {
fMinSeverity = it.second.first; fMinSeverity = std::max(fMinSeverity, it.second.first);
} else if (it.second.first != Severity::nolog) {
fMinSeverity = std::min(fMinSeverity, it.second.first);
} }
} }
} }
bool Logger::Logging(Severity severity)
{
if (Severity::fatal == severity) {
return true;
}
if (severity <= fMinSeverity && severity > Severity::nolog) {
return true;
} else {
return false;
}
}
bool Logger::Logging(const string& severityStr) bool Logger::Logging(const string& severityStr)
{ {
if (fSeverityMap.count(severityStr)) { if (fSeverityMap.count(severityStr)) {
@@ -491,7 +516,7 @@ void Logger::SetConsoleColor(const bool colored)
fColored = colored; fColored = colored;
} }
void Logger::InitFileSink(const Severity severity, const string& filename, bool customizeName) string Logger::InitFileSink(const Severity severity, const string& filename, bool customizeName)
{ {
lock_guard<mutex> lock(fMtx); lock_guard<mutex> lock(fMtx);
if (fFileStream.is_open()) { if (fFileStream.is_open()) {
@@ -516,21 +541,27 @@ void Logger::InitFileSink(const Severity severity, const string& filename, bool
fFileStream.open(fullName, fstream::out | fstream::app); fFileStream.open(fullName, fstream::out | fstream::app);
if (fFileStream.is_open()) { if (fFileStream.is_open()) {
fFileSeverity = severity; if (severity < Severity::FAIR_MIN_SEVERITY && severity != Severity::nolog) {
cout << "Requested file sink severity is higher than the enabled compile-time FAIR_MIN_SEVERITY (" << Severity::FAIR_MIN_SEVERITY << "), setting to " << Severity::FAIR_MIN_SEVERITY << endl;
fFileSeverity = Severity::FAIR_MIN_SEVERITY;
} else {
fFileSeverity = severity;
}
UpdateMinSeverity(); UpdateMinSeverity();
} else { } else {
cout << "Error opening file: " << fullName; cout << "Error opening file: " << fullName;
} }
return fullName;
} }
void Logger::InitFileSink(const string& severityStr, const string& filename, bool customizeName) string Logger::InitFileSink(const string& severityStr, const string& filename, bool customizeName)
{ {
if (fSeverityMap.count(severityStr)) { if (fSeverityMap.count(severityStr)) {
InitFileSink(fSeverityMap.at(severityStr), filename, customizeName); return InitFileSink(fSeverityMap.at(severityStr), filename, customizeName);
} else { } else {
LOG(error) << "Unknown severity setting: '" << severityStr << "', setting to default 'info'."; LOG(error) << "Unknown severity setting: '" << severityStr << "', setting to default 'info'.";
InitFileSink(Severity::info, filename); return InitFileSink(Severity::info, filename);
} }
} }
@@ -539,27 +570,29 @@ void Logger::RemoveFileSink()
lock_guard<mutex> lock(fMtx); lock_guard<mutex> lock(fMtx);
if (fFileStream.is_open()) { if (fFileStream.is_open()) {
fFileStream.close(); fFileStream.close();
fFileSeverity = Severity::nolog;
UpdateMinSeverity();
} }
} }
bool Logger::LoggingToConsole() const bool Logger::LoggingToConsole() const
{ {
return (fInfos.severity <= fConsoleSeverity && return (fInfos.severity >= fConsoleSeverity &&
fInfos.severity > Severity::nolog) || fConsoleSeverity > Severity::nolog) ||
fInfos.severity == Severity::fatal; fInfos.severity == Severity::fatal;
} }
bool Logger::LoggingToFile() const bool Logger::LoggingToFile() const
{ {
return (fInfos.severity <= fFileSeverity && return (fInfos.severity >= fFileSeverity &&
fInfos.severity > Severity::nolog) || fFileSeverity > Severity::nolog) ||
fInfos.severity == Severity::fatal; fInfos.severity == Severity::fatal;
} }
bool Logger::LoggingCustom(const Severity severity) const bool Logger::LoggingCustom(const Severity severity) const
{ {
return (fInfos.severity <= severity && return (fInfos.severity >= severity &&
fInfos.severity > Severity::nolog) || severity > Severity::nolog) ||
fInfos.severity == Severity::fatal; fInfos.severity == Severity::fatal;
} }
@@ -572,10 +605,16 @@ void Logger::AddCustomSink(const string& key, Severity severity, function<void(c
{ {
lock_guard<mutex> lock(fMtx); lock_guard<mutex> lock(fMtx);
if (fCustomSinks.count(key) == 0) { if (fCustomSinks.count(key) == 0) {
fCustomSinks.insert(make_pair(key, make_pair(severity, func))); if (severity < Severity::FAIR_MIN_SEVERITY && severity != Severity::nolog) {
cout << "Requested custom sink severity is higher than the enabled compile-time FAIR_MIN_SEVERITY (" << Severity::FAIR_MIN_SEVERITY << "), setting to " << Severity::FAIR_MIN_SEVERITY << endl;
fCustomSinks.insert(make_pair(key, make_pair(Severity::FAIR_MIN_SEVERITY, func)));
} else {
fCustomSinks.insert(make_pair(key, make_pair(severity, func)));
}
UpdateMinSeverity(); UpdateMinSeverity();
} else { } else {
cout << "Logger::AddCustomSink: sink '" << key << "' already exists, will not add again. Remove first with Logger::RemoveCustomSink(const string& key)" << endl; cout << "Logger::AddCustomSink: sink '" << key << "' already exists, will not add again. Remove first with Logger::RemoveCustomSink(const string& key)" << endl;
throw runtime_error("Adding a sink with a key that already exists. Remove first.");
} }
} }
@@ -596,6 +635,7 @@ void Logger::RemoveCustomSink(const string& key)
UpdateMinSeverity(); UpdateMinSeverity();
} else { } else {
cout << "Logger::RemoveCustomSink: sink '" << key << "' doesn't exists, will not remove." << endl; cout << "Logger::RemoveCustomSink: sink '" << key << "' doesn't exists, will not remove." << endl;
throw runtime_error("Trying to remove a sink with a key that does not exist.");
} }
} }

View File

@@ -13,6 +13,10 @@
#warning "The symbol 'DEBUG' is used in FairRoot Logger. undefining..." #warning "The symbol 'DEBUG' is used in FairRoot Logger. undefining..."
#endif #endif
#ifndef FAIR_MIN_SEVERITY
#define FAIR_MIN_SEVERITY nolog
#endif
#ifdef FAIRLOGGER_USE_BOOST_PRETTY_FUNCTION #ifdef FAIRLOGGER_USE_BOOST_PRETTY_FUNCTION
#include <boost/current_function.hpp> #include <boost/current_function.hpp>
#endif #endif
@@ -35,9 +39,10 @@
#include <mutex> #include <mutex>
#include <ostream> #include <ostream>
#include <sstream> #include <sstream>
#include <stdexcept>
#include <string> #include <string>
#include <time.h> // time_t #include <time.h> // time_t
#include <type_traits> #include <type_traits> // is_same
#include <unordered_map> #include <unordered_map>
#include <utility> // pair #include <utility> // pair
@@ -46,59 +51,59 @@ namespace fair
enum class Severity : int enum class Severity : int
{ {
nolog, nolog = 0,
fatal, trace = 1,
error, debug4 = 2,
warn, debug3 = 3,
state, debug2 = 4,
info, debug1 = 5,
debug, debug = 6,
debug1, info = 7,
debug2, state = 8,
debug3, warn = 9,
debug4, error = 10,
trace, fatal = 11,
// backwards-compatibility: // backwards-compatibility:
NOLOG = nolog, NOLOG = nolog,
FATAL = fatal, TRACE = trace,
ERROR = error,
WARN = warn,
warning = warn,
WARNING = warn,
STATE = state,
INFO = info,
DEBUG = debug,
DEBUG1 = debug1,
DEBUG2 = debug2,
DEBUG3 = debug3,
DEBUG4 = debug4, DEBUG4 = debug4,
TRACE = trace DEBUG3 = debug3,
DEBUG2 = debug2,
DEBUG1 = debug1,
DEBUG = debug,
INFO = info,
STATE = state,
WARNING = warn,
warning = warn,
WARN = warn,
ERROR = error,
FATAL = fatal
}; };
// verbosity levels: // verbosity levels:
// verylow: message // verylow: message
// low: [severity] message // low: [severity] message
// medium: [HH:MM:SS][severity] message // medium: [HH:MM:SS][severity] message
// high: [process name][HH:MM:SS][severity] message // high: [process_name][HH:MM:SS][severity] message
// veryhigh: [process name][HH:MM:SS:µS][severity][file:line:function] message // veryhigh: [process_name][HH:MM:SS:µS][severity][file:line:function] message
enum class Verbosity : int enum class Verbosity : int
{ {
verylow, verylow = 0,
low, low,
medium, medium,
high, high,
veryhigh, veryhigh,
// backwards-compatibility:
VERYLOW = verylow,
LOW = low,
MEDIUM = medium,
HIGH = high,
VERYHIGH = veryhigh,
// extra slots for user-defined verbosities: // extra slots for user-defined verbosities:
user1, user1,
user2, user2,
user3, user3,
user4, user4,
// backwards-compatibility:
VERYLOW = verylow,
LOW = low,
MEDIUM = medium,
HIGH = high,
VERYHIGH = veryhigh
}; };
struct VerbositySpec struct VerbositySpec
@@ -106,7 +111,7 @@ struct VerbositySpec
enum class Info : int enum class Info : int
{ {
__empty__ = 0, // used to initialize order array __empty__ = 0, // used to initialize order array
process_name, // [process name] process_name, // [process_name]
timestamp_s, // [HH:MM:SS] timestamp_s, // [HH:MM:SS]
timestamp_us, // [HH:MM:SS:µS] timestamp_us, // [HH:MM:SS:µS]
severity, // [severity] severity, // [severity]
@@ -235,6 +240,7 @@ class Logger
static std::string startColor(Color color) { return fmt::format("\033[01;{}m", static_cast<int>(color)); } 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 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, const std::string& 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); static void SetConsoleSeverity(const Severity severity);
static void SetConsoleSeverity(const std::string& severityStr); static void SetConsoleSeverity(const std::string& severityStr);
@@ -242,16 +248,23 @@ class Logger
static void SetFileSeverity(const Severity severity); static void SetFileSeverity(const Severity severity);
static void SetFileSeverity(const std::string& severityStr); static void SetFileSeverity(const std::string& severityStr);
static Severity GetFileSeverity() { return fFileSeverity; }
static void SetCustomSeverity(const std::string& key, const Severity severity); static void SetCustomSeverity(const std::string& key, const Severity severity);
static void SetCustomSeverity(const std::string& key, const std::string& severityStr); static void SetCustomSeverity(const std::string& key, const std::string& severityStr);
static Severity GetCustomSeverity(const std::string& key);
static void CycleConsoleSeverityUp(); static void CycleConsoleSeverityUp();
static void CycleConsoleSeverityDown(); static void CycleConsoleSeverityDown();
static void CycleVerbosityUp(); static void CycleVerbosityUp();
static void CycleVerbosityDown(); static void CycleVerbosityDown();
static bool Logging(const Severity severity); static bool Logging(const Severity severity)
{
return (severity >= fMinSeverity &&
fMinSeverity > Severity::nolog) ||
severity == Severity::fatal;
}
static bool Logging(const std::string& severityStr); static bool Logging(const std::string& severityStr);
static void SetVerbosity(const Verbosity verbosity); static void SetVerbosity(const Verbosity verbosity);
@@ -262,8 +275,8 @@ class Logger
static void SetConsoleColor(const bool colored = true); static void SetConsoleColor(const bool colored = true);
static void InitFileSink(const Severity severity, const std::string& filename, bool customizeName = true); static std::string InitFileSink(const Severity severity, const std::string& filename, bool customizeName = true);
static void InitFileSink(const std::string& severityStr, const std::string& filename, bool customizeName = true); static std::string InitFileSink(const std::string& severityStr, const std::string& filename, bool customizeName = true);
static void RemoveFileSink(); static void RemoveFileSink();
@@ -313,6 +326,11 @@ class Logger
static bool fIsDestructed; static bool fIsDestructed;
static struct DestructionHelper { ~DestructionHelper() { Logger::fIsDestructed = true; }} fDestructionHelper; static struct DestructionHelper { ~DestructionHelper() { Logger::fIsDestructed = true; }} fDestructionHelper;
static bool constexpr SuppressSeverity(Severity sev)
{
return sev < Severity::FAIR_MIN_SEVERITY;
}
private: private:
LogMetaData fInfos; LogMetaData fInfos;
@@ -345,6 +363,9 @@ class Logger
static std::map<Verbosity, VerbositySpec> fVerbosities; static std::map<Verbosity, VerbositySpec> fVerbosities;
}; };
inline std::ostream& operator<<(std::ostream& os, const Severity& s) { return os << Logger::SeverityName(s); }
inline std::ostream& operator<<(std::ostream& os, const Verbosity& v) { return os << Logger::VerbosityName(v); }
} // namespace fair } // namespace fair
#define IMP_CONVERTTOSTRING(s) # s #define IMP_CONVERTTOSTRING(s) # s
@@ -356,32 +377,73 @@ class Logger
#define MSG_ORIGIN __FILE__, CONVERTTOSTRING(__LINE__), static_cast<const char*>(__FUNCTION__) #define MSG_ORIGIN __FILE__, CONVERTTOSTRING(__LINE__), static_cast<const char*>(__FUNCTION__)
#endif #endif
// allow user of this header file to prevent definition of the LOG macro, by defining FAIR_NO_LOG before including this header
#ifndef FAIR_NO_LOG
#undef LOG
#define LOG FAIR_LOG
#endif
// allow user of this header file to prevent definition of the LOGV macro, by defining FAIR_NO_LOGV before including this header
#ifndef FAIR_NO_LOGV
#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 LOGN macro, by defining FAIR_NO_LOGN before including this header
#ifndef FAIR_NO_LOGN
#undef LOGN
#define LOGN FAIR_LOGN
#endif
// allow user of this header file to prevent definition of the LOGD macro, by defining FAIR_NO_LOGD before including this header
#ifndef FAIR_NO_LOGD
#undef LOGD
#define LOGD FAIR_LOGD
#endif
// allow user of this header file to prevent definition of the LOG_IF macro, by defining FAIR_NO_LOG_IF before including this header
#ifndef FAIR_NO_LOG_IF
#undef LOG_IF
#define LOG_IF FAIR_LOG_IF
#endif
// Log line if the provided severity is below or equals the configured one // Log line if the provided severity is below or equals the configured one
#define LOG(severity) \ #define FAIR_LOG(severity) \
for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(fair::Severity::severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \ for (bool fairLOggerunLikelyvariable3 = false; !fair::Logger::SuppressSeverity(fair::Severity::severity) && !fairLOggerunLikelyvariable3; fairLOggerunLikelyvariable3 = true) \
fair::Logger(fair::Severity::severity, MSG_ORIGIN) for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(fair::Severity::severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \
fair::Logger(fair::Severity::severity, MSG_ORIGIN)
// Log line with the given verbosity if the provided severity is below or equals the configured one // Log line with the given verbosity if the provided severity is below or equals the configured one
#define LOGV(severity, verbosity) \ #define FAIR_LOGV(severity, verbosity) \
for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(fair::Severity::severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \ for (bool fairLOggerunLikelyvariable3 = false; !fair::Logger::SuppressSeverity(fair::Severity::severity) && !fairLOggerunLikelyvariable3; fairLOggerunLikelyvariable3 = true) \
fair::Logger(fair::Severity::severity, fair::Verbosity::verbosity, MSG_ORIGIN) for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(fair::Severity::severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \
fair::Logger(fair::Severity::severity, fair::Verbosity::verbosity, MSG_ORIGIN)
// Log with fmt- or printf-like formatting // Log with fmt- or printf-like formatting
#define LOGF(severity, ...) LOG(severity) << fmt::format(__VA_ARGS__) #define FAIR_LOGP(severity, ...) LOG(severity) << fmt::format(__VA_ARGS__)
#define LOGP(severity, ...) LOG(severity) << fmt::sprintf(__VA_ARGS__) #define FAIR_LOGF(severity, ...) LOG(severity) << fmt::sprintf(__VA_ARGS__)
// Log an empty line // Log an empty line
#define LOGN(severity) \ #define FAIR_LOGN(severity) \
for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(fair::Severity::severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \ for (bool fairLOggerunLikelyvariable3 = false; !fair::Logger::SuppressSeverity(fair::Severity::severity) && !fairLOggerunLikelyvariable3; fairLOggerunLikelyvariable3 = true) \
fair::Logger(fair::Severity::severity, fair::Verbosity::verylow, MSG_ORIGIN).LogEmptyLine() for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(fair::Severity::severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \
fair::Logger(fair::Severity::severity, fair::Verbosity::verylow, MSG_ORIGIN).LogEmptyLine()
// Log with custom file, line, function // Log with custom file, line, function
#define LOGD(severity, file, line, f) \ #define FAIR_LOGD(severity, file, line, f) \
for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \ for (bool fairLOggerunLikelyvariable3 = false; !fair::Logger::SuppressSeverity(severity) && !fairLOggerunLikelyvariable3; fairLOggerunLikelyvariable3 = true) \
fair::Logger(severity, file, line, f) for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \
fair::Logger(severity, file, line, f)
#define LOG_IF(severity, condition) \ #define FAIR_LOG_IF(severity, condition) \
for (bool fairLOggerunLikelyvariable2 = false; condition && !fairLOggerunLikelyvariable2; fairLOggerunLikelyvariable2 = true) \ for (bool fairLOggerunLikelyvariable4 = false; !fair::Logger::SuppressSeverity(fair::Severity::severity) && !fairLOggerunLikelyvariable4; fairLOggerunLikelyvariable4 = true) \
LOG(severity) for (bool fairLOggerunLikelyvariable2 = false; condition && !fairLOggerunLikelyvariable2; fairLOggerunLikelyvariable2 = true) \
LOG(severity)
#endif // FAIR_LOGGER_H #endif // FAIR_LOGGER_H

100
test/Common.h Normal file
View File

@@ -0,0 +1,100 @@
/********************************************************************************
* Copyright (C) 2014-2020 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" *
********************************************************************************/
#ifndef FAIR_LOGGER_TEST_COMMON_H
#define FAIR_LOGGER_TEST_COMMON_H
#include <fstream>
#include <functional>
#include <iostream>
#include <regex>
#include <stdexcept>
#include <sstream>
#include <string>
#include <stdio.h> // fflush
#include <unistd.h> // dup, dup2, close
namespace fair
{
namespace logger
{
namespace test
{
template<typename ... T>
auto ToStr(T&&... t) -> std::string
{
std::stringstream ss;
(void)std::initializer_list<int>{(ss << t, 0)...};
return ss.str();
}
template<int S>
class StreamCapturer
{
public:
explicit StreamCapturer()
: mFd(S)
, mOriginalFd(dup(S)) // create a copy of the given file descriptor
{
char name[] = "/tmp/fairlogger_test_capture.XXXXXX";
const int capturedFd = mkstemp(name); // create a unique temporary file
if (capturedFd == -1) {
std::cout << "Could not create tmp file " << name << " for test; does the test have access to the /tmp directory?" << std::endl;
throw std::runtime_error("Could not create tmp file for test; does the test have access to the /tmp directory?");
}
mTmpFile = name;
fflush(nullptr); // flushes all open output streams
dup2(capturedFd, mFd);
close(capturedFd);
}
std::string GetCapture()
{
fflush(nullptr); // flushes all open output streams
std::ifstream t(mTmpFile);
std::stringstream buffer;
buffer << t.rdbuf();
return buffer.str();
}
~StreamCapturer()
{
dup2(mOriginalFd, mFd);
close(mOriginalFd);
remove(mTmpFile.c_str());
}
private:
const int mFd;
int mOriginalFd;
std::string mTmpFile;
};
void CheckOutput(std::string const& expected, std::function<void()> f)
{
std::string output;
{
StreamCapturer<1> c;
f();
output = c.GetCapture();
}
const std::regex e(expected);
if (!std::regex_match(output, e)) {
throw std::runtime_error(std::string("MISMATCH:\n##### expected (regex):\n" + expected + "\n##### found:\n" + output));
}
}
} // namespace test
} // namespace logger
} // namespace fair
#endif // FAIR_LOGGER_TEST_COMMON_H

81
test/cycle.cxx Normal file
View File

@@ -0,0 +1,81 @@
/********************************************************************************
* Copyright (C) 2014-2020 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 "Common.h"
#include <Logger.h>
#include <iostream>
using namespace std;
using namespace fair;
using namespace fair::logger::test;
int main()
{
try {
Logger::SetConsoleColor(false);
Logger::SetVerbosity(Verbosity::user4);
cout << "initial verbosity >" << Logger::GetVerbosity() << "<" << endl << endl;
array<Verbosity, 10> verbositiesUp{{ Verbosity::verylow, Verbosity::low, Verbosity::medium, Verbosity::high, Verbosity::veryhigh, Verbosity::user1, Verbosity::user2, Verbosity::user3, Verbosity::user4, Verbosity::verylow }};
for (unsigned int i = 0; i < verbositiesUp.size(); ++i) {
Logger::CycleVerbosityUp();
if (Logger::GetVerbosity() != verbositiesUp.at(i)) { throw runtime_error(ToStr("Expected verbosity to be ", verbositiesUp.at(i), ", but it is ", Logger::GetVerbosity())); }
}
array<Verbosity, 10> verbositiesDown{{ Verbosity::user4, Verbosity::user3, Verbosity::user2, Verbosity::user1, Verbosity::veryhigh, Verbosity::high, Verbosity::medium, Verbosity::low, Verbosity::verylow, Verbosity::user4 }};
for (unsigned int i = 0; i < verbositiesDown.size(); ++i) {
Logger::CycleVerbosityDown();
if (Logger::GetVerbosity() != verbositiesDown.at(i)) { throw runtime_error(ToStr("Expected verbosity to be ", verbositiesDown.at(i), ", but it is ", Logger::GetVerbosity())); }
}
Logger::SetConsoleSeverity(Severity::fatal);
cout << "initial severity >" << Logger::GetConsoleSeverity() << "<" << endl << endl;
array<Severity, 12> severitiesUp{{ Severity::nolog, Severity::trace, Severity::debug4, Severity::debug3, Severity::debug2, Severity::debug1, Severity::debug, Severity::info, Severity::state, Severity::warn, Severity::error, Severity::fatal }};
#ifdef FAIR_MIN_SEVERITY
for (unsigned int i = static_cast<int>(Severity::FAIR_MIN_SEVERITY); i < severitiesUp.size(); ++i) {
#else
for (unsigned int i = 0; i < severitiesUp.size(); ++i) {
#endif
Logger::CycleConsoleSeverityUp();
if (Logger::GetConsoleSeverity() != severitiesUp.at(i)) { throw runtime_error(ToStr("Expected severity to be ", severitiesUp.at(i), ", but it is ", Logger::GetConsoleSeverity())); }
}
Logger::CycleConsoleSeverityUp();
#ifdef FAIR_MIN_SEVERITY
if (Logger::GetConsoleSeverity() != Severity::FAIR_MIN_SEVERITY) { throw runtime_error(ToStr("Expected severity to be ", Severity::nolog, ", but it is ", Logger::GetConsoleSeverity())); }
#else
if (Logger::GetConsoleSeverity() != Severity::nolog) { throw runtime_error(ToStr("Expected severity to be ", Severity::nolog, ", but it is ", Logger::GetConsoleSeverity())); }
#endif
Logger::SetConsoleSeverity(Severity::fatal);
cout << "initial severity >" << Logger::GetConsoleSeverity() << "<" << endl << endl;
array<Severity, 12> severitiesDown{{ Severity::error, Severity::warn, Severity::state, Severity::info, 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
for (unsigned int i = 0; i < severitiesDown.size(); ++i) {
#endif
Logger::CycleConsoleSeverityDown();
if (Logger::GetConsoleSeverity() != severitiesDown.at(i)) { throw runtime_error(ToStr("Expected severity to be ", severitiesDown.at(i), ", but it is ", Logger::GetConsoleSeverity())); }
}
Logger::CycleConsoleSeverityDown();
#ifdef FAIR_MIN_SEVERITY
if (Logger::GetConsoleSeverity() != Severity::fatal) { throw runtime_error(ToStr("Expected severity to be ", Severity::fatal, ", but it is ", Logger::GetConsoleSeverity())); }
#else
if (Logger::GetConsoleSeverity() != Severity::error) { throw runtime_error(ToStr("Expected severity to be ", Severity::error, ", but it is ", Logger::GetConsoleSeverity())); }
#endif
} catch (runtime_error& rte) {
cout << rte.what() << endl;
return 1;
}
return 0;
}

58
test/logger.cxx Normal file
View File

@@ -0,0 +1,58 @@
/********************************************************************************
* Copyright (C) 2014-2020 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 <iostream>
using namespace std;
using namespace fair;
void printEverySeverity()
{
static int i = 1;
LOG(nolog) << "nolog message, counter: " << i++;
LOG(trace) << "trace message, counter: " << i++;
LOG(debug4) << "debug4 message, counter: " << i++;
LOG(debug3) << "debug3 message, counter: " << i++;
LOG(debug2) << "debug2 message, counter: " << i++;
LOG(debug1) << "debug1 message, counter: " << i++;
LOG(debug) << "debug message, counter: " << i++;
LOG(info) << "info message, counter: " << i++;
LOG(state) << "state message, counter: " << i++;
LOG(warn) << "warning message, counter: " << i++;
LOG(error) << "error message, counter: " << i++;
LOG(fatal) << "fatal message, counter: " << i++;
}
void printAllVerbositiesWithSeverity(Severity sev)
{
Logger::SetConsoleSeverity(sev);
for (uint32_t i = 0; i < Logger::fVerbosityNames.size(); ++i) {
cout << "##### testing severity '" << sev << "' with verbosity '" << Logger::fVerbosityNames.at(i) << "'" << endl;
Logger::SetVerbosity(static_cast<Verbosity>(i));
printEverySeverity();
}
}
int main()
{
Logger::SetConsoleColor(true);
Logger::SetVerbosity(Verbosity::veryhigh);
cout << "##### GetConsoleSeverity = " << Logger::SeverityName(Logger::GetConsoleSeverity()) << endl;
cout << "##### testing severities..." << endl;
for (uint32_t i = 0; i < Logger::fSeverityNames.size(); ++i) {
printAllVerbositiesWithSeverity(static_cast<Severity>(i));
}
return 0;
}

View File

@@ -1,208 +0,0 @@
/********************************************************************************
* Copyright (C) 2014-2019 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 <iostream>
#include <vector>
#include <thread>
using namespace std;
using namespace fair;
void printEverySeverity()
{
static int i = 1;
LOG(nolog) << "nolog message " << i++;
LOG(error) << "error message " << i++;
LOG(warn) << "warning message " << i++;
LOG(state) << "state message " << i++;
LOG(info) << "info message " << i++;
LOG(debug) << "debug message " << i++;
LOG(debug1) << "debug1 message " << i++;
LOG(debug2) << "debug2 message " << i++;
LOG(debug3) << "debug3 message " << i++;
LOG(debug4) << "debug4 message " << i++;
LOG(trace) << "trace message " << i++;
}
void printAllVerbositiesWithSeverity(Severity sev)
{
Logger::SetConsoleSeverity(sev);
cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'verylow' verbosity..." << endl;
Logger::SetVerbosity(Verbosity::verylow);
printEverySeverity();
cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'low' verbosity..." << endl;
Logger::SetVerbosity(Verbosity::low);
printEverySeverity();
cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'medium' verbosity..." << endl;
Logger::SetVerbosity(Verbosity::medium);
printEverySeverity();
cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'high' verbosity..." << endl;
Logger::SetVerbosity(Verbosity::high);
printEverySeverity();
cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'veryhigh' verbosity..." << endl;
Logger::SetVerbosity(Verbosity::veryhigh);
printEverySeverity();
cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'user1' verbosity..." << endl;
Logger::SetVerbosity(Verbosity::user1);
printEverySeverity();
cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'user2' verbosity..." << endl;
Logger::SetVerbosity(Verbosity::user2);
printEverySeverity();
cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'user3' verbosity..." << endl;
Logger::SetVerbosity(Verbosity::user3);
printEverySeverity();
cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'user4' verbosity..." << endl;
Logger::SetVerbosity(Verbosity::user4);
printEverySeverity();
}
void silentlyPrintAllVerbositiesWithSeverity(Severity sev)
{
Logger::SetConsoleSeverity(sev);
Logger::SetVerbosity(Verbosity::verylow);
printEverySeverity();
Logger::SetVerbosity(Verbosity::low);
printEverySeverity();
Logger::SetVerbosity(Verbosity::medium);
printEverySeverity();
Logger::SetVerbosity(Verbosity::high);
printEverySeverity();
Logger::SetVerbosity(Verbosity::veryhigh);
printEverySeverity();
Logger::SetVerbosity(Verbosity::user1);
printEverySeverity();
Logger::SetVerbosity(Verbosity::user2);
printEverySeverity();
Logger::SetVerbosity(Verbosity::user3);
printEverySeverity();
Logger::SetVerbosity(Verbosity::user4);
printEverySeverity();
}
int main()
{
Logger::SetConsoleColor(true);
auto spec = VerbositySpec::Make(VerbositySpec::Info::file_line_function,
VerbositySpec::Info::process_name,
VerbositySpec::Info::process_name);
cout << "Defining custom verbosity \"user2\"" << endl;
Logger::DefineVerbosity(Verbosity::user2, spec);
cout << "cout: testing severities..." << endl;
printAllVerbositiesWithSeverity(Severity::trace);
printAllVerbositiesWithSeverity(Severity::debug4);
printAllVerbositiesWithSeverity(Severity::debug3);
printAllVerbositiesWithSeverity(Severity::debug2);
printAllVerbositiesWithSeverity(Severity::debug1);
printAllVerbositiesWithSeverity(Severity::debug);
printAllVerbositiesWithSeverity(Severity::info);
printAllVerbositiesWithSeverity(Severity::state);
printAllVerbositiesWithSeverity(Severity::warn);
printAllVerbositiesWithSeverity(Severity::error);
printAllVerbositiesWithSeverity(Severity::nolog);
cout << endl;
cout << "cout: setting severity to 'info' and verbosity to 'medium'" << endl;
Logger::SetConsoleSeverity(Severity::info);
Logger::SetVerbosity(Verbosity::medium);
cout << "cout: is logging trace: " << fair::Logger::Logging(Severity::trace) << endl;
cout << "cout: is logging debug4: " << fair::Logger::Logging(Severity::debug) << endl;
cout << "cout: is logging debug3: " << fair::Logger::Logging(Severity::debug) << endl;
cout << "cout: is logging debug2: " << fair::Logger::Logging(Severity::debug) << endl;
cout << "cout: is logging debug1: " << fair::Logger::Logging(Severity::debug) << endl;
cout << "cout: is logging debug: " << fair::Logger::Logging(Severity::debug) << endl;
cout << "cout: is logging info: " << fair::Logger::Logging(Severity::info) << endl;
cout << "cout: is logging state: " << fair::Logger::Logging(Severity::state) << endl;
cout << "cout: is logging warn: " << fair::Logger::Logging(Severity::warn) << endl;
cout << "cout: is logging error: " << fair::Logger::Logging(Severity::error) << endl;
cout << "cout: is logging fatal: " << fair::Logger::Logging(Severity::fatal) << endl;
cout << "cout: is logging nolog: " << fair::Logger::Logging(Severity::nolog) << endl;
for (int i = 0; i < 1000000; ++i) {
silentlyPrintAllVerbositiesWithSeverity(Severity::nolog);
}
cout << endl;
cout << "cout: setting severity to 'trace' and verbosity to 'veryhigh'" << endl;
Logger::SetConsoleSeverity(Severity::trace);
Logger::SetVerbosity(Verbosity::veryhigh);
cout << endl;
cout << "cout: testing conditional logging..." << endl;
int x = 0;
LOG(info) << "x = " << x << " (initial)";
LOG_IF(info, (x == 0)) << "incrementing x to " << ++x;
LOG(info) << "x = " << x << " (after increment)";
LOG_IF(info, (x == 0)) << "this should not be printed and x not incremented: " << ++x;
LOG(info) << "x = " << x << " (after conditional increment)";
cout << endl;
cout << "cout: setting severity to 'nolog'" << endl;
Logger::SetConsoleSeverity(Severity::nolog);
cout << "cout: ----------------------------" << endl;
cout << "cout: open log file with severity 'error'" << endl;
Logger::InitFileSink(Severity::error, "test_log", true);
printEverySeverity();
cout << "cout: closing log file" << endl;
Logger::RemoveFileSink();
cout << "cout: setting severity to 'nolog'" << endl;
Logger::SetConsoleSeverity(Severity::nolog);
cout << "cout: ----------------------------" << endl;
cout << "cout: adding custom sink with error severity" << endl << endl;
Logger::AddCustomSink("CustomSink", "error", [](const string& content, const LogMetaData& metadata)
{
cout << "CustomSink: content: " << content << endl;
cout << "CustomSink: available metadata: " << endl;
cout << "CustomSink: \tstd::time_t timestamp: " << metadata.timestamp << endl;
cout << "CustomSink: \tstd::chrono::microseconds us: " << metadata.us.count() << endl;
cout << "CustomSink: \tstd::string process_name: " << metadata.process_name << endl;
cout << "CustomSink: \tstd::string file: " << metadata.file << endl;
cout << "CustomSink: \tstd::string line: " << metadata.line << endl;
cout << "CustomSink: \tstd::string func: " << metadata.func << endl;
cout << "CustomSink: \tstd::string severity_name: " << metadata.severity_name << endl;
cout << "CustomSink: \tfair::Severity severity: " << static_cast<int>(metadata.severity) << endl;
});
printEverySeverity();
cout << endl << "cout: removing custom sink with info severity" << endl;
Logger::AddCustomSink("CustomSink", Severity::error, [](const string& /*content*/, const LogMetaData& /*metadata*/){});
Logger::RemoveCustomSink("CustomSink");
Logger::RemoveCustomSink("bla");
cout << "cout: setting severity to 'trace'" << endl;
Logger::SetConsoleSeverity(Severity::trace);
LOGF(info, "Hello {} {}!", "world", ":-)");
LOGP(info, "Hello %s %s!", "world", ":-)");
cout << "cout: setting verbosity to 'high'" << endl;
Logger::SetVerbosity(Verbosity::high);
LOGV(info, verylow) << "I should be printed with very low verbosity";
cout << "cout: pushing 4 new lines with LOGN() in info verbosity" << endl;
LOGN(info);
LOGN(info);
LOGN(info);
LOGN(info);
return 0;
}

60
test/macros.cxx Normal file
View File

@@ -0,0 +1,60 @@
/********************************************************************************
* Copyright (C) 2014-2020 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 "Common.h"
#include <Logger.h>
#include <iostream>
using namespace std;
using namespace fair;
using namespace fair::logger::test;
int main()
{
try {
Logger::SetConsoleColor(false);
Logger::SetConsoleSeverity(Severity::fatal);
Logger::SetVerbosity(Verbosity::verylow);
int x = 0;
CheckOutput("^incrementing x to 1\n$", [&]() { LOG_IF(fatal, true) << "incrementing x to " << ++x; });
if (x != 1) {
throw runtime_error(ToStr("expected x to be 1, but it is: ", x));
}
CheckOutput("^$", [&]() { LOG_IF(fatal, false) << "incrementing x to " << ++x; });
if (x != 1) {
throw runtime_error(ToStr("expected x to be 1, but it is: ", x));
}
CheckOutput("^Hello world :-\\)!\n$", []() { LOGP(fatal, "Hello {} {}!", "world", ":-)"); });
CheckOutput("^Hello world :-\\)!\n$", []() { LOGF(fatal, "Hello %s %s!", "world", ":-)"); });
CheckOutput(ToStr(R"(^\[FATAL\])", " content\n$"), []() { LOGV(fatal, low) << "content"; });
CheckOutput("^\n\n\n\n$", []() {
LOGN(fatal);
LOGN(fatal);
LOGN(fatal);
LOGN(fatal);
});
Logger::SetVerbosity(Verbosity::veryhigh);
CheckOutput(ToStr(R"(^\[.*\]\[\d{2}:\d{2}:\d{2}\.\d{6}\]\[FATAL\]\[a:4:b\])", " c\n$"), []() {
LOGD(Severity::fatal, "a", "4", "b") << "c";
});
} catch (runtime_error& rte) {
cout << rte.what() << endl;
return 1;
}
return 0;
}

60
test/nolog.cxx Normal file
View File

@@ -0,0 +1,60 @@
/********************************************************************************
* Copyright (C) 2014-2020 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>
using namespace std;
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(error) << "error message, counter: ";
}
void silentlyPrintAllVerbositiesWithSeverity(Severity sev)
{
Logger::SetConsoleSeverity(sev);
Logger::SetVerbosity(Verbosity::verylow);
printEverySeverity();
Logger::SetVerbosity(Verbosity::low);
printEverySeverity();
Logger::SetVerbosity(Verbosity::medium);
printEverySeverity();
Logger::SetVerbosity(Verbosity::high);
printEverySeverity();
Logger::SetVerbosity(Verbosity::veryhigh);
printEverySeverity();
Logger::SetVerbosity(Verbosity::user1);
printEverySeverity();
Logger::SetVerbosity(Verbosity::user2);
printEverySeverity();
Logger::SetVerbosity(Verbosity::user3);
printEverySeverity();
Logger::SetVerbosity(Verbosity::user4);
printEverySeverity();
}
int main()
{
for (int i = 0; i < 1000000; ++i) {
silentlyPrintAllVerbositiesWithSeverity(Severity::nolog);
}
return 0;
}

98
test/severity.cxx Normal file
View File

@@ -0,0 +1,98 @@
/********************************************************************************
* Copyright (C) 2014-2020 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 "Common.h"
#include <Logger.h>
#include <cstdint>
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
using namespace fair;
using namespace fair::logger::test;
uint32_t printEverySeverity(uint32_t i)
{
LOG(nolog) << "nolog message, counter: " << i++;
LOG(trace) << "trace message, counter: " << i++;
LOG(debug4) << "debug4 message, counter: " << i++;
LOG(debug3) << "debug3 message, counter: " << i++;
LOG(debug2) << "debug2 message, counter: " << i++;
LOG(debug1) << "debug1 message, counter: " << i++;
LOG(debug) << "debug message, counter: " << i++;
LOG(info) << "info message, counter: " << i++;
LOG(state) << "state message, counter: " << i++;
LOG(warn) << "warning message, counter: " << i++;
LOG(error) << "error message, counter: " << i++;
LOG(fatal) << "fatal message, counter: " << i++;
return i;
}
void CheckSeverity(Severity severity)
{
Logger::SetConsoleSeverity(severity);
auto sev = Logger::GetConsoleSeverity();
cout << "##### testing severity '" << Logger::SeverityName(sev) << "' (" << static_cast<int>(sev) << "), Logging(): " << std::boolalpha << Logger::Logging(sev) << endl;
for (uint32_t i = 0; i < Logger::fSeverityNames.size(); ++i) {
if (sev == Severity::nolog) {
if (i == 11) {
if (!Logger::Logging(static_cast<Severity>(i))) {
throw runtime_error(ToStr("expecting to be logging ", Logger::fSeverityNames.at(i), " during ", sev, ", but it is not."));
}
} else {
if (Logger::Logging(static_cast<Severity>(i))) {
throw runtime_error(ToStr("expecting to NOT be logging ", Logger::fSeverityNames.at(i), " during ", sev, ", but it is."));
}
}
} else {
if (i >= static_cast<unsigned int>(sev)) {
if (!Logger::Logging(static_cast<Severity>(i))) {
throw runtime_error(ToStr("expecting to be logging ", Logger::fSeverityNames.at(i), " during ", sev, ", but it is not."));
}
} else {
if (Logger::Logging(static_cast<Severity>(i))) {
throw runtime_error(ToStr("expecting to NOT be logging ", Logger::fSeverityNames.at(i), " during ", sev, ", but it is."));
}
}
}
}
uint32_t i = 0;
i = printEverySeverity(i);
if (sev == Severity::nolog) {
if (i != 1) {
throw runtime_error(ToStr("expected: i==1, found: i==", i));
}
} else {
if (i != Logger::fSeverityNames.size() - static_cast<int>(sev)) {
throw runtime_error(ToStr("expected: i==", Logger::fSeverityNames.size() - static_cast<int>(sev) - 1, ", found: i==", i));
}
}
}
int main()
{
try {
Logger::SetConsoleColor(true);
cout << "##### testing " << Logger::fSeverityNames.size() << " severities..." << endl;
for (uint32_t i = 0; i < Logger::fSeverityNames.size(); ++i) {
CheckSeverity(static_cast<Severity>(i));
}
} catch (runtime_error& rte) {
cout << rte.what() << endl;
return 1;
}
return 0;
}

151
test/sinks.cxx Normal file
View File

@@ -0,0 +1,151 @@
/********************************************************************************
* Copyright (C) 2014-2020 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 "Common.h"
#include <Logger.h>
#include <fstream>
#include <iostream>
#include <random>
#include <sstream>
using namespace std;
using namespace fair;
using namespace fair::logger::test;
int main()
{
#ifdef FAIR_MIN_SEVERITY
if (static_cast<int>(Severity::FAIR_MIN_SEVERITY) > static_cast<int>(Severity::warn)) {
cout << "test requires at least FAIR_MIN_SEVERITY == warn to run, skipping" << endl;
return 0;
}
#endif
try {
Logger::SetConsoleColor(false);
Logger::SetConsoleSeverity(Severity::nolog);
Logger::SetVerbosity(Verbosity::low);
if (Logger::Logging(Severity::warn)) { cout << "Logger expected to NOT log warn, but it reports to do so" << endl; return 1; }
if (Logger::Logging(Severity::error)) { cout << "Logger expected to NOT log error, but it reports to do so" << endl; return 1; }
if (!Logger::Logging(Severity::fatal)) { cout << "Logger expected to log fatal, but it reports not to" << endl; return 1; }
cout << "##### adding file sink with warn severity" << endl;
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<> distrib(1, 65536);
string name = Logger::InitFileSink(Severity::warn, string("test_log_" + to_string(distrib(gen))), true);
if (Logger::GetFileSeverity() != Severity::warn) {
throw runtime_error(ToStr("File sink severity (", Logger::GetFileSeverity(), ") does not match the expected one (", Severity::warn, ")"));
}
CheckOutput("^\\[FATAL\\] fatal\n$", [](){
LOG(state) << "state";
LOG(warn) << "warning";
LOG(error) << "error";
LOG(fatal) << "fatal";
});
if (Logger::Logging(Severity::state)) { cout << "Logger expected to NOT log warn, but it reports to do so" << endl; return 1; }
if (!Logger::Logging(Severity::warn)) { cout << "Logger expected to log warn, but it reports not to" << endl; return 1; }
if (!Logger::Logging(Severity::error)) { cout << "Logger expected to log error, but it reports not to" << endl; return 1; }
if (!Logger::Logging(Severity::fatal)) { cout << "Logger expected to log fatal, but it reports not to" << endl; return 1; }
ifstream t(name);
stringstream buffer;
buffer << t.rdbuf();
string fileContent = buffer.str();
if (fileContent != "[WARN] warning\n[ERROR] error\n[FATAL] fatal\n") {
throw runtime_error(ToStr("unexpected file sink output. expected:\n[WARN] warning\n[ERROR] error\n[FATAL] fatal\nfound:\n", fileContent));
}
cout << "##### removing file sink with warn severity" << endl;
Logger::RemoveFileSink();
if (Logger::Logging(Severity::warn)) { cout << "Logger expected to NOT log warn, but it reports to do so" << endl; return 1; }
if (Logger::Logging(Severity::error)) { cout << "Logger expected to NOT log error, but it reports to do so" << endl; return 1; }
if (!Logger::Logging(Severity::fatal)) { cout << "Logger expected to log fatal, but it reports not to" << endl; return 1; }
cout << "##### adding custom sink with warn severity" << endl;
Logger::AddCustomSink("CustomSink", "warn", [](const string& content, const LogMetaData& metadata)
{
cout << "CustomSink " << content << endl;
if (metadata.severity != Severity::warn && metadata.severity != Severity::error && metadata.severity != Severity::fatal) {
throw runtime_error(ToStr("unexpected severity message arrived at custom sink that accepts only warn,error,fatal: ", metadata.severity));
}
if (metadata.severity_name != "WARN" && metadata.severity_name != "ERROR" && metadata.severity_name != "FATAL") {
throw runtime_error(ToStr("unexpected severity name arrived at custom sink that accepts only warn,error,fatal: ", metadata.severity_name));
}
});
if (Logger::GetCustomSeverity("CustomSink") != Severity::warn) {
throw runtime_error(ToStr("File sink severity (", Logger::GetCustomSeverity("CustomSink"), ") does not match the expected one (", Severity::warn, ")"));
}
bool oorThrown = false;
try {
Logger::GetCustomSeverity("NonExistentSink");
} catch (const out_of_range& oor) {
oorThrown = true;
}
if (!oorThrown) {
throw runtime_error("Did not detect a severity request from a non-existent sink");
}
CheckOutput("^CustomSink warning\nCustomSink error\nCustomSink fatal\n\\[FATAL\\] fatal\n$", [](){
LOG(state) << "state";
LOG(warn) << "warning";
LOG(error) << "error";
LOG(fatal) << "fatal";
});
if (Logger::Logging(Severity::state)) { cout << "Logger expected to NOT log warn, but it reports to do so" << endl; return 1; }
if (!Logger::Logging(Severity::warn)) { cout << "Logger expected to log warn, but it reports not to" << endl; return 1; }
if (!Logger::Logging(Severity::error)) { cout << "Logger expected to log error, but it reports not to" << endl; return 1; }
if (!Logger::Logging(Severity::fatal)) { cout << "Logger expected to log fatal, but it reports not to" << endl; return 1; }
cout << "##### removing custom sink with error severity" << endl;
bool caught = false;
try {
Logger::AddCustomSink("CustomSink", Severity::error, [](const string& /*content*/, const LogMetaData& /*metadata*/){});
} catch (runtime_error& rte) {
caught = true;
}
if (!caught) {
throw runtime_error("expected to throw a runtime_error upon adding sink with same key, but none was thrown");
}
Logger::RemoveCustomSink("CustomSink");
if (Logger::Logging(Severity::warn)) { cout << "Logger expected to NOT log warn, but it reports to do so" << endl; return 1; }
if (Logger::Logging(Severity::error)) { cout << "Logger expected to NOT log error, but it reports to do so" << endl; return 1; }
if (!Logger::Logging(Severity::fatal)) { cout << "Logger expected to log fatal, but it reports not to" << endl; return 1; }
caught = false;
try {
Logger::RemoveCustomSink("bla");
} catch (runtime_error& rte) {
caught = true;
}
if (!caught) {
throw runtime_error("expected to throw a runtime_error upon removing non-existent sink, but none was thrown");
}
} catch (runtime_error& rte) {
cout << rte.what() << endl;
return 1;
}
return 0;
}

67
test/threads.cxx Normal file
View File

@@ -0,0 +1,67 @@
/********************************************************************************
* Copyright (C) 2014-2020 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 "Common.h"
#include <Logger.h>
#include <iostream>
#include <thread>
#include <vector>
using namespace std;
using namespace fair;
using namespace fair::logger::test;
void f()
{
LOG(fatal) << "a" << "b" << "c" << "d" << "e" << "f" << "g" << "h" << "i" << "j" << "k" << "l" << "m" << "n" << "o" << "p" << "q" << "r" << "s" << "t" << "u" << "v" << "w" << "x" << "y" << "z";
}
int main()
{
try {
Logger::SetConsoleColor(false);
Logger::SetConsoleSeverity(Severity::fatal);
Logger::SetVerbosity(Verbosity::veryhigh);
CheckOutput(
R"(^\[.*\]\[\d{2}:\d{2}:\d{2}\.\d{6}\]\[FATAL\]\[.*:\d+:.*\] abcdefghijklmnopqrstuvwxyz
\[.*\]\[\d{2}:\d{2}:\d{2}\.\d{6}\]\[FATAL\]\[.*:\d+:.*\] abcdefghijklmnopqrstuvwxyz
\[.*\]\[\d{2}:\d{2}:\d{2}\.\d{6}\]\[FATAL\]\[.*:\d+:.*\] abcdefghijklmnopqrstuvwxyz
\[.*\]\[\d{2}:\d{2}:\d{2}\.\d{6}\]\[FATAL\]\[.*:\d+:.*\] abcdefghijklmnopqrstuvwxyz
\[.*\]\[\d{2}:\d{2}:\d{2}\.\d{6}\]\[FATAL\]\[.*:\d+:.*\] abcdefghijklmnopqrstuvwxyz
$)", []() {
thread t1(f);
thread t2(f);
thread t3(f);
thread t4(f);
thread t5(f);
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
});
thread t1(f);
thread t2(f);
thread t3(f);
thread t4(f);
thread t5(f);
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
} catch (runtime_error& rte) {
cout << rte.what() << endl;
return 1;
}
return 0;
}

102
test/verbosity.cxx Normal file
View File

@@ -0,0 +1,102 @@
/********************************************************************************
* Copyright (C) 2014-2020 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 "Common.h"
#include <Logger.h>
#include <iostream>
#include <string>
using namespace std;
using namespace fair;
using namespace fair::logger::test;
int main()
{
try {
Logger::SetConsoleColor(false);
Logger::SetConsoleSeverity(Severity::fatal);
auto spec1 = VerbositySpec::Make(VerbositySpec::Info::file_line_function, VerbositySpec::Info::process_name);
auto spec2 = VerbositySpec::Make(VerbositySpec::Info::process_name, VerbositySpec::Info::file_line_function);
Logger::DefineVerbosity(Verbosity::user1, spec1);
Logger::SetVerbosity(Verbosity::user1); // spec1 on user1
CheckOutput(ToStr(R"(^\[.*:\d{2}:.*\]\[.*\])", " content\n$"), []() { LOG(fatal) << "content"; });
Logger::DefineVerbosity(Verbosity::user1, spec2);
Logger::SetVerbosity(Verbosity::user1); // spec2 on user1
CheckOutput(ToStr(R"(^\[.*\]\[.*:\d{2}:.*\])", " content\n$"), []() { LOG(fatal) << "content"; });
Logger::DefineVerbosity(Verbosity::user2, spec1);
Logger::SetVerbosity(Verbosity::user2); // spec1 on user2
CheckOutput(ToStr(R"(^\[.*:\d{2}:.*\]\[.*\])", " content\n$"), []() { LOG(fatal) << "content"; });
Logger::SetVerbosity(Verbosity::verylow); // content
CheckOutput("^content\n$", []() { LOG(fatal) << "content"; });
Logger::SetVerbosity(Verbosity::low); // [severity] content
CheckOutput(ToStr(R"(^\[FATAL\])", " content\n$"), []() { LOG(fatal) << "content"; });
Logger::SetVerbosity(Verbosity::medium); // [HH:MM:SS][severity] content
CheckOutput(ToStr(R"(^\[\d{2}:\d{2}:\d{2}\]\[FATAL\])", " content\n$"), []() { LOG(fatal) << "content"; });
Logger::SetVerbosity(Verbosity::high); // [process_name][HH:MM:SS][severity] content
CheckOutput(ToStr(R"(^\[.*\]\[\d{2}:\d{2}:\d{2}\]\[FATAL\])", " content\n$"), []() { LOG(fatal) << "content"; });
Logger::SetVerbosity(Verbosity::veryhigh); // [process_name][HH:MM:SS:µS][severity][file:line:function] content
CheckOutput(ToStr(R"(^\[.*\]\[\d{2}:\d{2}:\d{2}\.\d{6}\]\[FATAL\]\[.*:\d+:.*\])", " content\n$"), []() { LOG(fatal) << "content"; });
Logger::SetConsoleColor(true);
Logger::SetVerbosity(Verbosity::verylow); // content
CheckOutput(
"^"
"content\n"
"$", []() { LOG(fatal) << "content"; });
Logger::SetVerbosity(Verbosity::low); // [severity] content
CheckOutput(
"^"
"\\[\033\\[01;31mFATAL\033\\[0m\\]"
" content\n"
"$", []() { LOG(fatal) << "content"; });
Logger::SetVerbosity(Verbosity::medium); // [HH:MM:SS][severity] content
CheckOutput(
"^"
"\\[\033\\[01;36m\\d{2}:\\d{2}:\\d{2}\033\\[0m\\]"
"\\[\033\\[01;31mFATAL\033\\[0m\\]"
" content\n"
"$", []() { LOG(fatal) << "content"; });
Logger::SetVerbosity(Verbosity::high); // [process_name][HH:MM:SS][severity] content
CheckOutput(
"^"
"\\[\033\\[01;34m.*\033\\[0m\\]"
"\\[\033\\[01;36m\\d{2}:\\d{2}:\\d{2}\033\\[0m\\]"
"\\[\033\\[01;31mFATAL\033\\[0m\\]"
" content\n"
"$", []() { LOG(fatal) << "content"; });
Logger::SetVerbosity(Verbosity::veryhigh); // [process_name][HH:MM:SS:µS][severity][file:line:function] content
CheckOutput(
"^"
"\\[\033\\[01;34m.*\033\\[0m\\]"
"\\[\033\\[01;36m\\d{2}:\\d{2}:\\d{2}\\.\\d{6}\033\\[0m\\]"
"\\[\033\\[01;31mFATAL\033\\[0m\\]"
"\\[\033\\[01;34m.*\033\\[0m:\033\\[01;33m\\d+\033\\[0m:\033\\[01;34m.*\033\\[0m\\]"
" content\n"
"$", []() { LOG(fatal) << "content"; });
} catch (runtime_error& rte) {
cout << rte.what() << endl;
return 1;
}
return 0;
}