mirror of
https://github.com/FairRootGroup/FairLogger.git
synced 2025-10-17 18:41:45 +00:00
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
bcfe438862 | ||
|
4b3e6d3837 | ||
|
b30cacab12 | ||
|
c8d59d11fb | ||
|
a737a1de9c | ||
|
1cb941021c | ||
|
de1014dabb | ||
|
ce64f628b0 | ||
|
35ebc10204 | ||
|
1253bbbac8 | ||
|
e9bd3f2b62 | ||
|
1f3b2a2c82 | ||
|
2b37d0147e | ||
|
f0cbe0bd47 | ||
|
5f7197d987 | ||
|
b1cb6f8a99 | ||
|
56780689fc | ||
|
8446c6db0c | ||
|
a0ff4eba50 | ||
|
cfe0f9dc53 | ||
|
cdf887f5da | ||
|
6555aa1dc0 | ||
|
d1f73fe9f0 | ||
|
86ab87de7b |
@@ -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 " ")
|
||||||
################################################################################
|
################################################################################
|
||||||
|
59
README.md
59
README.md
@@ -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
|
||||||
|
@@ -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.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
172
logger/Logger.h
172
logger/Logger.h
@@ -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
100
test/Common.h
Normal 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
81
test/cycle.cxx
Normal 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
58
test/logger.cxx
Normal 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;
|
||||||
|
}
|
@@ -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
60
test/macros.cxx
Normal 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
60
test/nolog.cxx
Normal 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
98
test/severity.cxx
Normal 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
151
test/sinks.cxx
Normal 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
67
test/threads.cxx
Normal 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
102
test/verbosity.cxx
Normal 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;
|
||||||
|
}
|
Reference in New Issue
Block a user