mirror of
https://github.com/juzzlin/Heimer.git
synced 2025-06-10 07:37:14 +08:00
Update SimpleLogger
This commit is contained in:
parent
5b3615cdae
commit
9ffe90f9da
@ -1,3 +1,19 @@
|
||||
2.0.0
|
||||
=====
|
||||
|
||||
New features:
|
||||
|
||||
* Fix GitHub Issue #5: Add support for tags
|
||||
* Add support for customized timestamp format
|
||||
* Add ISODateTime option to TimestampMode
|
||||
|
||||
Other:
|
||||
|
||||
* Add SimpleLogger::setTimestampSeparator()
|
||||
* Rename init() to initialize()
|
||||
* Rename Logger to SimpleLogger
|
||||
* Require C++17
|
||||
|
||||
1.4.0
|
||||
=====
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
project(SimpleLogger)
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
cmake_policy(VERSION 3.10)
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
cmake_policy(VERSION 2.8.12)
|
||||
project(SimpleLogger)
|
||||
|
||||
option(BUILD_TESTS "Build unit tests" ON)
|
||||
|
||||
@ -12,16 +12,11 @@ if(NOT CMAKE_BUILD_TYPE)
|
||||
MinSizeRel." FORCE)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR MINGW OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden")
|
||||
|
||||
# CMAKE_CXX_STANDARD supported only by versions >= 3.1
|
||||
if (CMAKE_VERSION VERSION_LESS "3.1")
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
set(LIBRARY_NAME "SimpleLogger")
|
||||
|
39
src/contrib/SimpleLogger/Jenkinsfile
vendored
39
src/contrib/SimpleLogger/Jenkinsfile
vendored
@ -1,30 +1,33 @@
|
||||
pipeline {
|
||||
agent any
|
||||
agent none
|
||||
stages {
|
||||
stage('CMake Debug build') {
|
||||
agent {
|
||||
docker {
|
||||
image 'juzzlin/qt5-18.04:latest'
|
||||
args '--privileged -t -v $WORKSPACE:/SimpleLogger'
|
||||
stage('Matrix Build') {
|
||||
matrix {
|
||||
axes {
|
||||
axis {
|
||||
name 'IMAGE'
|
||||
values 'qt5-20.04', 'qt6-22.04', 'qt6-24.04'
|
||||
}
|
||||
axis {
|
||||
name 'BUILD_TYPE'
|
||||
values 'Debug', 'Release'
|
||||
}
|
||||
}
|
||||
stages {
|
||||
stage('Build and Test') {
|
||||
agent any
|
||||
steps {
|
||||
sh "mkdir -p build-debug"
|
||||
sh "cd build-debug && cmake -DCMAKE_BUILD_TYPE=Debug .."
|
||||
sh "cd build-debug && cmake --build . --target all -- -j3 && ctest"
|
||||
script {
|
||||
docker.image("juzzlin/${IMAGE}:latest").inside('--privileged -t -v $WORKSPACE:/Argengine') {
|
||||
def buildDir = "build-${BUILD_TYPE.toLowerCase()}-${IMAGE}"
|
||||
sh "mkdir -p ${buildDir}"
|
||||
sh "cd ${buildDir} && cmake -GNinja -DCMAKE_BUILD_TYPE=${BUILD_TYPE} .."
|
||||
sh "cd ${buildDir} && cmake --build . && ctest"
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('CMake Release build') {
|
||||
agent {
|
||||
docker {
|
||||
image 'juzzlin/qt5-18.04:latest'
|
||||
args '--privileged -t -v $WORKSPACE:/SimpleLogger'
|
||||
}
|
||||
}
|
||||
steps {
|
||||
sh "mkdir -p build-release"
|
||||
sh "cd build-release && cmake -DCMAKE_BUILD_TYPE=Release .."
|
||||
sh "cd build-release && cmake --build . --target all -- -j3 && ctest"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ Looking for a simple logger for your C++ project? `SimpleLogger` might be for yo
|
||||
|
||||
* Based on RAII
|
||||
* Configurable level symbols
|
||||
* Datetime / EPOCH timestamps
|
||||
* Datetime, ISO Datetime, EPOCH, and custom timestamp formats
|
||||
* Logging levels: `Trace`, `Debug`, `Info`, `Warning`, `Error`, `Fatal`
|
||||
* Log to file and/or console
|
||||
* Thread-safe
|
||||
@ -34,7 +34,7 @@ include_directories(SimpleLogger/src)
|
||||
Link to the library:
|
||||
|
||||
```
|
||||
target_link_libraries(${YOUR_TARGET_NAME} SimpleLogger)
|
||||
target_link_libraries(${YOUR_TARGET_NAME} SimpleLogger_static)
|
||||
```
|
||||
|
||||
In your code:
|
||||
@ -78,7 +78,7 @@ Outputs something like this:
|
||||
```
|
||||
using juzzlin::L;
|
||||
|
||||
L::init("/tmp/myLog.txt");
|
||||
L::initialize("/tmp/myLog.txt");
|
||||
|
||||
L().info() << "Something happened";
|
||||
```
|
||||
@ -88,7 +88,7 @@ L().info() << "Something happened";
|
||||
```
|
||||
using juzzlin::L;
|
||||
|
||||
L::init("/tmp/myLog.txt");
|
||||
L::initialize("/tmp/myLog.txt");
|
||||
L::enableEchoMode(false);
|
||||
|
||||
L().info() << "Something happened";
|
||||
@ -111,6 +111,20 @@ Outputs something like this:
|
||||
|
||||
`Sat Oct 13 22:38:42 2018 D: A debug thing happened`
|
||||
|
||||
## Log with a tag
|
||||
|
||||
```
|
||||
using juzzlin::L;
|
||||
|
||||
L::setLoggingLevel(L::Level::Info);
|
||||
|
||||
L("MyTag").info() << "Something happened";
|
||||
```
|
||||
|
||||
Outputs something like this:
|
||||
|
||||
`Sat Oct 13 22:38:42 2018 I: MyTag: Something happened`
|
||||
|
||||
## Set custom level symbols
|
||||
|
||||
```
|
||||
@ -126,14 +140,15 @@ Outputs something like this:
|
||||
|
||||
`Sat Oct 13 22:38:42 2018 <DEBUG> A debug thing happened`
|
||||
|
||||
## Set timestamp mode and optional custom separator
|
||||
## Set timestamp mode and optional timestamp separator
|
||||
|
||||
Possible modes: `None`, `EpochSeconds`, `EpochMilliseconds`, `EpochMicroseconds`, `DateTime`.
|
||||
Possible timestamp modes: `None`, `EpochSeconds`, `EpochMilliseconds`, `EpochMicroseconds`, `DateTime`, `ISODateTime`.
|
||||
|
||||
```
|
||||
using juzzlin::L;
|
||||
|
||||
L::setTimestampMode(L::TimestampMode::EpochMilliseconds, " ## ");
|
||||
L::setTimestampMode(L::TimestampMode::EpochMilliseconds);
|
||||
L::setTimestampSeparator(" ## ");
|
||||
|
||||
L().info() << "Something happened";
|
||||
```
|
||||
@ -142,6 +157,23 @@ Outputs something like this:
|
||||
|
||||
`1562955750677 ## I: Something happened`
|
||||
|
||||
## Set custom timestamp format
|
||||
|
||||
By setting a custom timestamp format the timestamp mode is set to `Custom`:
|
||||
|
||||
```
|
||||
using juzzlin::L;
|
||||
|
||||
L::setCustomTimestampFormat("%H:%M:%S_%Y-%m-%d");
|
||||
L::setTimestampSeparator(" ## ");
|
||||
|
||||
L().info() << "Something happened";
|
||||
```
|
||||
|
||||
Outputs something like this:
|
||||
|
||||
`12:34:58_2024-07-06 ## I: Something happened`
|
||||
|
||||
## Set custom output stream
|
||||
|
||||
```
|
||||
@ -153,7 +185,7 @@ L::setStream(L::Level::Info, ssI);
|
||||
|
||||
# Requirements
|
||||
|
||||
C++11
|
||||
C++17
|
||||
|
||||
# Licence
|
||||
|
||||
|
@ -27,338 +27,398 @@
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include <QDebug>
|
||||
#endif
|
||||
|
||||
namespace juzzlin {
|
||||
|
||||
class Logger::Impl
|
||||
class SimpleLogger::Impl
|
||||
{
|
||||
public:
|
||||
|
||||
Impl();
|
||||
|
||||
Impl(const std::string & tag);
|
||||
|
||||
~Impl();
|
||||
|
||||
std::ostringstream & trace();
|
||||
std::ostringstream & traceStream();
|
||||
|
||||
std::ostringstream & debug();
|
||||
std::ostringstream & debugStream();
|
||||
|
||||
std::ostringstream & info();
|
||||
std::ostringstream & infoStream();
|
||||
|
||||
std::ostringstream & warning();
|
||||
std::ostringstream & warningStream();
|
||||
|
||||
std::ostringstream & error();
|
||||
std::ostringstream & errorStream();
|
||||
|
||||
std::ostringstream & fatal();
|
||||
std::ostringstream & fatalStream();
|
||||
|
||||
static void enableEchoMode(bool enable);
|
||||
|
||||
static void setLevelSymbol(Logger::Level level, std::string symbol);
|
||||
static void setLevelSymbol(SimpleLogger::Level level, std::string symbol);
|
||||
|
||||
static void setLoggingLevel(Logger::Level level);
|
||||
static void setLoggingLevel(SimpleLogger::Level level);
|
||||
|
||||
static void setTimestampMode(Logger::TimestampMode timestampMode, std::string separator);
|
||||
static void setCustomTimestampFormat(std::string format);
|
||||
|
||||
static void setTimestampMode(SimpleLogger::TimestampMode timestampMode);
|
||||
|
||||
static void setTimestampSeparator(std::string separator);
|
||||
|
||||
static void setStream(Level level, std::ostream & stream);
|
||||
|
||||
static void init(std::string filename, bool append);
|
||||
static void initialize(std::string filename, bool append);
|
||||
|
||||
void flush();
|
||||
|
||||
std::ostringstream & getStream(Logger::Level level);
|
||||
|
||||
void prefixTimestamp();
|
||||
std::ostringstream & prepareStreamForLoggingLevel(SimpleLogger::Level level);
|
||||
|
||||
private:
|
||||
std::string currentDateTime(std::chrono::time_point<std::chrono::system_clock> now, const std::string & dateTimeFormat) const;
|
||||
|
||||
void flushFileIfOpen();
|
||||
|
||||
void flushEchoIfEnabled();
|
||||
|
||||
void prefixWithLevelAndTag(SimpleLogger::Level level);
|
||||
|
||||
void prefixWithTimestamp();
|
||||
|
||||
bool shouldFlush() const;
|
||||
|
||||
static bool m_echoMode;
|
||||
|
||||
static Logger::Level m_level;
|
||||
static SimpleLogger::Level m_level;
|
||||
|
||||
static Logger::TimestampMode m_timestampMode;
|
||||
static SimpleLogger::TimestampMode m_timestampMode;
|
||||
|
||||
static std::string m_timestampSeparator;
|
||||
|
||||
static std::ofstream m_fout;
|
||||
static std::string m_customTimestampFormat;
|
||||
|
||||
using SymbolMap = std::map<Logger::Level, std::string>;
|
||||
static std::ofstream m_fileStream;
|
||||
|
||||
using SymbolMap = std::map<SimpleLogger::Level, std::string>;
|
||||
static SymbolMap m_symbols;
|
||||
|
||||
using StreamMap = std::map<Logger::Level, std::ostream *>;
|
||||
using StreamMap = std::map<SimpleLogger::Level, std::ostream *>;
|
||||
static StreamMap m_streams;
|
||||
|
||||
static std::recursive_mutex m_mutex;
|
||||
|
||||
Logger::Level m_activeLevel = Logger::Level::Info;
|
||||
SimpleLogger::Level m_activeLevel = SimpleLogger::Level::Info;
|
||||
|
||||
std::lock_guard<std::recursive_mutex> m_lock;
|
||||
|
||||
std::ostringstream m_oss;
|
||||
std::string m_tag;
|
||||
|
||||
std::ostringstream m_message;
|
||||
};
|
||||
|
||||
bool Logger::Impl::m_echoMode = true;
|
||||
bool SimpleLogger::Impl::m_echoMode = true;
|
||||
|
||||
Logger::Level Logger::Impl::m_level = Logger::Level::Info;
|
||||
SimpleLogger::Level SimpleLogger::Impl::m_level = SimpleLogger::Level::Info;
|
||||
|
||||
Logger::TimestampMode Logger::Impl::m_timestampMode = Logger::TimestampMode::DateTime;
|
||||
SimpleLogger::TimestampMode SimpleLogger::Impl::m_timestampMode = SimpleLogger::TimestampMode::DateTime;
|
||||
|
||||
std::string Logger::Impl::m_timestampSeparator = ": ";
|
||||
std::string SimpleLogger::Impl::m_timestampSeparator = ": ";
|
||||
|
||||
std::ofstream Logger::Impl::m_fout;
|
||||
std::string SimpleLogger::Impl::m_customTimestampFormat;
|
||||
|
||||
std::ofstream SimpleLogger::Impl::m_fileStream;
|
||||
|
||||
// Default level symbols
|
||||
Logger::Impl::SymbolMap Logger::Impl::m_symbols = {
|
||||
{Logger::Level::Trace, "T:"},
|
||||
{Logger::Level::Debug, "D:"},
|
||||
{Logger::Level::Info, "I:"},
|
||||
{Logger::Level::Warning, "W:"},
|
||||
{Logger::Level::Error, "E:"},
|
||||
{Logger::Level::Fatal, "F:"}
|
||||
SimpleLogger::Impl::SymbolMap SimpleLogger::Impl::m_symbols = {
|
||||
{ SimpleLogger::Level::Trace, "T:" },
|
||||
{ SimpleLogger::Level::Debug, "D:" },
|
||||
{ SimpleLogger::Level::Info, "I:" },
|
||||
{ SimpleLogger::Level::Warning, "W:" },
|
||||
{ SimpleLogger::Level::Error, "E:" },
|
||||
{ SimpleLogger::Level::Fatal, "F:" }
|
||||
};
|
||||
|
||||
// Default streams
|
||||
Logger::Impl::StreamMap Logger::Impl::m_streams = {
|
||||
{Logger::Level::Trace, &std::cout},
|
||||
{Logger::Level::Debug, &std::cout},
|
||||
{Logger::Level::Info, &std::cout},
|
||||
{Logger::Level::Warning, &std::cerr},
|
||||
{Logger::Level::Error, &std::cerr},
|
||||
{Logger::Level::Fatal, &std::cerr}
|
||||
SimpleLogger::Impl::StreamMap SimpleLogger::Impl::m_streams = {
|
||||
{ SimpleLogger::Level::Trace, &std::cout },
|
||||
{ SimpleLogger::Level::Debug, &std::cout },
|
||||
{ SimpleLogger::Level::Info, &std::cout },
|
||||
{ SimpleLogger::Level::Warning, &std::cerr },
|
||||
{ SimpleLogger::Level::Error, &std::cerr },
|
||||
{ SimpleLogger::Level::Fatal, &std::cerr }
|
||||
};
|
||||
|
||||
std::recursive_mutex Logger::Impl::m_mutex;
|
||||
std::recursive_mutex SimpleLogger::Impl::m_mutex;
|
||||
|
||||
Logger::Impl::Impl()
|
||||
: m_lock(Logger::Impl::m_mutex)
|
||||
SimpleLogger::Impl::Impl()
|
||||
: m_lock(m_mutex)
|
||||
{
|
||||
}
|
||||
|
||||
Logger::Impl::~Impl()
|
||||
SimpleLogger::Impl::Impl(const std::string & tag)
|
||||
: m_lock(m_mutex)
|
||||
, m_tag(tag)
|
||||
{
|
||||
}
|
||||
|
||||
SimpleLogger::Impl::~Impl()
|
||||
{
|
||||
flush();
|
||||
}
|
||||
|
||||
void Logger::Impl::enableEchoMode(bool enable)
|
||||
void SimpleLogger::Impl::enableEchoMode(bool enable)
|
||||
{
|
||||
Impl::m_echoMode = enable;
|
||||
m_echoMode = enable;
|
||||
}
|
||||
|
||||
std::ostringstream & Logger::Impl::getStream(Logger::Level level)
|
||||
std::ostringstream & SimpleLogger::Impl::prepareStreamForLoggingLevel(SimpleLogger::Level level)
|
||||
{
|
||||
m_activeLevel = level;
|
||||
Impl::prefixTimestamp();
|
||||
m_oss << Impl::m_symbols[level] << " ";
|
||||
return m_oss;
|
||||
prefixWithTimestamp();
|
||||
prefixWithLevelAndTag(level);
|
||||
return m_message;
|
||||
}
|
||||
|
||||
void Logger::Impl::setLevelSymbol(Level level, std::string symbol)
|
||||
void SimpleLogger::Impl::setLevelSymbol(Level level, std::string symbol)
|
||||
{
|
||||
Impl::m_symbols[level] = symbol;
|
||||
m_symbols[level] = symbol;
|
||||
}
|
||||
|
||||
void Logger::Impl::setLoggingLevel(Logger::Level level)
|
||||
void SimpleLogger::Impl::setLoggingLevel(SimpleLogger::Level level)
|
||||
{
|
||||
Impl::m_level = level;
|
||||
m_level = level;
|
||||
}
|
||||
|
||||
void Logger::Impl::setTimestampMode(TimestampMode timestampMode, std::string separator)
|
||||
void SimpleLogger::Impl::setCustomTimestampFormat(std::string customTimestampFormat)
|
||||
{
|
||||
Impl::m_timestampMode = timestampMode;
|
||||
Impl::m_timestampSeparator = separator;
|
||||
m_customTimestampFormat = customTimestampFormat;
|
||||
}
|
||||
|
||||
void Logger::Impl::prefixTimestamp()
|
||||
void SimpleLogger::Impl::setTimestampMode(TimestampMode timestampMode)
|
||||
{
|
||||
std::string timeStr;
|
||||
m_timestampMode = timestampMode;
|
||||
}
|
||||
|
||||
void SimpleLogger::Impl::setTimestampSeparator(std::string separator)
|
||||
{
|
||||
m_timestampSeparator = separator;
|
||||
}
|
||||
|
||||
std::string SimpleLogger::Impl::currentDateTime(std::chrono::time_point<std::chrono::system_clock> now, const std::string & dateTimeFormat) const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
const auto rawTime = std::chrono::system_clock::to_time_t(now);
|
||||
oss << std::put_time(std::localtime(&rawTime), dateTimeFormat.c_str());
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void SimpleLogger::Impl::prefixWithLevelAndTag(SimpleLogger::Level level)
|
||||
{
|
||||
m_message << m_symbols[level] << (!m_tag.empty() ? " " + m_tag + ":" : "") << " ";
|
||||
}
|
||||
|
||||
void SimpleLogger::Impl::prefixWithTimestamp()
|
||||
{
|
||||
std::string timestamp;
|
||||
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::system_clock;
|
||||
|
||||
switch (Impl::m_timestampMode)
|
||||
{
|
||||
case Logger::TimestampMode::None:
|
||||
switch (m_timestampMode) {
|
||||
case SimpleLogger::TimestampMode::None:
|
||||
break;
|
||||
case Logger::TimestampMode::DateTime:
|
||||
{
|
||||
time_t rawTime;
|
||||
time(&rawTime);
|
||||
timeStr = ctime(&rawTime);
|
||||
timeStr.erase(timeStr.length() - 1);
|
||||
}
|
||||
case SimpleLogger::TimestampMode::DateTime: {
|
||||
timestamp = currentDateTime(system_clock::now(), "%a %b %e %H:%M:%S %Y");
|
||||
} break;
|
||||
case SimpleLogger::TimestampMode::ISODateTime: {
|
||||
timestamp = currentDateTime(system_clock::now(), "%Y-%m-%dT%H:%M:%S");
|
||||
} break;
|
||||
case SimpleLogger::TimestampMode::EpochSeconds:
|
||||
timestamp = std::to_string(duration_cast<std::chrono::seconds>(system_clock::now().time_since_epoch()).count());
|
||||
break;
|
||||
case Logger::TimestampMode::EpochSeconds:
|
||||
timeStr = std::to_string(duration_cast<std::chrono::seconds>(system_clock::now().time_since_epoch()).count());
|
||||
case SimpleLogger::TimestampMode::EpochMilliseconds:
|
||||
using std::chrono::duration_cast;
|
||||
timestamp = std::to_string(duration_cast<std::chrono::milliseconds>(system_clock::now().time_since_epoch()).count());
|
||||
break;
|
||||
case Logger::TimestampMode::EpochMilliseconds:
|
||||
timeStr = std::to_string(duration_cast<std::chrono::milliseconds>(system_clock::now().time_since_epoch()).count());
|
||||
case SimpleLogger::TimestampMode::EpochMicroseconds:
|
||||
using std::chrono::duration_cast;
|
||||
timestamp = std::to_string(duration_cast<std::chrono::microseconds>(system_clock::now().time_since_epoch()).count());
|
||||
break;
|
||||
case Logger::TimestampMode::EpochMicroseconds:
|
||||
timeStr = std::to_string(duration_cast<std::chrono::microseconds>(system_clock::now().time_since_epoch()).count());
|
||||
case SimpleLogger::TimestampMode::Custom:
|
||||
timestamp = currentDateTime(system_clock::now(), m_customTimestampFormat);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!timeStr.empty())
|
||||
{
|
||||
m_oss << timeStr << m_timestampSeparator;
|
||||
if (!timestamp.empty()) {
|
||||
m_message << timestamp << m_timestampSeparator;
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::Impl::flush()
|
||||
bool SimpleLogger::Impl::shouldFlush() const
|
||||
{
|
||||
if (m_activeLevel < m_level)
|
||||
{
|
||||
return;
|
||||
return m_activeLevel >= m_level && !m_message.str().empty();
|
||||
}
|
||||
|
||||
if (!m_oss.str().size())
|
||||
void SimpleLogger::Impl::flushFileIfOpen()
|
||||
{
|
||||
return;
|
||||
if (m_fileStream.is_open()) {
|
||||
m_fileStream << m_message.str() << std::endl;
|
||||
m_fileStream.flush();
|
||||
}
|
||||
}
|
||||
|
||||
if (Impl::m_fout.is_open())
|
||||
void SimpleLogger::Impl::flushEchoIfEnabled()
|
||||
{
|
||||
Impl::m_fout << m_oss.str() << std::endl;
|
||||
Impl::m_fout.flush();
|
||||
}
|
||||
|
||||
if (Impl::m_echoMode)
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
qDebug() << m_oss.str().c_str();
|
||||
#else
|
||||
auto stream = Impl::m_streams[m_activeLevel];
|
||||
if (stream) {
|
||||
*stream << m_oss.str() << std::endl;
|
||||
if (m_echoMode) {
|
||||
if (auto && stream = m_streams[m_activeLevel]; stream) {
|
||||
*stream << m_message.str() << std::endl;
|
||||
stream->flush();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::Impl::init(std::string filename, bool append)
|
||||
void SimpleLogger::Impl::flush()
|
||||
{
|
||||
if (!filename.empty())
|
||||
{
|
||||
Impl::m_fout.open(filename, append ? std::ofstream::out | std::ofstream::app : std::ofstream::out);
|
||||
if (!Impl::m_fout.is_open())
|
||||
if (shouldFlush()) {
|
||||
flushFileIfOpen();
|
||||
flushEchoIfEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleLogger::Impl::initialize(std::string filename, bool append)
|
||||
{
|
||||
if (!filename.empty()) {
|
||||
m_fileStream.open(filename, append ? std::ofstream::out | std::ofstream::app : std::ofstream::out);
|
||||
if (!m_fileStream.is_open()) {
|
||||
throw std::runtime_error("ERROR!!: Couldn't open '" + filename + "' for write.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::ostringstream & Logger::Impl::trace()
|
||||
std::ostringstream & SimpleLogger::Impl::traceStream()
|
||||
{
|
||||
return getStream(Logger::Level::Trace);
|
||||
return prepareStreamForLoggingLevel(SimpleLogger::Level::Trace);
|
||||
}
|
||||
|
||||
std::ostringstream & Logger::Impl::debug()
|
||||
std::ostringstream & SimpleLogger::Impl::debugStream()
|
||||
{
|
||||
return getStream(Logger::Level::Debug);
|
||||
return prepareStreamForLoggingLevel(SimpleLogger::Level::Debug);
|
||||
}
|
||||
|
||||
std::ostringstream & Logger::Impl::info()
|
||||
std::ostringstream & SimpleLogger::Impl::infoStream()
|
||||
{
|
||||
return getStream(Logger::Level::Info);
|
||||
return prepareStreamForLoggingLevel(SimpleLogger::Level::Info);
|
||||
}
|
||||
|
||||
std::ostringstream & Logger::Impl::warning()
|
||||
std::ostringstream & SimpleLogger::Impl::warningStream()
|
||||
{
|
||||
return getStream(Logger::Level::Warning);
|
||||
return prepareStreamForLoggingLevel(SimpleLogger::Level::Warning);
|
||||
}
|
||||
|
||||
std::ostringstream & Logger::Impl::error()
|
||||
std::ostringstream & SimpleLogger::Impl::errorStream()
|
||||
{
|
||||
return getStream(Logger::Level::Error);
|
||||
return prepareStreamForLoggingLevel(SimpleLogger::Level::Error);
|
||||
}
|
||||
|
||||
std::ostringstream & Logger::Impl::fatal()
|
||||
std::ostringstream & SimpleLogger::Impl::fatalStream()
|
||||
{
|
||||
return getStream(Logger::Level::Fatal);
|
||||
return prepareStreamForLoggingLevel(SimpleLogger::Level::Fatal);
|
||||
}
|
||||
|
||||
void Logger::Impl::setStream(Level level, std::ostream & stream)
|
||||
void SimpleLogger::Impl::setStream(Level level, std::ostream & stream)
|
||||
{
|
||||
Logger::Impl::m_streams[level] = &stream;
|
||||
m_streams[level] = &stream;
|
||||
}
|
||||
|
||||
Logger::Logger()
|
||||
: m_impl(new Logger::Impl)
|
||||
SimpleLogger::SimpleLogger()
|
||||
: m_impl(std::make_unique<SimpleLogger::Impl>())
|
||||
{
|
||||
}
|
||||
|
||||
void Logger::init(std::string filename, bool append)
|
||||
SimpleLogger::SimpleLogger(const std::string & tag)
|
||||
: m_impl(std::make_unique<SimpleLogger::Impl>(tag))
|
||||
{
|
||||
Impl::init(filename, append);
|
||||
}
|
||||
|
||||
void Logger::enableEchoMode(bool enable)
|
||||
void SimpleLogger::initialize(std::string filename, bool append)
|
||||
{
|
||||
Impl::initialize(filename, append);
|
||||
}
|
||||
|
||||
void SimpleLogger::enableEchoMode(bool enable)
|
||||
{
|
||||
Impl::enableEchoMode(enable);
|
||||
}
|
||||
|
||||
void Logger::setLoggingLevel(Level level)
|
||||
void SimpleLogger::setLoggingLevel(Level level)
|
||||
{
|
||||
Impl::setLoggingLevel(level);
|
||||
}
|
||||
|
||||
void Logger::setLevelSymbol(Level level, std::string symbol)
|
||||
void SimpleLogger::setLevelSymbol(Level level, std::string symbol)
|
||||
{
|
||||
Impl::setLevelSymbol(level, symbol);
|
||||
}
|
||||
|
||||
void Logger::setTimestampMode(TimestampMode timestampMode, std::string separator)
|
||||
void SimpleLogger::setTimestampMode(TimestampMode timestampMode)
|
||||
{
|
||||
Impl::setTimestampMode(timestampMode, separator);
|
||||
Impl::setTimestampMode(timestampMode);
|
||||
}
|
||||
|
||||
void Logger::setStream(Level level, std::ostream & stream)
|
||||
void SimpleLogger::setCustomTimestampFormat(std::string customTimestampFormat)
|
||||
{
|
||||
Impl::setTimestampMode(TimestampMode::Custom);
|
||||
Impl::setCustomTimestampFormat(customTimestampFormat);
|
||||
}
|
||||
|
||||
void SimpleLogger::setTimestampSeparator(std::string timestampSeparator)
|
||||
{
|
||||
Impl::setTimestampSeparator(timestampSeparator);
|
||||
}
|
||||
|
||||
void SimpleLogger::setStream(Level level, std::ostream & stream)
|
||||
{
|
||||
Impl::setStream(level, stream);
|
||||
}
|
||||
|
||||
std::ostringstream & Logger::trace()
|
||||
std::ostringstream & SimpleLogger::trace()
|
||||
{
|
||||
return m_impl->trace();
|
||||
return m_impl->traceStream();
|
||||
}
|
||||
|
||||
std::ostringstream & Logger::debug()
|
||||
std::ostringstream & SimpleLogger::debug()
|
||||
{
|
||||
return m_impl->debug();
|
||||
return m_impl->debugStream();
|
||||
}
|
||||
|
||||
std::ostringstream & Logger::info()
|
||||
std::ostringstream & SimpleLogger::info()
|
||||
{
|
||||
return m_impl->info();
|
||||
return m_impl->infoStream();
|
||||
}
|
||||
|
||||
std::ostringstream & Logger::warning()
|
||||
std::ostringstream & SimpleLogger::warning()
|
||||
{
|
||||
return m_impl->warning();
|
||||
return m_impl->warningStream();
|
||||
}
|
||||
|
||||
std::ostringstream & Logger::error()
|
||||
std::ostringstream & SimpleLogger::error()
|
||||
{
|
||||
return m_impl->error();
|
||||
return m_impl->errorStream();
|
||||
}
|
||||
|
||||
std::ostringstream & Logger::fatal()
|
||||
std::ostringstream & SimpleLogger::fatal()
|
||||
{
|
||||
return m_impl->fatal();
|
||||
return m_impl->fatalStream();
|
||||
}
|
||||
|
||||
std::string Logger::version()
|
||||
std::string SimpleLogger::version()
|
||||
{
|
||||
return "1.4.0";
|
||||
return "2.0.0";
|
||||
}
|
||||
|
||||
Logger::~Logger() = default;
|
||||
SimpleLogger::~SimpleLogger() = default;
|
||||
|
||||
} // juzzlin
|
||||
|
@ -22,10 +22,9 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#ifndef JUZZLIN_LOGGER_HPP
|
||||
#define JUZZLIN_LOGGER_HPP
|
||||
#ifndef JUZZLIN_SIMPLE_LOGGER_HPP
|
||||
#define JUZZLIN_SIMPLE_LOGGER_HPP
|
||||
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
@ -36,14 +35,14 @@ namespace juzzlin {
|
||||
*
|
||||
* using juzzlin::L;
|
||||
*
|
||||
* L::init("myLog.txt");
|
||||
* L::initialize("myLog.txt");
|
||||
*
|
||||
* Example logging:
|
||||
*
|
||||
* L().info() << "Initialization finished.";
|
||||
* L().error() << "Foo happened!";
|
||||
*/
|
||||
class Logger
|
||||
class SimpleLogger
|
||||
{
|
||||
public:
|
||||
enum class Level
|
||||
@ -63,20 +62,26 @@ public:
|
||||
DateTime,
|
||||
EpochSeconds,
|
||||
EpochMilliseconds,
|
||||
EpochMicroseconds
|
||||
EpochMicroseconds,
|
||||
ISODateTime,
|
||||
Custom
|
||||
};
|
||||
|
||||
//! Constructor.
|
||||
Logger();
|
||||
SimpleLogger();
|
||||
|
||||
//! Constructor.
|
||||
//! \param tag Tag that will be added to the message.
|
||||
SimpleLogger(const std::string & tag);
|
||||
|
||||
//! Destructor.
|
||||
~Logger();
|
||||
~SimpleLogger();
|
||||
|
||||
/*! Initialize the logger.
|
||||
* \param filename Log to filename. Disabled if empty.
|
||||
* \param append The existing log will be appended if true.
|
||||
* Throws on error. */
|
||||
static void init(std::string filename, bool append = false);
|
||||
static void initialize(std::string filename, bool append = false);
|
||||
|
||||
//! Enable/disable echo mode.
|
||||
//! \param enable Echo everything if true. Default is false.
|
||||
@ -93,8 +98,15 @@ public:
|
||||
|
||||
//! Set/enable timestamp mode.
|
||||
//! \param timestampMode Timestamp mode enumeration.
|
||||
static void setTimestampMode(TimestampMode timestampMode);
|
||||
|
||||
//! Set custom timestamp format. Sets timestamp mode to TimestampMode::Custom.
|
||||
//! \param customTimestampFormat Timestamp format e.g. "%Y-%m-%dT%H:%M:%S".
|
||||
static void setCustomTimestampFormat(std::string customTimestampFormat);
|
||||
|
||||
//! Set/enable timestamp separator.
|
||||
//! \param separator Separator string outputted after timestamp.
|
||||
static void setTimestampMode(TimestampMode timestampMode, std::string separator = " ");
|
||||
static void setTimestampSeparator(std::string separator);
|
||||
|
||||
//! Set specific stream.
|
||||
//! \param level The level.
|
||||
@ -123,15 +135,15 @@ public:
|
||||
std::ostringstream & fatal();
|
||||
|
||||
private:
|
||||
Logger(const Logger & r) = delete;
|
||||
Logger & operator=(const Logger & r) = delete;
|
||||
SimpleLogger(const SimpleLogger &) = delete;
|
||||
SimpleLogger & operator=(const SimpleLogger &) = delete;
|
||||
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
};
|
||||
|
||||
using L = Logger;
|
||||
using L = SimpleLogger;
|
||||
|
||||
} // juzzlin
|
||||
} // namespace juzzlin
|
||||
|
||||
#endif // JUZZLIN_LOGGER_HPP
|
||||
#endif // JUZZLIN_SIMPLE_LOGGER_HPP
|
||||
|
@ -22,7 +22,7 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "simple_logger.hpp"
|
||||
#include "../../simple_logger.hpp"
|
||||
|
||||
// Don't compile asserts away
|
||||
#ifdef NDEBUG
|
||||
@ -33,19 +33,27 @@
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
|
||||
int main(int, char **)
|
||||
namespace juzzlin::FileTest {
|
||||
|
||||
void verifyLogFile(const std::string & logFile, const std::string & message, const std::string & timestampSeparator, int expectedLines)
|
||||
{
|
||||
using juzzlin::L;
|
||||
std::ifstream fin { logFile };
|
||||
assert(fin.is_open());
|
||||
|
||||
const auto logFile = "file_test.log";
|
||||
int lines = 0;
|
||||
std::string line;
|
||||
while (std::getline(fin, line)) {
|
||||
assert(line.find(message) != std::string::npos);
|
||||
assert(line.find(timestampSeparator) != std::string::npos);
|
||||
lines++;
|
||||
}
|
||||
|
||||
L::init(logFile);
|
||||
L::enableEchoMode(true);
|
||||
L::setLoggingLevel(L::Level::Trace);
|
||||
assert(lines == expectedLines);
|
||||
}
|
||||
|
||||
void testAllLoggingLevels_allMessagesShouldBeFoundInFile(const std::string & logFileName, const std::string & timestampSeparator)
|
||||
{
|
||||
const std::string message = "Hello, world!";
|
||||
const std::string timestampSeparator = " ## ";
|
||||
L::setTimestampMode(L::TimestampMode::DateTime, timestampSeparator);
|
||||
|
||||
L().trace() << message;
|
||||
L().debug() << message;
|
||||
@ -54,19 +62,28 @@ int main(int, char **)
|
||||
L().error() << message;
|
||||
L().fatal() << message;
|
||||
|
||||
std::ifstream fin{logFile};
|
||||
assert(fin.is_open());
|
||||
|
||||
int lines = 0;
|
||||
std::string line;
|
||||
while (std::getline(fin, line))
|
||||
{
|
||||
assert(line.find(message) != std::string::npos);
|
||||
assert(line.find(timestampSeparator) != std::string::npos);
|
||||
lines++;
|
||||
verifyLogFile(logFileName, message, timestampSeparator, 6);
|
||||
}
|
||||
|
||||
assert(lines == 6);
|
||||
void initializeLoggger(const std::string & logFileName, const std::string & timestampSeparator)
|
||||
{
|
||||
L::initialize(logFileName);
|
||||
L::enableEchoMode(true);
|
||||
L::setLoggingLevel(L::Level::Trace);
|
||||
L::setTimestampMode(L::TimestampMode::DateTime);
|
||||
L::setTimestampSeparator(timestampSeparator);
|
||||
}
|
||||
|
||||
} // namespace juzzlin::FileTest
|
||||
|
||||
int main(int, char **)
|
||||
{
|
||||
const std::string logFileName = "file_test.log";
|
||||
const std::string timestampSeparator = " ## ";
|
||||
|
||||
juzzlin::FileTest::initializeLoggger(logFileName, timestampSeparator);
|
||||
|
||||
juzzlin::FileTest::testAllLoggingLevels_allMessagesShouldBeFoundInFile(logFileName, timestampSeparator);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "simple_logger.hpp"
|
||||
#include "../../simple_logger.hpp"
|
||||
|
||||
// Don't compile asserts away
|
||||
#ifdef NDEBUG
|
||||
@ -31,78 +31,368 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
void assertMessage(std::stringstream & stream, std::string message, std::string timestampSeparator)
|
||||
namespace juzzlin::StreamTest {
|
||||
|
||||
void assertString(std::stringstream & stream, const std::string & message)
|
||||
{
|
||||
assert(stream.str().find(message) != std::string::npos);
|
||||
assert(stream.str().find(timestampSeparator) != std::string::npos);
|
||||
if (stream.str().find(message) == std::string::npos) {
|
||||
throw std::runtime_error("ERROR!!: '" + message + "' not found in '" + stream.str() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
void assertNotMessage(std::stringstream & stream, std::string message, std::string timestampSeparator)
|
||||
void assertMessage(std::stringstream & stream, const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
assert(stream.str().find(message) == std::string::npos);
|
||||
assert(stream.str().find(timestampSeparator) == std::string::npos);
|
||||
assertString(stream, message);
|
||||
assertString(stream, timestampSeparator);
|
||||
}
|
||||
|
||||
int main(int, char **)
|
||||
void assertNotString(std::stringstream & stream, const std::string & message)
|
||||
{
|
||||
using juzzlin::L;
|
||||
if (stream.str().find(message) != std::string::npos) {
|
||||
throw std::runtime_error("ERROR!!: '" + message + "' was found in '" + stream.str() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
L::enableEchoMode(true);
|
||||
|
||||
const std::string message = "Hello, world!";
|
||||
const std::string timestampSeparator = " ## ";
|
||||
L::setTimestampMode(L::TimestampMode::DateTime, timestampSeparator);
|
||||
void assertNotMessage(std::stringstream & stream, const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
assertNotString(stream, message);
|
||||
assertNotString(stream, timestampSeparator);
|
||||
}
|
||||
|
||||
void testFatal_noneLoggingLevel_shouldNotPrintMessage(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
L::setLoggingLevel(L::Level::None);
|
||||
std::stringstream ssF;
|
||||
L::setStream(L::Level::Fatal, ssF);
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Fatal, ss);
|
||||
L().fatal() << message;
|
||||
assertNotMessage(ssF, message, timestampSeparator);
|
||||
assertNotMessage(ss, message, timestampSeparator);
|
||||
}
|
||||
|
||||
void testFatal_fatalLoggingLevel_shouldPrintMessage(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Fatal, ss);
|
||||
L::setLoggingLevel(L::Level::Fatal);
|
||||
L().fatal() << message;
|
||||
assertMessage(ssF, message, timestampSeparator);
|
||||
assertMessage(ss, message, timestampSeparator);
|
||||
}
|
||||
|
||||
std::stringstream ssE;
|
||||
L::setStream(L::Level::Error, ssE);
|
||||
void testError_higherLoggingLevel_shouldNotPrintMessage(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
L::setLoggingLevel(L::Level::Fatal);
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Error, ss);
|
||||
L().error() << message;
|
||||
assertNotMessage(ssE, message, timestampSeparator);
|
||||
assertNotMessage(ss, message, timestampSeparator);
|
||||
}
|
||||
|
||||
void testError_errorLoggingLevel_shouldPrintMessage(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Error, ss);
|
||||
L::setLoggingLevel(L::Level::Error);
|
||||
L().error() << message;
|
||||
assertMessage(ssE, message, timestampSeparator);
|
||||
assertMessage(ss, message, timestampSeparator);
|
||||
}
|
||||
|
||||
std::stringstream ssW;
|
||||
L::setStream(L::Level::Warning, ssW);
|
||||
void testWarning_higherLoggingLevel_shouldNotPrintMessage(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
L::setLoggingLevel(L::Level::Error);
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Warning, ss);
|
||||
L().warning() << message;
|
||||
assertNotMessage(ssW, message, timestampSeparator);
|
||||
assertNotMessage(ss, message, timestampSeparator);
|
||||
}
|
||||
|
||||
void testWarning_warningLoggingLevel_shouldPrintMessage(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Warning, ss);
|
||||
L::setLoggingLevel(L::Level::Warning);
|
||||
L().warning() << message;
|
||||
assertMessage(ssW, message, timestampSeparator);
|
||||
assertMessage(ss, message, timestampSeparator);
|
||||
}
|
||||
|
||||
std::stringstream ssI;
|
||||
L::setStream(L::Level::Info, ssI);
|
||||
void testInfo_higherLoggingLevel_shouldNotPrintMessage(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
L::setLoggingLevel(L::Level::Warning);
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Info, ss);
|
||||
L().info() << message;
|
||||
assertNotMessage(ssI, message, timestampSeparator);
|
||||
assertNotMessage(ss, message, timestampSeparator);
|
||||
}
|
||||
|
||||
void testInfo_infoLoggingLevel_shouldPrintMessage(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Info, ss);
|
||||
L::setLoggingLevel(L::Level::Info);
|
||||
L().info() << message;
|
||||
assertMessage(ssI, message, timestampSeparator);
|
||||
assertMessage(ss, message, timestampSeparator);
|
||||
}
|
||||
|
||||
std::stringstream ssD;
|
||||
L::setStream(L::Level::Debug, ssD);
|
||||
void testDebug_higherLoggingLevel_shouldNotPrintMessage(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
L::setLoggingLevel(L::Level::Info);
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Debug, ss);
|
||||
L().debug() << message;
|
||||
assertNotMessage(ssD, message, timestampSeparator);
|
||||
assertNotMessage(ss, message, timestampSeparator);
|
||||
}
|
||||
|
||||
void testDebug_debugLoggingLevel_shouldPrintMessage(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Debug, ss);
|
||||
L::setLoggingLevel(L::Level::Debug);
|
||||
L().debug() << message;
|
||||
assertMessage(ssD, message, timestampSeparator);
|
||||
assertMessage(ss, message, timestampSeparator);
|
||||
}
|
||||
|
||||
std::stringstream ssT;
|
||||
L::setStream(L::Level::Trace, ssT);
|
||||
void testTrace_higherLoggingLevel_shouldNotPrintMessage(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
L::setLoggingLevel(L::Level::Debug);
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Trace, ss);
|
||||
L().trace() << message;
|
||||
assertNotMessage(ssT, message, timestampSeparator);
|
||||
assertNotMessage(ss, message, timestampSeparator);
|
||||
}
|
||||
|
||||
void testTrace_traceLoggingLevel_shouldPrintMessage(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Trace, ss);
|
||||
L::setLoggingLevel(L::Level::Trace);
|
||||
L().trace() << message;
|
||||
assertMessage(ssT, message, timestampSeparator);
|
||||
assertMessage(ss, message, timestampSeparator);
|
||||
}
|
||||
|
||||
void testTag_fatalLevel_shouldPrintTag(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Fatal, ss);
|
||||
L::setLoggingLevel(L::Level::Fatal);
|
||||
const std::string tag = "TAG";
|
||||
L(tag).fatal() << message;
|
||||
assertMessage(ss, tag + ": " + message, timestampSeparator);
|
||||
}
|
||||
|
||||
void testTag_errorLevel_shouldPrintTag(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Error, ss);
|
||||
L::setLoggingLevel(L::Level::Error);
|
||||
const std::string tag = "TAG";
|
||||
L(tag).fatal() << message;
|
||||
assertMessage(ss, tag + ": " + message, timestampSeparator);
|
||||
}
|
||||
|
||||
void testTag_warningLevel_shouldPrintTag(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Warning, ss);
|
||||
L::setLoggingLevel(L::Level::Warning);
|
||||
const std::string tag = "TAG";
|
||||
L(tag).fatal() << message;
|
||||
assertMessage(ss, tag + ": " + message, timestampSeparator);
|
||||
}
|
||||
|
||||
void testTag_infoLevel_shouldPrintTag(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Info, ss);
|
||||
L::setLoggingLevel(L::Level::Info);
|
||||
const std::string tag = "TAG";
|
||||
L(tag).fatal() << message;
|
||||
assertMessage(ss, tag + ": " + message, timestampSeparator);
|
||||
}
|
||||
|
||||
void testTag_debugLevel_shouldPrintTag(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Debug, ss);
|
||||
L::setLoggingLevel(L::Level::Debug);
|
||||
const std::string tag = "TAG";
|
||||
L(tag).fatal() << message;
|
||||
assertMessage(ss, tag + ": " + message, timestampSeparator);
|
||||
}
|
||||
|
||||
void testTag_traceLevel_shouldPrintTag(const std::string & message, const std::string & timestampSeparator)
|
||||
{
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Trace, ss);
|
||||
L::setLoggingLevel(L::Level::Trace);
|
||||
const std::string tag = "TAG";
|
||||
L(tag).fatal() << message;
|
||||
assertMessage(ss, tag + ": " + message, timestampSeparator);
|
||||
}
|
||||
|
||||
void initializeLogger(const std::string & timestampSeparator)
|
||||
{
|
||||
L::enableEchoMode(true);
|
||||
L::setTimestampMode(L::TimestampMode::DateTime);
|
||||
L::setTimestampSeparator(timestampSeparator);
|
||||
}
|
||||
|
||||
void testTimestampMode_none_shouldNotPrintTimestamp(const std::string & message)
|
||||
{
|
||||
L::setTimestampMode(L::TimestampMode::None);
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Info, ss);
|
||||
L::setLoggingLevel(L::Level::Info);
|
||||
L().info() << message;
|
||||
assertString(ss, message);
|
||||
assertNotString(ss, "##");
|
||||
}
|
||||
|
||||
void testTimestampMode_dateTime_shouldPrintDateTimeTimestamp(const std::string & message)
|
||||
{
|
||||
L::setTimestampMode(L::TimestampMode::DateTime);
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Info, ss);
|
||||
L().info() << message;
|
||||
|
||||
assert(ss.str().find(message) != std::string::npos);
|
||||
|
||||
// Example of expected format: "Mon Jan 1 00:00:00 2021"
|
||||
// Regex to match date-time format (handling single-digit day with optional space)
|
||||
std::regex dateTimeRegex(R"(\w{3} \w{3} \s?\d{1,2} \d{2}:\d{2}:\d{2} \d{4} ##)");
|
||||
assert(std::regex_search(ss.str(), dateTimeRegex));
|
||||
}
|
||||
|
||||
void testTimestampMode_epochSeconds_shouldPrintEpochSecondsTimestamp(const std::string & message)
|
||||
{
|
||||
L::setTimestampMode(L::TimestampMode::EpochSeconds);
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Info, ss);
|
||||
L().info() << message;
|
||||
assert(ss.str().find(message) != std::string::npos);
|
||||
|
||||
// Regex to match epoch seconds format
|
||||
const std::regex epochSecondsRegex(R"(\d{10} ##)");
|
||||
assert(std::regex_search(ss.str(), epochSecondsRegex));
|
||||
}
|
||||
|
||||
void testTimestampMode_epochMilliseconds_shouldPrintEpochMillisecondsTimestamp(const std::string & message)
|
||||
{
|
||||
L::setTimestampMode(L::TimestampMode::EpochMilliseconds);
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Info, ss);
|
||||
L().info() << message;
|
||||
assert(ss.str().find(message) != std::string::npos);
|
||||
|
||||
// Regex to match epoch milliseconds format
|
||||
const std::regex epochMillisecondsRegex(R"(\d{13} ##)");
|
||||
assert(std::regex_search(ss.str(), epochMillisecondsRegex));
|
||||
}
|
||||
|
||||
void testTimestampMode_epochMicroseconds_shouldPrintEpochMicrosecondsTimestamp(const std::string & message)
|
||||
{
|
||||
L::setTimestampMode(L::TimestampMode::EpochMicroseconds);
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Info, ss);
|
||||
L().info() << message;
|
||||
assert(ss.str().find(message) != std::string::npos);
|
||||
|
||||
// Regex to match epoch microseconds format
|
||||
const std::regex epochMicrosecondsRegex(R"(\d{16} ##)");
|
||||
assert(std::regex_search(ss.str(), epochMicrosecondsRegex));
|
||||
}
|
||||
|
||||
void testTimestampMode_ISODateTime_shouldPrintISODateTimeTimestamp(const std::string & message)
|
||||
{
|
||||
L::setTimestampMode(L::TimestampMode::ISODateTime);
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Info, ss);
|
||||
L().info() << message;
|
||||
assert(ss.str().find(message) != std::string::npos);
|
||||
|
||||
// Regex to match ISO 8601 date-time format
|
||||
const std::regex isoDateTimeRegex(R"(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:.\d+)?Z? ##)");
|
||||
assert(std::regex_search(ss.str(), isoDateTimeRegex));
|
||||
}
|
||||
|
||||
void testTimestampMode_Custom_shouldPrintCustomTimestamp(const std::string & message)
|
||||
{
|
||||
L::setCustomTimestampFormat("%H:%M:%S_%Y-%m-%d");
|
||||
std::stringstream ss;
|
||||
L::setStream(L::Level::Info, ss);
|
||||
L().info() << message;
|
||||
assert(ss.str().find(message) != std::string::npos);
|
||||
|
||||
// Regex to match custom format
|
||||
const std::regex isoDateTimeRegex(R"(\d{2}:\d{2}:\d{2}_\d{4}-\d{2}-\d{2} ##)");
|
||||
assert(std::regex_search(ss.str(), isoDateTimeRegex));
|
||||
}
|
||||
|
||||
void runTests()
|
||||
{
|
||||
const std::string message = "Hello world!";
|
||||
const std::string timestampSeparator = " ## ";
|
||||
|
||||
initializeLogger(timestampSeparator);
|
||||
|
||||
testFatal_noneLoggingLevel_shouldNotPrintMessage(message, timestampSeparator);
|
||||
|
||||
testFatal_fatalLoggingLevel_shouldPrintMessage(message, timestampSeparator);
|
||||
|
||||
testError_higherLoggingLevel_shouldNotPrintMessage(message, timestampSeparator);
|
||||
|
||||
testError_errorLoggingLevel_shouldPrintMessage(message, timestampSeparator);
|
||||
|
||||
testWarning_higherLoggingLevel_shouldNotPrintMessage(message, timestampSeparator);
|
||||
|
||||
testWarning_warningLoggingLevel_shouldPrintMessage(message, timestampSeparator);
|
||||
|
||||
testInfo_higherLoggingLevel_shouldNotPrintMessage(message, timestampSeparator);
|
||||
|
||||
testInfo_infoLoggingLevel_shouldPrintMessage(message, timestampSeparator);
|
||||
|
||||
testDebug_higherLoggingLevel_shouldNotPrintMessage(message, timestampSeparator);
|
||||
|
||||
testDebug_debugLoggingLevel_shouldPrintMessage(message, timestampSeparator);
|
||||
|
||||
testTrace_higherLoggingLevel_shouldNotPrintMessage(message, timestampSeparator);
|
||||
|
||||
testTrace_traceLoggingLevel_shouldPrintMessage(message, timestampSeparator);
|
||||
|
||||
testTag_fatalLevel_shouldPrintTag(message, timestampSeparator);
|
||||
|
||||
testTag_errorLevel_shouldPrintTag(message, timestampSeparator);
|
||||
|
||||
testTag_warningLevel_shouldPrintTag(message, timestampSeparator);
|
||||
|
||||
testTag_infoLevel_shouldPrintTag(message, timestampSeparator);
|
||||
|
||||
testTag_debugLevel_shouldPrintTag(message, timestampSeparator);
|
||||
|
||||
testTag_traceLevel_shouldPrintTag(message, timestampSeparator);
|
||||
|
||||
testTimestampMode_none_shouldNotPrintTimestamp(message);
|
||||
|
||||
testTimestampMode_dateTime_shouldPrintDateTimeTimestamp(message);
|
||||
|
||||
testTimestampMode_epochSeconds_shouldPrintEpochSecondsTimestamp(message);
|
||||
|
||||
testTimestampMode_epochMilliseconds_shouldPrintEpochMillisecondsTimestamp(message);
|
||||
|
||||
testTimestampMode_epochMicroseconds_shouldPrintEpochMicrosecondsTimestamp(message);
|
||||
|
||||
testTimestampMode_ISODateTime_shouldPrintISODateTimeTimestamp(message);
|
||||
|
||||
testTimestampMode_Custom_shouldPrintCustomTimestamp(message);
|
||||
}
|
||||
|
||||
} // namespace juzzlin::StreamTest
|
||||
|
||||
int main()
|
||||
{
|
||||
juzzlin::StreamTest::runTests();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -35,9 +35,10 @@ static void initLogger()
|
||||
using juzzlin::L;
|
||||
|
||||
const QString logPath { QDir::tempPath() + QDir::separator() + "heimer-" + std::to_string(Utils::tsMs()).c_str() + ".log" };
|
||||
L::init(logPath.toStdString());
|
||||
L::initialize(logPath.toStdString());
|
||||
L::enableEchoMode(true);
|
||||
L::setTimestampMode(L::TimestampMode::DateTime, " ");
|
||||
L::setTimestampMode(L::TimestampMode::ISODateTime);
|
||||
L::setTimestampSeparator(" ");
|
||||
const std::map<L::Level, std::string> symbols = {
|
||||
{ L::Level::Debug, "D" },
|
||||
{ L::Level::Error, "E" },
|
||||
|
Loading…
x
Reference in New Issue
Block a user