mirror of
https://github.com/KjellKod/g3log.git
synced 2024-12-13 10:42:56 +01:00
commit
056a5483da
@ -23,6 +23,8 @@
|
||||
#include "g3log/logworker.hpp"
|
||||
#include "g3log/crashhandler.hpp"
|
||||
#include "g3log/logmessage.hpp"
|
||||
#include "g3log/loglevels.hpp"
|
||||
|
||||
|
||||
#include <cstdio> // vsnprintf
|
||||
#include <mutex>
|
||||
@ -125,6 +127,7 @@ namespace g3 {
|
||||
void shutDownLogging() {
|
||||
std::lock_guard<std::mutex> lock(g_logging_init_mutex);
|
||||
g_logger_instance = nullptr;
|
||||
|
||||
}
|
||||
|
||||
/** Same as the Shutdown above but called by the destructor of the LogWorker, thus ensuring that no further
|
||||
|
@ -8,18 +8,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
// Users of Juce or other libraries might have a define DEBUG which clashes with
|
||||
// the DEBUG logging level for G3log. In that case they can instead use the define
|
||||
// "CHANGE_G3LOG_DEBUG_TO_DBUG" and G3log's logging level DEBUG is changed to be DBUG
|
||||
#if (defined(CHANGE_G3LOG_DEBUG_TO_DBUG))
|
||||
#if (defined(DBUG))
|
||||
#error "DEBUG is already defined elsewhere which clashes with G3Log's log level DEBUG"
|
||||
#endif
|
||||
#if (defined(DBUG))
|
||||
#error "DEBUG is already defined elsewhere which clashes with G3Log's log level DEBUG"
|
||||
#endif
|
||||
#else
|
||||
#if (defined(DEBUG))
|
||||
#error "DEBUG is already defined elsewhere which clashes with G3Log's log level DEBUG"
|
||||
#endif
|
||||
#if (defined(DEBUG))
|
||||
#error "DEBUG is already defined elsewhere which clashes with G3Log's log level DEBUG"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
@ -30,9 +29,7 @@ struct LEVELS {
|
||||
// force internal copy of the const char*. This is a simple safeguard for when g3log is used in a
|
||||
// "dynamic, runtime loading of shared libraries"
|
||||
|
||||
LEVELS(const LEVELS &other)
|
||||
: value(other.value), text(other.text.c_str()) {}
|
||||
|
||||
LEVELS(const LEVELS &other): value(other.value), text(other.text.c_str()) {}
|
||||
LEVELS(int id, const char *idtext) : value(id), text(idtext) {}
|
||||
|
||||
friend bool operator==(const LEVELS &lhs, const LEVELS &rhs) {
|
||||
@ -50,35 +47,56 @@ namespace g3 {
|
||||
}
|
||||
|
||||
#if (defined(CHANGE_G3LOG_DEBUG_TO_DBUG))
|
||||
const LEVELS DBUG {
|
||||
g3::kDebugVaulue, {"DEBUG"}
|
||||
},
|
||||
const LEVELS DBUG {g3::kDebugVaulue, {"DEBUG"}},
|
||||
#else
|
||||
const LEVELS DEBUG {
|
||||
g3::kDebugVaulue, {"DEBUG"}
|
||||
},
|
||||
const LEVELS DEBUG {g3::kDebugVaulue, {"DEBUG"}},
|
||||
#endif
|
||||
INFO {g3::kDebugVaulue + 1, {"INFO"}},
|
||||
WARNING {INFO.value + 1, {"WARNING"}},
|
||||
// Insert here *any* extra logging levels that is needed
|
||||
INFO {g3::kDebugVaulue + 1, {"INFO"}},
|
||||
WARNING {INFO.value + 1, {"WARNING"}},
|
||||
|
||||
|
||||
|
||||
// Insert here *any* extra logging levels that is needed. You can do so in your own source file
|
||||
// If it is a FATAL you should keep it above (FATAL.value and below internal::CONTRACT.value
|
||||
// If it is a non-fatal you can keep it above (WARNING.value and below FATAL.value)
|
||||
//
|
||||
// example: MyLoggingLevel.h
|
||||
// #pragma once
|
||||
// const LEVELS MYINFO {WARNING.value +1, {"MyInfoLevel"}};
|
||||
// const LEVELS MYFATAL {FATAL.value +1, {"MyFatalLevel"}};
|
||||
//
|
||||
// IMPORTANT: As of yet dynamic on/off of logging is NOT changed automatically
|
||||
// any changes of this, if you use dynamic on/off must be done in loglevels.cpp,
|
||||
// g_log_level_status and
|
||||
// void setLogLevel(LEVELS log_level, bool enabled) {...}
|
||||
// bool logLevel(LEVELS log_level){...}
|
||||
|
||||
|
||||
// 1) Remember to update the FATAL initialization below
|
||||
// 2) Remember to update the initialization of "g3loglevels.cpp/g_log_level_status"
|
||||
FATAL {WARNING.value + 1, {"FATAL"}};
|
||||
|
||||
FATAL {500, {"FATAL"}};
|
||||
|
||||
namespace g3 {
|
||||
namespace internal {
|
||||
const LEVELS CONTRACT {
|
||||
100, {"CONTRACT"}
|
||||
}, FATAL_SIGNAL {101, {"FATAL_SIGNAL"}},
|
||||
FATAL_EXCEPTION {102, {"FATAL_EXCEPTION"}};
|
||||
const LEVELS CONTRACT {1000, {"CONTRACT"}},
|
||||
FATAL_SIGNAL {1001, {"FATAL_SIGNAL"}},
|
||||
FATAL_EXCEPTION {1002, {"FATAL_EXCEPTION"}};
|
||||
|
||||
/// helper function to tell the logger if a log message was fatal. If it is it will force
|
||||
/// a shutdown after all log entries are saved to the sinks
|
||||
bool wasFatal(const LEVELS &level);
|
||||
}
|
||||
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
// Enable/Disable a log level {DEBUG,INFO,WARNING,FATAL}
|
||||
void setLogLevel(LEVELS level, bool enabled_status);
|
||||
// Only safe if done at initialization in a single-thread context
|
||||
namespace only_change_at_initialization {
|
||||
// Enable/Disable a log level {DEBUG,INFO,WARNING,FATAL}
|
||||
void setLogLevel(LEVELS level, bool enabled_status);
|
||||
std::string printLevels();
|
||||
void reset();
|
||||
|
||||
} // only_change_at_initialization
|
||||
#endif
|
||||
bool logLevel(LEVELS level);
|
||||
bool logLevel(LEVELS level);
|
||||
} // g3
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
|
||||
* with no warranties. This code is yours to share, use and modify with no
|
||||
* strings attached and no restrictions or obligations.
|
||||
*
|
||||
*
|
||||
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
|
||||
* ============================================================================*/
|
||||
|
||||
@ -10,7 +10,30 @@
|
||||
#include "g3log/g3log.hpp"
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
|
||||
namespace {
|
||||
namespace {
|
||||
/// As suggested in: http://stackoverflow.com/questions/13193484/how-to-declare-a-vector-of-atomic-in-c
|
||||
struct atomicbool {
|
||||
private:
|
||||
std::atomic<bool> value_;
|
||||
public:
|
||||
atomicbool(): value_ {false} {}
|
||||
atomicbool(const bool &value): value_ {value} {}
|
||||
atomicbool(const std::atomic<bool> &value) : value_ {value.load(std::memory_order_acquire)} {}
|
||||
atomicbool(const atomicbool &other): value_ {other.value_.load(std::memory_order_acquire)} {}
|
||||
atomicbool &operator=(const atomicbool &other) {
|
||||
value_.store(other.value_.load(std::memory_order_acquire), std::memory_order_release);
|
||||
return *this;
|
||||
}
|
||||
bool value() {return value_.load(std::memory_order_acquire);}
|
||||
std::atomic<bool>& get() {return value_;}
|
||||
};
|
||||
|
||||
} // anonymous
|
||||
|
||||
}
|
||||
namespace g3 {
|
||||
namespace internal {
|
||||
bool wasFatal(const LEVELS &level) {
|
||||
@ -22,24 +45,37 @@ namespace g3 {
|
||||
const int g_level_size {
|
||||
FATAL.value + 1
|
||||
};
|
||||
std::atomic<bool> g_log_level_status[4] {{true}, {true}, {true}, {true}};
|
||||
//std::atomic<bool> g_log_level_status[4] {{true}, {true}, {true}, {true}};
|
||||
std::map<int, atomicbool> g_log_level_status = {{DEBUG.value, true}, {INFO.value, true}, {WARNING.value, true}, {FATAL.value, true}};
|
||||
#endif
|
||||
} // internal
|
||||
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
void setLogLevel(LEVELS log_level, bool enabled) {
|
||||
assert(internal::g_level_size == 4 && "Mismatch between number of logging levels and their use");
|
||||
int level = log_level.value;
|
||||
CHECK((level >= g3::kDebugVaulue) && (level <= FATAL.value));
|
||||
internal::g_log_level_status[level].store(enabled, std::memory_order_release);
|
||||
}
|
||||
namespace only_change_at_initialization {
|
||||
void setLogLevel(LEVELS log_level, bool enabled) {
|
||||
int level = log_level.value;
|
||||
internal::g_log_level_status[level].get().store(enabled, std::memory_order_release);
|
||||
}
|
||||
|
||||
std::string printLevels() {
|
||||
std::string levels;
|
||||
for (auto& v : internal::g_log_level_status) {
|
||||
levels += "value: " + std::to_string(v.first) + " status: " + std::to_string(v.second.value()) + "\n";
|
||||
}
|
||||
return levels;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
internal::g_log_level_status.clear();
|
||||
internal::g_log_level_status = {{DEBUG.value, true}, {INFO.value, true}, {WARNING.value, true}, {FATAL.value, true}};
|
||||
}
|
||||
} // only_change_at_initialization
|
||||
#endif
|
||||
|
||||
bool logLevel(LEVELS log_level) {
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
int level = log_level.value;
|
||||
CHECK((level >= g3::kDebugVaulue) && (level <= FATAL.value));
|
||||
bool status = (internal::g_log_level_status[level].load(std::memory_order_acquire));
|
||||
bool status = internal::g_log_level_status[level].value();
|
||||
return status;
|
||||
#endif
|
||||
return true;
|
||||
|
@ -54,7 +54,8 @@ TEST(Initialization, No_Logger_Initialized___LevelsAreONByDefault) {
|
||||
EXPECT_EQ(DEBUG.value, 0);
|
||||
EXPECT_EQ(INFO.value, 1);
|
||||
EXPECT_EQ(WARNING.value, 2);
|
||||
EXPECT_EQ(FATAL.value, 3);
|
||||
EXPECT_EQ(FATAL.value, 500);
|
||||
EXPECT_EQ(g3::internal::CONTRACT.value, 1000);
|
||||
}
|
||||
|
||||
TEST(Initialization, No_Logger_Initialized___Expecting_LOG_calls_to_be_Still_OKish) {
|
||||
@ -418,6 +419,44 @@ TEST(CHECK, CHECK_ThatWontThrow) {
|
||||
|
||||
|
||||
|
||||
TEST(CustomLogLevels, AddANonFatal){
|
||||
RestoreFileLogger logger(log_directory);
|
||||
const LEVELS MYINFO {WARNING.value +1, {"MY_INFO_LEVEL"}};
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
g3::only_change_at_initialization::setLogLevel(MYINFO, true);
|
||||
#endif
|
||||
LOG(MYINFO) << "Testing my own custom level"; auto line = __LINE__;
|
||||
logger.reset();
|
||||
std::string file_content = readFileToText(logger.logFile());
|
||||
std::string expected;
|
||||
expected += "MY_INFO_LEVEL [test_io.cpp L: " + std::to_string(line);
|
||||
EXPECT_TRUE(verifyContent(file_content, expected)) << file_content
|
||||
<< "\n\nExpected: \n" << expected;
|
||||
}
|
||||
|
||||
TEST(CustomLogLevels, AddFatal){
|
||||
RestoreFileLogger logger(log_directory);
|
||||
const LEVELS DEADLY {FATAL.value +1, {"DEADLY"}};
|
||||
EXPECT_TRUE(g3::internal::wasFatal(DEADLY));
|
||||
g_fatal_counter.store(0);
|
||||
ASSERT_FALSE(mockFatalWasCalled());
|
||||
g3::setFatalPreLoggingHook(fatalCounter);
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
g3::only_change_at_initialization::setLogLevel(DEADLY, true);
|
||||
#endif
|
||||
|
||||
LOG(DEADLY) << "Testing my own custom level"; auto line = __LINE__;
|
||||
logger.reset();
|
||||
ASSERT_TRUE(mockFatalWasCalled());
|
||||
EXPECT_EQ(size_t{1}, g_fatal_counter.load());
|
||||
|
||||
std::string file_content = readFileToText(logger.logFile());
|
||||
std::string expected;
|
||||
expected += "DEADLY [test_io.cpp L: " + std::to_string(line);
|
||||
EXPECT_TRUE(verifyContent(file_content, expected)) << file_content
|
||||
<< "\n\nExpected: \n" << expected;
|
||||
g_fatal_counter.store(0); // restore
|
||||
}
|
||||
|
||||
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
@ -428,13 +467,68 @@ namespace {
|
||||
RestoreDynamicLoggingLevels() {
|
||||
};
|
||||
~RestoreDynamicLoggingLevels() {
|
||||
g3::setLogLevel(DEBUG, false);
|
||||
g3::setLogLevel(INFO, false);
|
||||
g3::setLogLevel(WARNING, false);
|
||||
g3::setLogLevel(FATAL, false);
|
||||
g3::only_change_at_initialization::reset();
|
||||
g3::only_change_at_initialization::setLogLevel(DEBUG, false);
|
||||
g3::only_change_at_initialization::setLogLevel(INFO, false);
|
||||
g3::only_change_at_initialization::setLogLevel(WARNING, false);
|
||||
g3::only_change_at_initialization::setLogLevel(FATAL, false);
|
||||
}
|
||||
};
|
||||
} // anonymous
|
||||
|
||||
|
||||
TEST(CustomLogLevels, AddANonFatal__ThenReset){
|
||||
RestoreFileLogger logger(log_directory);
|
||||
const LEVELS MYINFO {WARNING.value +2, {"MY_INFO_LEVEL"}};
|
||||
EXPECT_FALSE(g3::logLevel(MYINFO));
|
||||
g3::only_change_at_initialization::setLogLevel(MYINFO, true);
|
||||
EXPECT_TRUE(g3::logLevel(MYINFO));
|
||||
g3::only_change_at_initialization::reset();
|
||||
EXPECT_FALSE(g3::logLevel(MYINFO));
|
||||
}
|
||||
|
||||
|
||||
TEST(CustomLogLevels, AddANonFatal__DidNotAddItToEnabledValue1){
|
||||
RestoreFileLogger logger(log_directory);
|
||||
const LEVELS MYINFO {WARNING.value +2, {"MY_INFO_LEVEL"}};
|
||||
LOG(MYINFO) << "Testing my own custom level"; auto line = __LINE__;
|
||||
logger.reset();
|
||||
|
||||
std::string file_content = readFileToText(logger.logFile());
|
||||
std::string expected;
|
||||
expected += "MY_INFO_LEVEL [test_io.cpp L: " + std::to_string(line);
|
||||
EXPECT_FALSE(verifyContent(file_content, expected)) << file_content
|
||||
<< "\n\nExpected: \n" << expected << "\nLevels:\n" << g3::only_change_at_initialization::printLevels();
|
||||
}
|
||||
|
||||
TEST(CustomLogLevels, AddANonFatal__DidNotAddItToEnabledValue2){
|
||||
RestoreFileLogger logger(log_directory);
|
||||
const LEVELS MYINFO {WARNING.value +2, {"MY_INFO_LEVEL"}};
|
||||
EXPECT_FALSE(g3::logLevel(MYINFO));
|
||||
LOG(MYINFO) << "Testing my own custom level"; auto line = __LINE__;
|
||||
logger.reset();
|
||||
|
||||
std::string file_content = readFileToText(logger.logFile());
|
||||
std::string expected;
|
||||
expected += "MY_INFO_LEVEL [test_io.cpp L: " + std::to_string(line);
|
||||
EXPECT_FALSE(verifyContent(file_content, expected)) << file_content
|
||||
<< "\n\nExpected: \n" << expected << "\nLevels:\n" << g3::only_change_at_initialization::printLevels();
|
||||
}
|
||||
|
||||
TEST(CustomLogLevels, AddANonFatal__DidtAddItToEnabledValue){
|
||||
RestoreFileLogger logger(log_directory);
|
||||
const LEVELS MYINFO {WARNING.value +3, {"MY_INFO_LEVEL"}};
|
||||
g3::only_change_at_initialization::setLogLevel(MYINFO, true);
|
||||
LOG(MYINFO) << "Testing my own custom level"; auto line = __LINE__;
|
||||
logger.reset();
|
||||
std::string file_content = readFileToText(logger.logFile());
|
||||
std::string expected;
|
||||
expected += "MY_INFO_LEVEL [test_io.cpp L: " + std::to_string(line);
|
||||
EXPECT_TRUE(verifyContent(file_content, expected)) << file_content
|
||||
<< "\n\nExpected: \n" << expected;
|
||||
}
|
||||
|
||||
|
||||
TEST(DynamicLogging, DynamicLogging_IS_ENABLED) {
|
||||
RestoreDynamicLoggingLevels raiiLevelRestore;
|
||||
|
||||
@ -442,25 +536,25 @@ TEST(DynamicLogging, DynamicLogging_IS_ENABLED) {
|
||||
ASSERT_TRUE(g3::logLevel(INFO));
|
||||
ASSERT_TRUE(g3::logLevel(WARNING));
|
||||
ASSERT_TRUE(g3::logLevel(FATAL)); // Yes FATAL can be turned off. Thereby rendering it ineffective.
|
||||
g3::setLogLevel(DEBUG, false);
|
||||
g3::only_change_at_initialization::setLogLevel(DEBUG, false);
|
||||
ASSERT_FALSE(g3::logLevel(DEBUG));
|
||||
ASSERT_TRUE(g3::logLevel(INFO));
|
||||
ASSERT_TRUE(g3::logLevel(WARNING));
|
||||
ASSERT_TRUE(g3::logLevel(FATAL)); // Yes FATAL can be turned off. Thereby rendering it ineffective.
|
||||
|
||||
g3::setLogLevel(INFO, false);
|
||||
g3::only_change_at_initialization::setLogLevel(INFO, false);
|
||||
ASSERT_FALSE(g3::logLevel(DEBUG));
|
||||
ASSERT_FALSE(g3::logLevel(INFO));
|
||||
ASSERT_TRUE(g3::logLevel(WARNING));
|
||||
ASSERT_TRUE(g3::logLevel(FATAL)); // Yes FATAL can be turned off. Thereby rendering it ineffective.
|
||||
|
||||
g3::setLogLevel(WARNING, false);
|
||||
g3::only_change_at_initialization::setLogLevel(WARNING, false);
|
||||
ASSERT_FALSE(g3::logLevel(DEBUG));
|
||||
ASSERT_FALSE(g3::logLevel(INFO));
|
||||
ASSERT_FALSE(g3::logLevel(WARNING));
|
||||
ASSERT_TRUE(g3::logLevel(FATAL)); // Yes FATAL can be turned off. Thereby rendering it ineffective.
|
||||
|
||||
g3::setLogLevel(FATAL, false);
|
||||
g3::only_change_at_initialization::setLogLevel(FATAL, false);
|
||||
ASSERT_FALSE(g3::logLevel(DEBUG));
|
||||
ASSERT_FALSE(g3::logLevel(INFO));
|
||||
ASSERT_FALSE(g3::logLevel(WARNING));
|
||||
@ -490,7 +584,7 @@ TEST(DynamicLogging, DynamicLogging_No_Logs_If_Disabled) {
|
||||
|
||||
{
|
||||
RestoreFileLogger logger(log_directory);
|
||||
g3::setLogLevel(DEBUG, false);
|
||||
g3::only_change_at_initialization::setLogLevel(DEBUG, false);
|
||||
EXPECT_FALSE(g3::logLevel(DEBUG));
|
||||
LOG(DEBUG) << msg_debugOff;
|
||||
auto content = logger.resetAndRetrieveContent();
|
||||
@ -521,7 +615,7 @@ TEST(DynamicLogging, DynamicLogging_No_Fatal_If_Disabled) {
|
||||
EXPECT_FALSE(mockFatalWasCalled());
|
||||
|
||||
|
||||
g3::setLogLevel(FATAL, false);
|
||||
g3::only_change_at_initialization::setLogLevel(FATAL, false);
|
||||
std::string msg3 = "This is NOT fatal (not crash, since it is unit test. FATAL is disabled";
|
||||
LOG(FATAL) << msg3;
|
||||
EXPECT_FALSE(mockFatalWasCalled());
|
||||
@ -544,7 +638,7 @@ TEST(DynamicLogging, DynamicLogging_Check_WillAlsoBeTurnedOffWhen_Fatal_Is_Disab
|
||||
EXPECT_FALSE(mockFatalWasCalled());
|
||||
|
||||
// Disable also CHECK calls
|
||||
g3::setLogLevel(FATAL, false);
|
||||
g3::only_change_at_initialization::setLogLevel(FATAL, false);
|
||||
ASSERT_FALSE(g3::logLevel(FATAL));
|
||||
LOG(FATAL) << msg3;
|
||||
EXPECT_FALSE(mockFatalWasCalled());
|
||||
@ -552,6 +646,7 @@ TEST(DynamicLogging, DynamicLogging_Check_WillAlsoBeTurnedOffWhen_Fatal_Is_Disab
|
||||
|
||||
|
||||
|
||||
|
||||
#else
|
||||
TEST(DynamicLogging, DynamicLogging_IS_NOT_ENABLED) {
|
||||
ASSERT_TRUE(g3::logLevel(DEBUG));
|
||||
|
@ -46,13 +46,13 @@ TEST(DynamicLoadOfLibrary, JustLoadAndExit) {
|
||||
EXPECT_FALSE(nullptr == factory);
|
||||
SomeLibrary* loadedLibrary = factory->CreateLibrary();
|
||||
|
||||
for (size_t i = 0; i < 300; ++i) {
|
||||
for (auto i = 0; i < 300; ++i) {
|
||||
loadedLibrary->action();
|
||||
}
|
||||
|
||||
delete loadedLibrary;
|
||||
dlclose(libHandle);
|
||||
} // scope exit. All log entries must be flushed now
|
||||
const int numberOfMessages = 2 + 300 + 1; // 2 library construction, 300 loop, 1 destoyed library
|
||||
const size_t numberOfMessages = 2 + 300 + 1; // 2 library construction, 300 loop, 1 destoyed library
|
||||
EXPECT_EQ(receiver.size(), numberOfMessages);
|
||||
}
|
||||
|
@ -121,10 +121,10 @@ namespace testing_helpers {
|
||||
_log_file = filename.get();
|
||||
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
g3::setLogLevel(INFO, true);
|
||||
g3::setLogLevel(DEBUG, true);
|
||||
g3::setLogLevel(WARNING, true);
|
||||
g3::setLogLevel(FATAL, true);
|
||||
g3::only_change_at_initialization::setLogLevel(INFO, true);
|
||||
g3::only_change_at_initialization::setLogLevel(DEBUG, true);
|
||||
g3::only_change_at_initialization::setLogLevel(WARNING, true);
|
||||
g3::only_change_at_initialization::setLogLevel(FATAL, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user