mirror of
https://github.com/KjellKod/g3log.git
synced 2024-12-12 10:23:50 +01:00
adding consistent and easy formatting (#508)
* clang format configuration file replaces sublime Astyleformatter * instructions added to pull request template * code base re-formatted to be consistent throughout.
This commit is contained in:
parent
0708f5aeb4
commit
cf91227966
83
.clang-format
Normal file
83
.clang-format
Normal file
@ -0,0 +1,83 @@
|
||||
# Google C/C++ Code Style settings
|
||||
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
# Author: Kehan Xue, kehan.xue (at) gmail.com
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
AccessModifierOffset: -1
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignOperands: Align
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortIfStatementsOnASingleLine: Never # To avoid conflict, set this "Never" and each "if statement" should include brace when coding
|
||||
AllowShortLambdasOnASingleLine: Inline
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: true
|
||||
PackConstructorInitializers: Never
|
||||
BreakBeforeBraces: Attach
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterStruct: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: AfterColon
|
||||
BreakInheritanceList: BeforeColon
|
||||
ColumnLimit: 0
|
||||
CompactNamespaces: false
|
||||
ContinuationIndentWidth: 3
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false # Make sure the * or & align on the left
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
FixNamespaceComments: true
|
||||
IncludeBlocks: Preserve
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 3
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: All
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PointerAlignment: Left
|
||||
ReflowComments: false
|
||||
# SeparateDefinitionBlocks: Always # Only support since clang-format 14
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: c++11
|
||||
TabWidth: 3
|
||||
UseTab: Never
|
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"cmake.configureOnOpen": false,
|
||||
"editor.formatOnSave": true
|
||||
}
|
@ -3,16 +3,18 @@
|
||||
|
||||
`ADD CONTENT HERE TO DESCRIBE THE PURPOSE OF THE PULL REQUEST`
|
||||
|
||||
|
||||
# Formatting
|
||||
- [ ] I am following the formatting style of the existing codebase.
|
||||
|
||||
_a clang-format configuration file is available in the root of g3log_
|
||||
|
||||
# Testing
|
||||
|
||||
- [ ] This new/modified code was covered by unit tests.
|
||||
|
||||
- [ ] (insight) Was all tests written using TDD (Test Driven Development) style?
|
||||
|
||||
- [ ] The CI (Windows, Linux, OSX) are working without issues.
|
||||
|
||||
- [ ] Was new functionality documented?
|
||||
|
||||
- [ ] The testing steps 1 - 2 below were followed
|
||||
|
||||
_step 1_
|
||||
|
@ -213,7 +213,7 @@ will install the g3log library to `CPACK_PACKAGING_INSTALL_PREFIX`.
|
||||
|
||||
## <a name="testing">Testing</a>
|
||||
|
||||
By default, tests will not be built. To enable unit testing, you should turn on `ADD_G3LOG_UNIT_TEST`.
|
||||
By default, tests will be built. To disable unit testing, you should turn off `ADD_G3LOG_UNIT_TEST`.
|
||||
|
||||
Suppose the build process has completed, then you can run the tests with:
|
||||
```
|
||||
|
@ -9,34 +9,29 @@
|
||||
#include <g3log/g3log.hpp>
|
||||
#include <g3log/logworker.hpp>
|
||||
#include <iomanip>
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace {
|
||||
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
||||
const std::string path_to_log_file = "./";
|
||||
#else
|
||||
const std::string path_to_log_file = "/tmp/";
|
||||
#endif
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace example_fatal
|
||||
{
|
||||
void killWithContractIfNonEqual(int first, int second)
|
||||
{
|
||||
namespace example_fatal {
|
||||
void killWithContractIfNonEqual(int first, int second) {
|
||||
CHECK(first == second) << "Test to see if contract works: onetwothree: " << 123 << ". This should be at the end of the log, and will exit this example";
|
||||
}
|
||||
} // example fatal
|
||||
} // namespace example_fatal
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char** argv) {
|
||||
double pi_d = 3.1415926535897932384626433832795;
|
||||
float pi_f = 3.1415926535897932384626433832795f;
|
||||
|
||||
auto worker = g3::LogWorker::createLogWorker();
|
||||
auto handle= worker->addDefaultLogger(argv[0], path_to_log_file);
|
||||
auto handle = worker->addDefaultLogger(argv[0], path_to_log_file);
|
||||
g3::initializeLogging(worker.get());
|
||||
std::future<std::string> log_file_name = handle->call(&g3::FileSink::fileName);
|
||||
|
||||
@ -49,11 +44,11 @@ int main(int argc, char **argv)
|
||||
changeFormatting.wait();
|
||||
changeHeader.wait();
|
||||
|
||||
|
||||
std::cout << "* This is an example of g3log. It WILL exit by a failed CHECK(...)" << std::endl;
|
||||
std::cout << "* that acts as a FATAL trigger. Please see the generated log and " << std::endl;
|
||||
std::cout << "* compare to the code at:\n* \t g3log/test_example/main_contract.cpp" << std::endl;
|
||||
std::cout << "*\n* Log file: [" << log_file_name.get() << "]\n\n" << std::endl;
|
||||
std::cout << "*\n* Log file: [" << log_file_name.get() << "]\n\n"
|
||||
<< std::endl;
|
||||
|
||||
LOGF(INFO, "Hi log %d", 123);
|
||||
LOG(INFO) << "Test SLOG INFO";
|
||||
@ -72,4 +67,3 @@ int main(int argc, char **argv)
|
||||
int larger = 2;
|
||||
example_fatal::killWithContractIfNonEqual(smaller, larger);
|
||||
}
|
||||
|
||||
|
@ -9,14 +9,14 @@
|
||||
#include <g3log/g3log.hpp>
|
||||
#include <g3log/logworker.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <cctype>
|
||||
#include <future>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <exception>
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#define NOEXCEPT noexcept
|
||||
@ -24,17 +24,15 @@
|
||||
#define NOEXCEPT throw()
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace {
|
||||
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
||||
const std::string path_to_log_file = "./";
|
||||
#else
|
||||
const std::string path_to_log_file = "/tmp/";
|
||||
#endif
|
||||
|
||||
void ToLower(std::string &str)
|
||||
{
|
||||
for (auto &character : str) {
|
||||
void ToLower(std::string& str) {
|
||||
for (auto& character : str) {
|
||||
character = std::tolower(character);
|
||||
}
|
||||
}
|
||||
@ -96,10 +94,9 @@ namespace
|
||||
LOG(WARNING) << "Expected to have died by now...";
|
||||
}
|
||||
|
||||
|
||||
void AccessViolation() {
|
||||
LOG(G3LOG_DEBUG) << " trigger exit";
|
||||
char *ptr = 0;
|
||||
char* ptr = 0;
|
||||
LOG(INFO) << "Death by access violation is imminent";
|
||||
*ptr = 0;
|
||||
LOG(WARNING) << "Expected to have died by now...";
|
||||
@ -119,8 +116,7 @@ namespace
|
||||
f2.wait();
|
||||
}
|
||||
|
||||
|
||||
using deathfunc = void (*) (void);
|
||||
using deathfunc = void (*)(void);
|
||||
void Death_x10000(deathfunc func, std::string funcname) NOEXCEPT {
|
||||
LOG(G3LOG_DEBUG) << " trigger exit";
|
||||
std::vector<std::future<void>> asyncs;
|
||||
@ -136,7 +132,6 @@ namespace
|
||||
std::cout << __FUNCTION__ << " unexpected result. Death by " << funcname << " did not crash and exit the system" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void Throw() NOEXCEPT {
|
||||
LOG(G3LOG_DEBUG) << " trigger exit";
|
||||
std::future<int> empty;
|
||||
@ -145,10 +140,12 @@ namespace
|
||||
// example of std::exceptions can be found here: http://en.cppreference.com/w/cpp/error/exception
|
||||
}
|
||||
|
||||
|
||||
void SegFaultAttempt_x10000() NOEXCEPT {
|
||||
|
||||
deathfunc f = []{char* ptr = 0; *ptr = 1; };
|
||||
deathfunc f = [] {
|
||||
char* ptr = 0;
|
||||
*ptr = 1;
|
||||
};
|
||||
Death_x10000(f, "throw uncaught exception... and then some sigsegv calls");
|
||||
}
|
||||
|
||||
@ -169,28 +166,57 @@ namespace
|
||||
CallActualExitFunction(fatal_function);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ExecuteDeathFunction(const bool runInNewThread, int fatalChoice) {
|
||||
LOG(G3LOG_DEBUG) << "trigger exit";
|
||||
|
||||
auto exitFunction = &NoExitFunction;
|
||||
switch (fatalChoice) {
|
||||
case 1: exitFunction = &RaiseSIGABRT; break;
|
||||
case 2: exitFunction = &RaiseSIGFPE; break;
|
||||
case 3: exitFunction = &RaiseSIGSEGV; break;
|
||||
case 4: exitFunction = &RaiseSIGILL; break;
|
||||
case 5: exitFunction = &RAiseSIGTERM; break;
|
||||
case 6: exitFunction = &DivisionByZero; gShouldBeZero = 0; DivisionByZero(); break;
|
||||
case 7: exitFunction = &IllegalPrintf; break;
|
||||
case 8: exitFunction = &OutOfBoundsArrayIndexing; break;
|
||||
case 9: exitFunction = &AccessViolation; break;
|
||||
case 10: exitFunction = &RaiseSIGABRTAndAccessViolation; break;
|
||||
case 11: exitFunction = &Throw; break;
|
||||
case 12: exitFunction = &FailedCHECK; break;
|
||||
case 13: exitFunction = &AccessViolation_x10000; break;
|
||||
case 14: exitFunction = &SegFaultAttempt_x10000; break;
|
||||
default: break;
|
||||
case 1:
|
||||
exitFunction = &RaiseSIGABRT;
|
||||
break;
|
||||
case 2:
|
||||
exitFunction = &RaiseSIGFPE;
|
||||
break;
|
||||
case 3:
|
||||
exitFunction = &RaiseSIGSEGV;
|
||||
break;
|
||||
case 4:
|
||||
exitFunction = &RaiseSIGILL;
|
||||
break;
|
||||
case 5:
|
||||
exitFunction = &RAiseSIGTERM;
|
||||
break;
|
||||
case 6:
|
||||
exitFunction = &DivisionByZero;
|
||||
gShouldBeZero = 0;
|
||||
DivisionByZero();
|
||||
break;
|
||||
case 7:
|
||||
exitFunction = &IllegalPrintf;
|
||||
break;
|
||||
case 8:
|
||||
exitFunction = &OutOfBoundsArrayIndexing;
|
||||
break;
|
||||
case 9:
|
||||
exitFunction = &AccessViolation;
|
||||
break;
|
||||
case 10:
|
||||
exitFunction = &RaiseSIGABRTAndAccessViolation;
|
||||
break;
|
||||
case 11:
|
||||
exitFunction = &Throw;
|
||||
break;
|
||||
case 12:
|
||||
exitFunction = &FailedCHECK;
|
||||
break;
|
||||
case 13:
|
||||
exitFunction = &AccessViolation_x10000;
|
||||
break;
|
||||
case 14:
|
||||
exitFunction = &SegFaultAttempt_x10000;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (runInNewThread) {
|
||||
auto dieInNearFuture = std::async(std::launch::async, CallExitFunction, exitFunction);
|
||||
@ -200,12 +226,10 @@ namespace
|
||||
}
|
||||
|
||||
std::string unexpected = "Expected to exit by FATAL event. That did not happen (printf choice in Windows?).";
|
||||
unexpected.append("Choice was: ").append(std::to_string(fatalChoice)).append(", async?: ")
|
||||
.append(std::to_string(runInNewThread)).append("\n\n***** TEST WILL RUN AGAIN *****\n\n");
|
||||
unexpected.append("Choice was: ").append(std::to_string(fatalChoice)).append(", async?: ").append(std::to_string(runInNewThread)).append("\n\n***** TEST WILL RUN AGAIN *****\n\n");
|
||||
|
||||
std::cerr << unexpected << std::endl;
|
||||
LOG(WARNING) << unexpected;
|
||||
|
||||
}
|
||||
|
||||
bool AskForAsyncDeath() {
|
||||
@ -224,8 +248,6 @@ namespace
|
||||
return ("yes" == option);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ChoiceOfFatalExit() {
|
||||
std::string option;
|
||||
int choice = {0};
|
||||
@ -287,10 +309,9 @@ void breakHere() {
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char** argv) {
|
||||
auto worker = g3::LogWorker::createLogWorker();
|
||||
auto handle= worker->addDefaultLogger(argv[0], path_to_log_file);
|
||||
auto handle = worker->addDefaultLogger(argv[0], path_to_log_file);
|
||||
g3::initializeLogging(worker.get());
|
||||
g3::setFatalPreLoggingHook(&breakHere);
|
||||
std::future<std::string> log_file_name = handle->call(&g3::FileSink::fileName);
|
||||
@ -298,8 +319,8 @@ int main(int argc, char **argv)
|
||||
std::cout << "**** G3LOG FATAL EXAMPLE ***\n\n"
|
||||
<< "Choose your type of fatal exit, then "
|
||||
<< " read the generated log and backtrace.\n"
|
||||
<< "The logfile is generated at: [" << log_file_name.get() << "]\n\n" << std::endl;
|
||||
|
||||
<< "The logfile is generated at: [" << log_file_name.get() << "]\n\n"
|
||||
<< std::endl;
|
||||
|
||||
LOGF(G3LOG_DEBUG, "Fatal exit example starts now, it's as easy as %d", 123);
|
||||
LOG(INFO) << "Feel free to read the source code also in g3log/example/main_fatal_choice.cpp";
|
||||
@ -311,6 +332,4 @@ int main(int argc, char **argv)
|
||||
LOG(WARNING) << "Expected to exit by fatal event, this code line should never be reached";
|
||||
CHECK(false) << "Forced death";
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
@ -10,62 +10,54 @@
|
||||
#include <g3log/logworker.hpp>
|
||||
|
||||
#include <iomanip>
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
namespace
|
||||
{
|
||||
#include <thread>
|
||||
namespace {
|
||||
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
||||
const std::string path_to_log_file = "./";
|
||||
#else
|
||||
const std::string path_to_log_file = "/tmp/";
|
||||
#endif
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace example_fatal
|
||||
{
|
||||
namespace example_fatal {
|
||||
// on Ubunti this caused get a compiler warning with gcc4.6
|
||||
// from gcc 4.7.2 (at least) it causes a crash (as expected)
|
||||
// On windows it'll probably crash too.
|
||||
void tryToKillWithIllegalPrintout()
|
||||
{
|
||||
std::cout << "\n\n***** Be ready this last example may 'abort' if on Windows/Linux_gcc4.7 " << std::endl << std::flush;
|
||||
std::cout << "************************************************************\n\n" << std::endl << std::flush;
|
||||
void tryToKillWithIllegalPrintout() {
|
||||
std::cout << "\n\n***** Be ready this last example may 'abort' if on Windows/Linux_gcc4.7 " << std::endl
|
||||
<< std::flush;
|
||||
std::cout << "************************************************************\n\n"
|
||||
<< std::endl
|
||||
<< std::flush;
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
const std::string logging = "logging";
|
||||
LOGF(G3LOG_DEBUG, "ILLEGAL PRINTF_SYNTAX EXAMPLE. WILL GENERATE compiler warning.\n\nbadly formatted message:[Printf-type %s is the number 1 for many %s]", logging.c_str());
|
||||
}
|
||||
|
||||
|
||||
// The function above 'tryToKillWithIllegalPrintout' IS system / compiler dependent. Older compilers sometimes did NOT generate a SIGSEGV
|
||||
// fault as expected by the illegal printf-format usage. just in case we exit by zero division"
|
||||
void killByZeroDivision(int value)
|
||||
{
|
||||
void killByZeroDivision(int value) {
|
||||
int zero = 0; // trying to fool the compiler to automatically warn
|
||||
LOG(INFO) << "This is a bad operation [value/zero] : " << value / zero;
|
||||
}
|
||||
|
||||
|
||||
void tryToKillWithAccessingIllegalPointer(std::unique_ptr<std::string> badStringPtr) {
|
||||
auto badPtr = std::move(badStringPtr);
|
||||
LOG(INFO) << "Function calls through a nullptr object will trigger SIGSEGV";
|
||||
badStringPtr->append("crashing");
|
||||
}
|
||||
|
||||
} // namespace example_fatal
|
||||
|
||||
} // example fatal
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char** argv) {
|
||||
double pi_d = 3.1415926535897932384626433832795;
|
||||
float pi_f = 3.1415926535897932384626433832795f;
|
||||
|
||||
using namespace g3;
|
||||
|
||||
|
||||
std::unique_ptr<LogWorker> logworker {LogWorker::createLogWorker()};
|
||||
std::unique_ptr<LogWorker> logworker{LogWorker::createLogWorker()};
|
||||
auto sinkHandle = logworker->addSink(std::make_unique<FileSink>(argv[0], path_to_log_file),
|
||||
&FileSink::fileWrite);
|
||||
|
||||
@ -74,8 +66,8 @@ int main(int argc, char **argv)
|
||||
std::cout << "* This is an example of g3log. It WILL exit by a FATAL trigger" << std::endl;
|
||||
std::cout << "* Please see the generated log and compare to the code at" << std::endl;
|
||||
std::cout << "* g3log/test_example/main.cpp" << std::endl;
|
||||
std::cout << "*\n* Log file: [" << log_file_name.get() << "]\n\n" << std::endl;
|
||||
|
||||
std::cout << "*\n* Log file: [" << log_file_name.get() << "]\n\n"
|
||||
<< std::endl;
|
||||
|
||||
LOGF(INFO, "Hi log %d", 123);
|
||||
LOG(INFO) << "Test SLOG INFO";
|
||||
|
@ -7,27 +7,26 @@
|
||||
* ============================================================================*/
|
||||
|
||||
#include "g3log/crashhandler.hpp"
|
||||
#include "g3log/logmessage.hpp"
|
||||
#include "g3log/logcapture.hpp"
|
||||
#include "g3log/loglevels.hpp"
|
||||
#include "g3log/logmessage.hpp"
|
||||
|
||||
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
||||
#error "crashhandler_unix.cpp used but it's a windows system"
|
||||
#endif
|
||||
|
||||
|
||||
#include <csignal>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <execinfo.h>
|
||||
#include <cxxabi.h>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <execinfo.h>
|
||||
#include <unistd.h>
|
||||
#include <atomic>
|
||||
#include <csignal>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
// Linux/Clang, OSX/Clang, OSX/gcc
|
||||
#if (defined(__clang__) || defined(__APPLE__))
|
||||
@ -36,10 +35,9 @@
|
||||
#include <ucontext.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
std::atomic<bool> gBlockForFatal {true};
|
||||
std::atomic<bool> gBlockForFatal{true};
|
||||
|
||||
const std::map<int, std::string> kSignals = {
|
||||
{SIGABRT, "SIGABRT"},
|
||||
@ -99,7 +97,7 @@ namespace {
|
||||
// do it verbose style - install all signal actions
|
||||
for (const auto& sig_pair : gSignals) {
|
||||
struct sigaction old_action;
|
||||
memset(&old_action, 0, sizeof (old_action));
|
||||
memset(&old_action, 0, sizeof(old_action));
|
||||
|
||||
if (sigaction(sig_pair.first, &action, &old_action) < 0) {
|
||||
std::string signalerror = "sigaction - " + sig_pair.second;
|
||||
@ -111,15 +109,8 @@ namespace {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Redirecting and using signals. In case of fatal signals g3log should log the fatal signal
|
||||
// and flush the log queue and then "rethrow" the signal to exit
|
||||
namespace g3 {
|
||||
@ -160,23 +151,18 @@ namespace g3 {
|
||||
/// first look for format that includes brackets "(mangled_name+offset)""
|
||||
const auto firstBracket = strMessage.find_last_of('(');
|
||||
const auto secondBracket = strMessage.find_last_of(')');
|
||||
if (firstBracket != strMessage.npos && secondBracket != strMessage.npos)
|
||||
{
|
||||
if (firstBracket != strMessage.npos && secondBracket != strMessage.npos) {
|
||||
const auto betweenBrackets = strMessage.substr(firstBracket + 1, secondBracket - firstBracket - 1);
|
||||
const auto plusSign = betweenBrackets.find_first_of('+');
|
||||
if (plusSign != betweenBrackets.npos)
|
||||
{
|
||||
if (plusSign != betweenBrackets.npos) {
|
||||
mangled_name = betweenBrackets.substr(0, plusSign);
|
||||
offset = betweenBrackets.substr(plusSign + 1, betweenBrackets.npos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/// we did not found brackets, looking for "_mangled_name + offset"
|
||||
const auto plusSign = strMessage.find_first_of('+');
|
||||
const auto lastUnderscore = strMessage.rfind(" _");
|
||||
if (plusSign != strMessage.npos && lastUnderscore != strMessage.npos)
|
||||
{
|
||||
if (plusSign != strMessage.npos && lastUnderscore != strMessage.npos) {
|
||||
mangled_name = strMessage.substr(lastUnderscore + 1, plusSign - lastUnderscore - 2);
|
||||
offset = strMessage.substr(plusSign + 2, strMessage.npos);
|
||||
}
|
||||
@ -188,10 +174,10 @@ namespace g3 {
|
||||
char* real_name = abi::__cxa_demangle(mangled_name.c_str(), 0, 0, &status);
|
||||
// if demangling is successful, output the demangled function name
|
||||
if (status == 0) {
|
||||
oss << "\tstack dump [" << idx << "] " << real_name << " + " << offset<< std::endl;
|
||||
}// otherwise, output the mangled function name
|
||||
oss << "\tstack dump [" << idx << "] " << real_name << " + " << offset << std::endl;
|
||||
} // otherwise, output the mangled function name
|
||||
else {
|
||||
oss << "\tstack dump [" << idx << "] " << mangled_name << " + " << offset<< std::endl;
|
||||
oss << "\tstack dump [" << idx << "] " << mangled_name << " + " << offset << std::endl;
|
||||
}
|
||||
free(real_name); // mallocated by abi::__cxa_demangle(...)
|
||||
} else {
|
||||
@ -203,22 +189,25 @@ namespace g3 {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// string representation of signal ID
|
||||
std::string exitReasonName(const LEVELS& level, g3::SignalType fatal_id) {
|
||||
|
||||
int signal_number = static_cast<int>(fatal_id);
|
||||
switch (signal_number) {
|
||||
case SIGABRT: return "SIGABRT";
|
||||
case SIGABRT:
|
||||
return "SIGABRT";
|
||||
break;
|
||||
case SIGFPE: return "SIGFPE";
|
||||
case SIGFPE:
|
||||
return "SIGFPE";
|
||||
break;
|
||||
case SIGSEGV: return "SIGSEGV";
|
||||
case SIGSEGV:
|
||||
return "SIGSEGV";
|
||||
break;
|
||||
case SIGILL: return "SIGILL";
|
||||
case SIGILL:
|
||||
return "SIGILL";
|
||||
break;
|
||||
case SIGTERM: return "SIGTERM";
|
||||
case SIGTERM:
|
||||
return "SIGTERM";
|
||||
break;
|
||||
default:
|
||||
std::ostringstream oss;
|
||||
@ -227,8 +216,6 @@ namespace g3 {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Triggered by g3log->g3LogWorker after receiving a FATAL trigger
|
||||
// which is LOG(FATAL), CHECK(false) or a fatal signal our signalhandler caught.
|
||||
// --- If LOG(FATAL) or CHECK(false) the signal_number will be SIGABRT
|
||||
@ -241,8 +228,9 @@ namespace g3 {
|
||||
restoreSignalHandler(sig.first);
|
||||
}
|
||||
|
||||
std::cerr << "\n\n" << __FUNCTION__ << ":" << __LINE__ << ". Exiting due to " << level.text << ", " << signal_number << " \n\n" << std::flush;
|
||||
|
||||
std::cerr << "\n\n"
|
||||
<< __FUNCTION__ << ":" << __LINE__ << ". Exiting due to " << level.text << ", " << signal_number << " \n\n"
|
||||
<< std::flush;
|
||||
|
||||
raise(signal_number);
|
||||
|
||||
@ -252,7 +240,6 @@ namespace g3 {
|
||||
gBlockForFatal = false;
|
||||
|
||||
exit(signal_number);
|
||||
|
||||
}
|
||||
|
||||
// restores the signal handler back to default
|
||||
@ -262,10 +249,7 @@ namespace g3 {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end g3::internal
|
||||
|
||||
} // namespace internal
|
||||
|
||||
std::string signalToStr(int signal_number) {
|
||||
std::string signal_name;
|
||||
@ -281,7 +265,6 @@ namespace g3 {
|
||||
return signal_name;
|
||||
}
|
||||
|
||||
|
||||
void restoreSignalHandler(int signal_number) {
|
||||
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
|
||||
auto old_action_it = gSavedSigActions.find(signal_number);
|
||||
@ -298,7 +281,6 @@ namespace g3 {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// This will override the default signal handler setup and instead
|
||||
// install a custom set of signals to handle
|
||||
void overrideSetupSignals(const std::map<int, std::string> overrideSignals) {
|
||||
@ -312,7 +294,6 @@ namespace g3 {
|
||||
installCrashHandler(); // installs all the signal handling for gSignals
|
||||
}
|
||||
|
||||
|
||||
// installs the signal handling for whatever signal set that is currently active
|
||||
// If you want to setup your own signal handling then
|
||||
// You should instead call overrideSetupSignals()
|
||||
|
@ -10,20 +10,20 @@
|
||||
#error "crashhandler_windows.cpp used but not on a windows system"
|
||||
#endif
|
||||
|
||||
#include <process.h> // getpid
|
||||
#include <windows.h>
|
||||
#include <atomic>
|
||||
#include <csignal>
|
||||
#include <sstream>
|
||||
#include <atomic>
|
||||
#include <process.h> // getpid
|
||||
#include "g3log/g3log.hpp"
|
||||
#include "g3log/crashhandler.hpp"
|
||||
#include "g3log/stacktrace_windows.hpp"
|
||||
#include "g3log/g3log.hpp"
|
||||
#include "g3log/logcapture.hpp"
|
||||
#include "g3log/stacktrace_windows.hpp"
|
||||
|
||||
#define getpid _getpid
|
||||
|
||||
namespace {
|
||||
std::atomic<bool> gBlockForFatal {true};
|
||||
std::atomic<bool> gBlockForFatal{true};
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER g_previous_unexpected_exception_handler = nullptr;
|
||||
|
||||
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
|
||||
@ -34,8 +34,6 @@ namespace {
|
||||
void* g_vector_exception_handler = nullptr;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// called for fatal signals SIGABRT, SIGFPE, SIGSEGV, SIGILL, SIGTERM
|
||||
void signalHandler(int signal_number) {
|
||||
using namespace g3::internal;
|
||||
@ -45,7 +43,6 @@ namespace {
|
||||
fatal_stream << "\n***** Received fatal signal " << g3::internal::exitReasonName(g3::internal::FATAL_SIGNAL, signal_number);
|
||||
fatal_stream << "(" << signal_number << ")\tPID: " << getpid() << std::endl;
|
||||
|
||||
|
||||
LogCapture trigger(FATAL_SIGNAL, static_cast<g3::SignalType>(signal_number), dump.c_str());
|
||||
trigger.stream() << fatal_stream.str();
|
||||
|
||||
@ -61,8 +58,6 @@ namespace {
|
||||
#endif
|
||||
} // scope exit - message sent to LogWorker, wait to die...
|
||||
|
||||
|
||||
|
||||
// Unhandled exception catching
|
||||
LONG WINAPI exceptionHandling(EXCEPTION_POINTERS* info, const std::string& handler) {
|
||||
std::string dump = stacktrace::stackdump(info);
|
||||
@ -84,14 +79,12 @@ namespace {
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
|
||||
// Unhandled exception catching
|
||||
LONG WINAPI unexpectedExceptionHandling(EXCEPTION_POINTERS* info) {
|
||||
g3::internal::restoreFatalHandlingToDefault();
|
||||
return exceptionHandling(info, "Unexpected Exception Handler");
|
||||
}
|
||||
|
||||
|
||||
/// Setup through (Windows API) AddVectoredExceptionHandler
|
||||
/// Ref: http://blogs.msdn.com/b/zhanli/archive/2010/06/25/c-tips-addvectoredexceptionhandler-addvectoredcontinuehandler-and-setunhandledexceptionfilter.aspx
|
||||
#if !(defined(DISABLE_VECTORED_EXCEPTIONHANDLING))
|
||||
@ -110,7 +103,6 @@ namespace {
|
||||
#endif
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
namespace g3 {
|
||||
namespace internal {
|
||||
// For windows exceptions this might ONCE be set to false, in case of a
|
||||
@ -119,7 +111,6 @@ namespace g3 {
|
||||
return gBlockForFatal;
|
||||
}
|
||||
|
||||
|
||||
/// Generate stackdump. Or in case a stackdump was pre-generated and
|
||||
/// non-empty just use that one. i.e. the latter case is only for
|
||||
/// Windows and test purposes
|
||||
@ -131,8 +122,6 @@ namespace g3 {
|
||||
return stacktrace::stackdump();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// string representation of signal ID or Windows exception id
|
||||
std::string exitReasonName(const LEVELS& level, g3::SignalType fatal_id) {
|
||||
if (level == g3::internal::FATAL_EXCEPTION) {
|
||||
@ -140,11 +129,21 @@ namespace g3 {
|
||||
}
|
||||
|
||||
switch (fatal_id) {
|
||||
case SIGABRT: return "SIGABRT"; break;
|
||||
case SIGFPE: return "SIGFPE"; break;
|
||||
case SIGSEGV: return "SIGSEGV"; break;
|
||||
case SIGILL: return "SIGILL"; break;
|
||||
case SIGTERM: return "SIGTERM"; break;
|
||||
case SIGABRT:
|
||||
return "SIGABRT";
|
||||
break;
|
||||
case SIGFPE:
|
||||
return "SIGFPE";
|
||||
break;
|
||||
case SIGSEGV:
|
||||
return "SIGSEGV";
|
||||
break;
|
||||
case SIGILL:
|
||||
return "SIGILL";
|
||||
break;
|
||||
case SIGTERM:
|
||||
return "SIGTERM";
|
||||
break;
|
||||
default:
|
||||
std::ostringstream oss;
|
||||
oss << "UNKNOWN SIGNAL(" << fatal_id << ")";
|
||||
@ -152,7 +151,6 @@ namespace g3 {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Triggered by g3log::LogWorker after receiving a FATAL trigger
|
||||
// which is LOG(FATAL), CHECK(false) or a fatal signal our signalhandler caught.
|
||||
// --- If LOG(FATAL) or CHECK(false) the signal_number will be SIGABRT
|
||||
@ -173,17 +171,15 @@ namespace g3 {
|
||||
raise(signal_number);
|
||||
}
|
||||
|
||||
|
||||
// Restore back to default fatal event handling
|
||||
void restoreFatalHandlingToDefault() {
|
||||
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
|
||||
SetUnhandledExceptionFilter (g_previous_unexpected_exception_handler);
|
||||
SetUnhandledExceptionFilter(g_previous_unexpected_exception_handler);
|
||||
|
||||
#if !(defined(DISABLE_VECTORED_EXCEPTIONHANDLING))
|
||||
RemoveVectoredExceptionHandler (g_vector_exception_handler);
|
||||
RemoveVectoredExceptionHandler(g_vector_exception_handler);
|
||||
#endif
|
||||
|
||||
|
||||
if (SIG_ERR == signal(SIGABRT, SIG_DFL))
|
||||
perror("signal - SIGABRT");
|
||||
|
||||
@ -201,14 +197,11 @@ namespace g3 {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void installSignalHandler() {
|
||||
g3::installSignalHandlerForThread();
|
||||
}
|
||||
|
||||
|
||||
} // end g3::internal
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// SIGFPE, SIGILL, and SIGSEGV handling must be installed per thread
|
||||
/// on Windows. This is automatically done if you do at least one LOG(...) call
|
||||
|
@ -7,23 +7,22 @@
|
||||
* ============================================================================*/
|
||||
|
||||
#include "g3log/filesink.hpp"
|
||||
#include "filesinkhelper.ipp"
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include "filesinkhelper.ipp"
|
||||
|
||||
namespace g3 {
|
||||
using namespace internal;
|
||||
|
||||
FileSink::FileSink(const std::string &log_prefix, const std::string &log_directory, const std::string& logger_id, size_t write_to_log_every_x_message)
|
||||
: _log_details_func(&LogMessage::DefaultLogDetailsToString)
|
||||
,_log_file_with_path(log_directory)
|
||||
, _log_prefix_backup(log_prefix)
|
||||
, _outptr(new std::ofstream)
|
||||
, _header("\t\tLOG format: [YYYY/MM/DD hh:mm:ss uuu* LEVEL FILE->FUNCTION:LINE] message\n\n\t\t(uuu*: microseconds fractions of the seconds value)\n\n")
|
||||
, _firstEntry(true)
|
||||
, _write_counter(0)
|
||||
, _write_to_log_every_x_message(write_to_log_every_x_message)
|
||||
{
|
||||
FileSink::FileSink(const std::string& log_prefix, const std::string& log_directory, const std::string& logger_id, size_t write_to_log_every_x_message) :
|
||||
_log_details_func(&LogMessage::DefaultLogDetailsToString),
|
||||
_log_file_with_path(log_directory),
|
||||
_log_prefix_backup(log_prefix),
|
||||
_outptr(new std::ofstream),
|
||||
_header("\t\tLOG format: [YYYY/MM/DD hh:mm:ss uuu* LEVEL FILE->FUNCTION:LINE] message\n\n\t\t(uuu*: microseconds fractions of the seconds value)\n\n"),
|
||||
_firstEntry(true),
|
||||
_write_counter(0),
|
||||
_write_to_log_every_x_message(write_to_log_every_x_message) {
|
||||
_log_prefix_backup = prefixSanityFix(log_prefix);
|
||||
if (!isValidFilename(_log_prefix_backup)) {
|
||||
std::cerr << "g3log: forced abort due to illegal log prefix [" << log_prefix << "]" << std::endl;
|
||||
@ -42,7 +41,6 @@ namespace g3 {
|
||||
assert(_outptr && "cannot open log file at startup");
|
||||
}
|
||||
|
||||
|
||||
FileSink::~FileSink() {
|
||||
std::string exit_msg = {"g3log g3FileSink shutdown at: "};
|
||||
auto now = std::chrono::system_clock::now();
|
||||
@ -57,7 +55,7 @@ namespace g3 {
|
||||
|
||||
// The actual log receiving function
|
||||
void FileSink::fileWrite(LogMessageMover message) {
|
||||
if (_firstEntry ) {
|
||||
if (_firstEntry) {
|
||||
addLogFileHeader();
|
||||
_firstEntry = false;
|
||||
}
|
||||
@ -71,7 +69,7 @@ namespace g3 {
|
||||
}
|
||||
}
|
||||
|
||||
std::string FileSink::changeLogFile(const std::string &directory, const std::string &logger_id) {
|
||||
std::string FileSink::changeLogFile(const std::string& directory, const std::string& logger_id) {
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto now_formatted = g3::localtime_formatted(now, {internal::date_formatted + " " + internal::time_formatted});
|
||||
@ -80,7 +78,8 @@ namespace g3 {
|
||||
std::string prospect_log = directory + file_name;
|
||||
std::unique_ptr<std::ofstream> log_stream = createLogFile(prospect_log);
|
||||
if (nullptr == log_stream) {
|
||||
filestream() << "\n" << now_formatted << " Unable to change log file. Illegal filename or busy? Unsuccessful log name was: " << prospect_log;
|
||||
filestream() << "\n"
|
||||
<< now_formatted << " Unable to change log file. Illegal filename or busy? Unsuccessful log name was: " << prospect_log;
|
||||
return {}; // no success
|
||||
}
|
||||
|
||||
@ -115,4 +114,4 @@ namespace g3 {
|
||||
void FileSink::addLogFileHeader() {
|
||||
filestream() << header(_header);
|
||||
}
|
||||
} // g3
|
||||
} // namespace g3
|
||||
|
@ -16,8 +16,7 @@
|
||||
// Btw: replacing g2log for g3log include is easy on Linux
|
||||
// find . -name "*.cpp*" -print | xargs sed -i -e 's/\g2log\.hpp/\g3log\/g3log\.hpp/g'
|
||||
|
||||
#include <g3log/g3log.hpp>
|
||||
#include <g3log/logworker.hpp>
|
||||
#include <g3log/loglevels.hpp>
|
||||
#include <g3log/filesink.hpp>
|
||||
|
||||
#include <g3log/g3log.hpp>
|
||||
#include <g3log/loglevels.hpp>
|
||||
#include <g3log/logworker.hpp>
|
||||
|
@ -19,19 +19,18 @@
|
||||
* ********************************************* */
|
||||
|
||||
#include "g3log/g3log.hpp"
|
||||
#include "g3log/logworker.hpp"
|
||||
#include "g3log/crashhandler.hpp"
|
||||
#include "g3log/logmessage.hpp"
|
||||
#include "g3log/loglevels.hpp"
|
||||
#include "g3log/logmessage.hpp"
|
||||
#include "g3log/logworker.hpp"
|
||||
|
||||
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
namespace {
|
||||
std::once_flag g_initialize_flag;
|
||||
@ -41,16 +40,11 @@ namespace {
|
||||
std::unique_ptr<g3::LogMessage> g_first_uninitialized_msg = {nullptr};
|
||||
std::once_flag g_set_first_uninitialized_flag;
|
||||
std::once_flag g_save_first_uninitialized_flag;
|
||||
const std::function<void(void)> g_pre_fatal_hook_that_does_nothing = [] { /*does nothing */};
|
||||
const std::function<void(void)> g_pre_fatal_hook_that_does_nothing = [] { /*does nothing */ };
|
||||
std::function<void(void)> g_fatal_pre_logging_hook;
|
||||
|
||||
|
||||
std::atomic<size_t> g_fatal_hook_recursive_counter = {0};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace g3 {
|
||||
// signalhandler and internal clock is only needed to install once
|
||||
@ -76,7 +70,7 @@ namespace g3 {
|
||||
// Save the first uninitialized message, if any
|
||||
std::call_once(g_save_first_uninitialized_flag, [&bgworker] {
|
||||
if (g_first_uninitialized_msg) {
|
||||
bgworker->save(LogMessagePtr {std::move(g_first_uninitialized_msg)});
|
||||
bgworker->save(LogMessagePtr{std::move(g_first_uninitialized_msg)});
|
||||
}
|
||||
});
|
||||
|
||||
@ -88,7 +82,6 @@ namespace g3 {
|
||||
g_fatal_hook_recursive_counter.store(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* default does nothing, @ref ::g_pre_fatal_hook_that_does_nothing
|
||||
* It will be called just before sending the fatal message, @ref pushFatalmessageToLogger
|
||||
@ -101,21 +94,17 @@ namespace g3 {
|
||||
g_fatal_pre_logging_hook = pre_fatal_hook;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// By default this function pointer goes to \ref pushFatalMessageToLogger;
|
||||
std::function<void(FatalMessagePtr) > g_fatal_to_g3logworker_function_ptr = internal::pushFatalMessageToLogger;
|
||||
std::function<void(FatalMessagePtr)> g_fatal_to_g3logworker_function_ptr = internal::pushFatalMessageToLogger;
|
||||
|
||||
/** REPLACE fatalCallToLogger for fatalCallForUnitTest
|
||||
* This function switches the function pointer so that only
|
||||
* 'unitTest' mock-fatal calls are made.
|
||||
* */
|
||||
void setFatalExitHandler(std::function<void(FatalMessagePtr) > fatal_call) {
|
||||
void setFatalExitHandler(std::function<void(FatalMessagePtr)> fatal_call) {
|
||||
g_fatal_to_g3logworker_function_ptr = fatal_call;
|
||||
}
|
||||
|
||||
|
||||
namespace internal {
|
||||
|
||||
bool isLoggingInitialized() {
|
||||
@ -129,7 +118,6 @@ 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
|
||||
@ -150,19 +138,15 @@ namespace g3 {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** explicitly copy of all input. This is makes it possibly to use g3log across dynamically loaded libraries
|
||||
* i.e. (dlopen + dlsym) */
|
||||
void saveMessage(const char* entry, const char* file, int line, const char* function, const LEVELS& level,
|
||||
const char* boolean_expression, int fatal_signal, const char* stack_trace) {
|
||||
LEVELS msgLevel {level};
|
||||
LogMessagePtr message {std::make_unique<LogMessage>(file, line, function, msgLevel)};
|
||||
LEVELS msgLevel{level};
|
||||
LogMessagePtr message{std::make_unique<LogMessage>(file, line, function, msgLevel)};
|
||||
message.get()->write().append(entry);
|
||||
message.get()->setExpression(boolean_expression);
|
||||
|
||||
|
||||
if (internal::wasFatal(level)) {
|
||||
auto fatalhook = g_fatal_pre_logging_hook;
|
||||
// In case the fatal_pre logging actually will cause a crash in its turn
|
||||
@ -177,12 +161,14 @@ namespace g3 {
|
||||
message.get()->write().append(stack_trace);
|
||||
|
||||
if (g_fatal_hook_recursive_counter.load() > 1) {
|
||||
message.get()->write()
|
||||
.append("\n\n\nWARNING\n"
|
||||
message.get()->write().append(
|
||||
"\n\n\nWARNING\n"
|
||||
"A recursive crash detected. It is likely the hook set with 'setFatalPreLoggingHook(...)' is responsible\n\n")
|
||||
.append("---First crash stacktrace: ").append(first_stack_trace).append("\n---End of first stacktrace\n");
|
||||
.append("---First crash stacktrace: ")
|
||||
.append(first_stack_trace)
|
||||
.append("\n---End of first stacktrace\n");
|
||||
}
|
||||
FatalMessagePtr fatal_message { std::make_unique<FatalMessage>(*(message._move_only.get()), fatal_signal) };
|
||||
FatalMessagePtr fatal_message{std::make_unique<FatalMessage>(*(message._move_only.get()), fatal_signal)};
|
||||
// At destruction, flushes fatal message to g3LogWorker
|
||||
// either we will stay here until the background worker has received the fatal
|
||||
// message, flushed the crash message to the sinks and exits with the same fatal signal
|
||||
@ -230,7 +216,8 @@ namespace g3 {
|
||||
std::ostringstream error;
|
||||
error << "FATAL CALL but logger is NOT initialized\n"
|
||||
<< "CAUSE: " << message.get()->reason()
|
||||
<< "\nMessage: \n" << message.get()->toString() << std::flush;
|
||||
<< "\nMessage: \n"
|
||||
<< message.get()->toString() << std::flush;
|
||||
std::cerr << error.str() << std::flush;
|
||||
internal::exitWithDefaultSignalHandler(message.get()->_level, message.get()->_signal_id);
|
||||
}
|
||||
@ -246,9 +233,8 @@ namespace g3 {
|
||||
* define the behaviour.
|
||||
*/
|
||||
void fatalCall(FatalMessagePtr message) {
|
||||
g_fatal_to_g3logworker_function_ptr(FatalMessagePtr {std::move(message)});
|
||||
g_fatal_to_g3logworker_function_ptr(FatalMessagePtr{std::move(message)});
|
||||
}
|
||||
|
||||
|
||||
} // internal
|
||||
} // g3
|
||||
} // namespace internal
|
||||
} // namespace g3
|
||||
|
@ -19,19 +19,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include "g3log/shared_queue.hpp"
|
||||
|
||||
namespace kjellkod {
|
||||
typedef std::function<void() > Callback;
|
||||
typedef std::function<void()> Callback;
|
||||
|
||||
class Active {
|
||||
private:
|
||||
Active() : done_(false) {} // Construction ONLY through factory createActive();
|
||||
Active(const Active &) = delete;
|
||||
Active &operator=(const Active &) = delete;
|
||||
Active() :
|
||||
done_(false) {} // Construction ONLY through factory createActive();
|
||||
Active(const Active&) = delete;
|
||||
Active& operator=(const Active&) = delete;
|
||||
|
||||
void run() {
|
||||
while (!done_) {
|
||||
@ -45,10 +46,9 @@ namespace kjellkod {
|
||||
std::thread thd_;
|
||||
bool done_;
|
||||
|
||||
|
||||
public:
|
||||
virtual ~Active() {
|
||||
send([this]() noexcept { done_ = true;});
|
||||
send([this]() noexcept { done_ = true; });
|
||||
thd_.join();
|
||||
}
|
||||
|
||||
@ -64,6 +64,4 @@ namespace kjellkod {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // kjellkod
|
||||
} // namespace kjellkod
|
||||
|
@ -6,7 +6,6 @@
|
||||
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
|
||||
* ============================================================================*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
@ -16,11 +15,16 @@ namespace g3 {
|
||||
struct atomicbool {
|
||||
private:
|
||||
std::atomic<bool> value_;
|
||||
|
||||
public:
|
||||
atomicbool(): value_ {false} {}
|
||||
atomicbool(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() :
|
||||
value_{false} {}
|
||||
atomicbool(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);
|
||||
@ -36,8 +40,8 @@ namespace g3 {
|
||||
return (value_.load(std::memory_order_acquire) == rhs.value_.load(std::memory_order_acquire));
|
||||
}
|
||||
|
||||
bool value() {return value_.load(std::memory_order_acquire);}
|
||||
std::atomic<bool>& get() {return value_;}
|
||||
bool value() { return value_.load(std::memory_order_acquire); }
|
||||
std::atomic<bool>& get() { return value_; }
|
||||
};
|
||||
} // g3
|
||||
// explicit whitespace/EOF for VS15
|
||||
} // namespace g3
|
||||
// explicit whitespace/EOF for VS15
|
@ -8,10 +8,10 @@
|
||||
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
|
||||
* ============================================================================*/
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "g3log/loglevels.hpp"
|
||||
#include <string>
|
||||
#include "g3log/generated_definitions.hpp"
|
||||
#include "g3log/loglevels.hpp"
|
||||
|
||||
// kjell. Separera på crashhandler.hpp och crashhanlder_internal.hpp
|
||||
// implementationsfilen kan vara den samma
|
||||
@ -28,7 +28,6 @@ namespace g3 {
|
||||
SIGTERM TERMINATION (ANSI) */
|
||||
void installCrashHandler();
|
||||
|
||||
|
||||
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
||||
typedef unsigned long SignalType;
|
||||
/// SIGFPE, SIGILL, and SIGSEGV handling must be installed per thread
|
||||
@ -43,7 +42,6 @@ namespace g3 {
|
||||
// restore to whatever signal handler was used before signal handler installation
|
||||
void restoreSignalHandler(int signal_number);
|
||||
|
||||
|
||||
/// Overrides the existing signal handling for custom signals
|
||||
/// For example: usage of zcmq relies on its own signal handler for SIGTERM
|
||||
/// so users of g3log with zcmq should then use the @ref overrideSetupSignals
|
||||
@ -55,14 +53,12 @@ namespace g3 {
|
||||
void overrideSetupSignals(const std::map<int, std::string> overrideSignals);
|
||||
#endif
|
||||
|
||||
|
||||
namespace internal {
|
||||
/// Resets the fatal signal/exception handling back to default
|
||||
/// which might be needed in case it was previously overridden
|
||||
/// The default signals are: SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGTERM
|
||||
void restoreFatalHandlingToDefault();
|
||||
|
||||
|
||||
/** return whether or any fatal handling is still ongoing
|
||||
* this is used by g3log::fatalCallToLogger
|
||||
* only in the case of Windows exceptions (not fatal signals)
|
||||
@ -81,5 +77,5 @@ namespace g3 {
|
||||
* This is an internal only function. Do not use it elsewhere. It is triggered
|
||||
* from g3log, g3LogWorker after flushing messages to file */
|
||||
void exitWithDefaultSignalHandler(const LEVELS& level, g3::SignalType signal_number);
|
||||
} // end g3::internal
|
||||
} // g3
|
||||
} // namespace internal
|
||||
} // namespace g3
|
||||
|
@ -7,24 +7,23 @@
|
||||
* ============================================================================*/
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "g3log/logmessage.hpp"
|
||||
namespace g3 {
|
||||
|
||||
class FileSink {
|
||||
public:
|
||||
FileSink(const std::string &log_prefix, const std::string &log_directory, const std::string &logger_id="g3log", size_t write_to_log_every_x_message = 100);
|
||||
FileSink(const std::string& log_prefix, const std::string& log_directory, const std::string& logger_id = "g3log", size_t write_to_log_every_x_message = 100);
|
||||
virtual ~FileSink();
|
||||
|
||||
void fileWrite(LogMessageMover message);
|
||||
std::string changeLogFile(const std::string &directory, const std::string &logger_id);
|
||||
std::string changeLogFile(const std::string& directory, const std::string& logger_id);
|
||||
std::string fileName();
|
||||
void overrideLogDetails(LogMessage::LogDetailsFunc func);
|
||||
void overrideLogHeader(const std::string& change);
|
||||
|
||||
|
||||
private:
|
||||
LogMessage::LogDetailsFunc _log_details_func;
|
||||
std::string _log_file_with_path;
|
||||
@ -37,14 +36,11 @@ namespace g3 {
|
||||
size_t _write_to_log_every_x_message;
|
||||
|
||||
void addLogFileHeader();
|
||||
std::ofstream &filestream() {
|
||||
std::ofstream& filestream() {
|
||||
return *(_outptr.get());
|
||||
}
|
||||
|
||||
|
||||
FileSink &operator=(const FileSink &) = delete;
|
||||
FileSink(const FileSink &other) = delete;
|
||||
|
||||
FileSink& operator=(const FileSink&) = delete;
|
||||
FileSink(const FileSink& other) = delete;
|
||||
};
|
||||
} // g3
|
||||
|
||||
} // namespace g3
|
||||
|
@ -23,8 +23,6 @@
|
||||
* PUBLIC DOMAIN and NOT under copywrite protection.
|
||||
* ********************************************* */
|
||||
|
||||
|
||||
|
||||
#include <future>
|
||||
#include "g3log/active.hpp"
|
||||
#include "g3log/moveoncopy.hpp"
|
||||
@ -42,8 +40,7 @@ namespace g3 {
|
||||
// auto msg_call=[=](){return ("Hello from the Background");};
|
||||
// auto future_msg = g3::spawn_task(msg_lambda, bgWorker.get());
|
||||
template <typename Func, class BgWorker>
|
||||
std::future<std::invoke_result_t<Func>> spawn_task(Func func, BgWorker *worker)
|
||||
{
|
||||
std::future<std::invoke_result_t<Func>> spawn_task(Func func, BgWorker* worker) {
|
||||
typedef std::invoke_result_t<Func> result_type;
|
||||
typedef std::packaged_task<result_type()> task_type;
|
||||
|
||||
|
@ -18,16 +18,15 @@
|
||||
* 5. Various Q&A at StackOverflow
|
||||
* ********************************************* */
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "g3log/loglevels.hpp"
|
||||
#include "g3log/logcapture.hpp"
|
||||
#include "g3log/logmessage.hpp"
|
||||
#include "g3log/generated_definitions.hpp"
|
||||
#include "g3log/logcapture.hpp"
|
||||
#include "g3log/loglevels.hpp"
|
||||
#include "g3log/logmessage.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#if defined(_MSC_VER) && (defined(WINDOWS_FUNCSIG)) // Microsoft
|
||||
#define G3LOG_PRETTY_FUNCTION __FUNCSIG__
|
||||
@ -43,7 +42,6 @@
|
||||
#define thread_local __declspec(thread)
|
||||
#endif
|
||||
|
||||
|
||||
/** namespace for LOG() and CHECK() frameworks
|
||||
* History lesson: Why the names 'g3' and 'g3log'?:
|
||||
* The framework was made in my own free time as PUBLIC DOMAIN but the
|
||||
@ -62,8 +60,7 @@ namespace g3 {
|
||||
|
||||
/** Should be called at very first startup of the software with \ref g3LogWorker
|
||||
* pointer. Ownership of the \ref g3LogWorker is the responsibility of the caller */
|
||||
void initializeLogging(LogWorker *logger);
|
||||
|
||||
void initializeLogging(LogWorker* logger);
|
||||
|
||||
/** setFatalPreLoggingHook() provides an optional extra step before the fatalExitHandler is called
|
||||
*
|
||||
@ -88,7 +85,6 @@ namespace g3 {
|
||||
*/
|
||||
void setFatalExitHandler(std::function<void(FatalMessagePtr)> fatal_call);
|
||||
|
||||
|
||||
#ifdef G3_DYNAMIC_MAX_MESSAGE_SIZE
|
||||
// only_change_at_initialization namespace is for changes to be done only during initialization. More specifically
|
||||
// items here would be called prior to calling other parts of g3log
|
||||
@ -97,7 +93,7 @@ namespace g3 {
|
||||
// Longer than this are bound to 2KB with the string "[...truncated...]" at the end. This function allows
|
||||
// this limit to be changed.
|
||||
void setMaxMessageSize(size_t max_size);
|
||||
}
|
||||
} // namespace only_change_at_initialization
|
||||
#endif /* G3_DYNAMIC_MAX_MESSAGE_SIZE */
|
||||
|
||||
// internal namespace is for completely internal or semi-hidden from the g3 namespace due to that it is unlikely
|
||||
@ -107,13 +103,12 @@ namespace g3 {
|
||||
bool isLoggingInitialized();
|
||||
|
||||
// Save the created LogMessage to any existing sinks
|
||||
void saveMessage(const char *message, const char *file, int line, const char *function, const LEVELS &level,
|
||||
const char *boolean_expression, int fatal_signal, const char *stack_trace);
|
||||
void saveMessage(const char* message, const char* file, int line, const char* function, const LEVELS& level,
|
||||
const char* boolean_expression, int fatal_signal, const char* stack_trace);
|
||||
|
||||
// forwards the message to all sinks
|
||||
void pushMessageToLogger(LogMessagePtr log_entry);
|
||||
|
||||
|
||||
// forwards a FATAL message to all sinks,. after which the g3logworker
|
||||
// will trigger crashhandler / g3::internal::exitWithDefaultSignalHandler
|
||||
//
|
||||
@ -122,7 +117,6 @@ namespace g3 {
|
||||
// "setFatalExitHandler"
|
||||
void pushFatalMessageToLogger(FatalMessagePtr message);
|
||||
|
||||
|
||||
// Saves the created FatalMessage to any existing sinks and exits with
|
||||
// the originating fatal signal,. or SIGABRT if it originated from a broken contract.
|
||||
// By default forwards to: pushFatalMessageToLogger, see "setFatalExitHandler" to override
|
||||
@ -136,11 +130,11 @@ namespace g3 {
|
||||
void shutDownLogging();
|
||||
|
||||
// Shutdown logging, but ONLY if the active logger corresponds to the one currently initialized
|
||||
bool shutDownLoggingForActiveOnly(LogWorker *active);
|
||||
|
||||
} // internal
|
||||
} // g3
|
||||
bool shutDownLoggingForActiveOnly(LogWorker* active);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace g3
|
||||
// clang-format off
|
||||
#define INTERNAL_LOG_MESSAGE(level) LogCapture(__FILE__, __LINE__, static_cast<const char*>(G3LOG_PRETTY_FUNCTION), level)
|
||||
|
||||
#define INTERNAL_CONTRACT_MESSAGE(boolean_expression) \
|
||||
@ -228,3 +222,4 @@ And here is possible output
|
||||
// (ref test_io.cpp)
|
||||
#define CHECK_F(boolean_expression, printf_like_message, ...) \
|
||||
if (true == (boolean_expression)) {} else INTERNAL_CONTRACT_MESSAGE(#boolean_expression).capturef(printf_like_message, ##__VA_ARGS__)
|
||||
// clang-format on
|
@ -8,15 +8,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "g3log/loglevels.hpp"
|
||||
#include "g3log/crashhandler.hpp"
|
||||
#include "g3log/loglevels.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <cstdarg>
|
||||
#include <csignal>
|
||||
#include <cstdarg>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#ifdef _MSC_VER
|
||||
# include <sal.h>
|
||||
#include <sal.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -27,8 +27,7 @@
|
||||
*/
|
||||
struct LogCapture {
|
||||
/// Called from crash handler when a fatal signal has occurred (SIGSEGV etc)
|
||||
LogCapture(const LEVELS &level, g3::SignalType fatal_signal, const char *dump = nullptr);
|
||||
|
||||
LogCapture(const LEVELS& level, g3::SignalType fatal_signal, const char* dump = nullptr);
|
||||
|
||||
/**
|
||||
* @file, line, function are given in g3log.hpp from macros
|
||||
@ -36,48 +35,41 @@ struct LogCapture {
|
||||
* @expression for CHECK calls
|
||||
* @fatal_signal for failed CHECK:SIGABRT or fatal signal caught in the signal handler
|
||||
*/
|
||||
LogCapture(const char *file, const int line, const char *function, const LEVELS &level, const char *expression = "", g3::SignalType fatal_signal = SIGABRT, const char *dump = nullptr);
|
||||
|
||||
LogCapture(const char* file, const int line, const char* function, const LEVELS& level, const char* expression = "", g3::SignalType fatal_signal = SIGABRT, const char* dump = nullptr);
|
||||
|
||||
// At destruction the message will be forwarded to the g3log worker.
|
||||
// In the case of dynamically (at runtime) loaded libraries, the important thing to know is that
|
||||
// all strings are copied, so the original are not destroyed at the receiving end, only the copy
|
||||
virtual ~LogCapture() noexcept (false);
|
||||
|
||||
|
||||
|
||||
virtual ~LogCapture() noexcept(false);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# if _MSC_VER >= 1400
|
||||
# define G3LOG_FORMAT_STRING _Printf_format_string_
|
||||
# else
|
||||
# define G3LOG_FORMAT_STRING __format_string
|
||||
# endif
|
||||
|
||||
void capturef(G3LOG_FORMAT_STRING const char *printf_like_message, ...);
|
||||
#if _MSC_VER >= 1400
|
||||
#define G3LOG_FORMAT_STRING _Printf_format_string_
|
||||
#else
|
||||
# define G3LOG_FORMAT_STRING
|
||||
#define G3LOG_FORMAT_STRING __format_string
|
||||
#endif
|
||||
|
||||
void capturef(G3LOG_FORMAT_STRING const char* printf_like_message, ...);
|
||||
#else
|
||||
#define G3LOG_FORMAT_STRING
|
||||
|
||||
// Use "-Wall" to generate warnings in case of illegal printf format.
|
||||
// Ref: http://www.unixwiz.net/techtips/gnu-c-attributes.html
|
||||
[[gnu::format(printf, 2, 3)]] void capturef(G3LOG_FORMAT_STRING const char *printf_like_message, ...); // 2,3 ref: http://www.codemaestro.com/reviews/18
|
||||
[[gnu::format(printf, 2, 3)]] void capturef(G3LOG_FORMAT_STRING const char* printf_like_message, ...); // 2,3 ref: http://www.codemaestro.com/reviews/18
|
||||
#endif
|
||||
|
||||
/// prettifying API for this completely open struct
|
||||
std::ostringstream &stream() {
|
||||
std::ostringstream& stream() {
|
||||
return _stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::ostringstream _stream;
|
||||
std::string _stack_trace;
|
||||
const char* _file;
|
||||
const int _line;
|
||||
const char* _function;
|
||||
const LEVELS &_level;
|
||||
const LEVELS& _level;
|
||||
const char* _expression;
|
||||
const g3::SignalType _fatal_signal;
|
||||
|
||||
};
|
||||
//} // g3
|
||||
|
@ -22,20 +22,24 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <atomic>
|
||||
#include <g3log/atomicbool.hpp>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
// Levels for logging, made so that it would be easy to change, remove, add levels -- KjellKod
|
||||
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 std::string& idtext) : value(id), text(idtext) {}
|
||||
LEVELS(int id, const std::string& idtext) :
|
||||
value(id),
|
||||
text(idtext) {}
|
||||
|
||||
bool operator==(const LEVELS& rhs) const {
|
||||
return (value == rhs.value && text == rhs.text);
|
||||
@ -51,13 +55,11 @@ struct LEVELS {
|
||||
swap(first.text, second.text);
|
||||
}
|
||||
|
||||
|
||||
LEVELS& operator=(LEVELS other) {
|
||||
swap(*this, other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
int value;
|
||||
std::string text;
|
||||
};
|
||||
@ -89,14 +91,12 @@ namespace g3 {
|
||||
static const int kWarningValue = 500;
|
||||
static const int kFatalValue = 1000;
|
||||
static const int kInternalFatalValue = 2000;
|
||||
} // g3
|
||||
} // namespace g3
|
||||
|
||||
const LEVELS G3LOG_DEBUG{g3::kDebugValue, "DEBUG"},
|
||||
INFO {g3::kInfoValue, "INFO"},
|
||||
WARNING {g3::kWarningValue, "WARNING"},
|
||||
FATAL {g3::kFatalValue, "FATAL"};
|
||||
|
||||
|
||||
INFO{g3::kInfoValue, "INFO"},
|
||||
WARNING{g3::kWarningValue, "WARNING"},
|
||||
FATAL{g3::kFatalValue, "FATAL"};
|
||||
|
||||
namespace g3 {
|
||||
// Logging level and atomic status collection struct
|
||||
@ -105,10 +105,18 @@ namespace g3 {
|
||||
LEVELS level;
|
||||
|
||||
// default operator needed for std::map compliance
|
||||
LoggingLevel(): status(false), level(INFO) {};
|
||||
LoggingLevel(const LoggingLevel& lvl) : status(lvl.status), level(lvl.level) {}
|
||||
LoggingLevel(const LEVELS& lvl): status(true), level(lvl) {};
|
||||
LoggingLevel(const LEVELS& lvl, bool enabled): status(enabled), level(lvl) {};
|
||||
LoggingLevel() :
|
||||
status(false),
|
||||
level(INFO){};
|
||||
LoggingLevel(const LoggingLevel& lvl) :
|
||||
status(lvl.status),
|
||||
level(lvl.level) {}
|
||||
LoggingLevel(const LEVELS& lvl) :
|
||||
status(true),
|
||||
level(lvl){};
|
||||
LoggingLevel(const LEVELS& lvl, bool enabled) :
|
||||
status(enabled),
|
||||
level(lvl){};
|
||||
~LoggingLevel() = default;
|
||||
|
||||
LoggingLevel& operator=(const LoggingLevel& other) {
|
||||
@ -120,23 +128,19 @@ namespace g3 {
|
||||
bool operator==(const LoggingLevel& rhs) const {
|
||||
return (status == rhs.status && level == rhs.level);
|
||||
}
|
||||
|
||||
};
|
||||
} // g3
|
||||
|
||||
|
||||
|
||||
} // namespace g3
|
||||
|
||||
namespace g3 {
|
||||
namespace internal {
|
||||
const LEVELS CONTRACT {g3::kInternalFatalValue, {"CONTRACT"}},
|
||||
FATAL_SIGNAL {g3::kInternalFatalValue + 1, {"FATAL_SIGNAL"}},
|
||||
FATAL_EXCEPTION {kInternalFatalValue + 2, {"FATAL_EXCEPTION"}};
|
||||
const LEVELS CONTRACT{g3::kInternalFatalValue, {"CONTRACT"}},
|
||||
FATAL_SIGNAL{g3::kInternalFatalValue + 1, {"FATAL_SIGNAL"}},
|
||||
FATAL_EXCEPTION{kInternalFatalValue + 2, {"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);
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
// Only safe if done at initialization in a single-thread context
|
||||
@ -152,8 +156,7 @@ namespace g3 {
|
||||
/// remove any added logging levels so that the only ones left are
|
||||
/// {DEBUG,INFO,WARNING,FATAL}
|
||||
void reset();
|
||||
} // only_change_at_initialization
|
||||
|
||||
} // namespace only_change_at_initialization
|
||||
|
||||
namespace log_levels {
|
||||
/// Enable log level >= log_level.
|
||||
@ -169,7 +172,6 @@ namespace g3 {
|
||||
void disableAll();
|
||||
void enableAll();
|
||||
|
||||
|
||||
/// print all levels with their disabled or enabled status
|
||||
std::string to_string(std::map<int, g3::LoggingLevel> levelsToPrint);
|
||||
|
||||
@ -177,16 +179,17 @@ namespace g3 {
|
||||
/// disabled or enabled status
|
||||
std::string to_string();
|
||||
|
||||
|
||||
/// Snapshot view of the current logging levels' status
|
||||
std::map<int, g3::LoggingLevel> getAll();
|
||||
|
||||
enum class status {Absent, Enabled, Disabled};
|
||||
enum class status { Absent,
|
||||
Enabled,
|
||||
Disabled };
|
||||
status getStatus(LEVELS level);
|
||||
} // log_levels
|
||||
} // namespace log_levels
|
||||
|
||||
#endif
|
||||
/// Enabled status for the given logging level
|
||||
bool logLevel(const LEVELS& level);
|
||||
|
||||
} // g3
|
||||
} // namespace g3
|
||||
|
@ -8,17 +8,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#include "g3log/loglevels.hpp"
|
||||
#include "g3log/time.hpp"
|
||||
#include "g3log/moveoncopy.hpp"
|
||||
#include "g3log/crashhandler.hpp"
|
||||
#include "g3log/loglevels.hpp"
|
||||
#include "g3log/moveoncopy.hpp"
|
||||
#include "g3log/time.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
namespace g3 {
|
||||
|
||||
@ -71,10 +69,8 @@ namespace g3 {
|
||||
_expression = std::move(expression);
|
||||
}
|
||||
|
||||
|
||||
LogMessage& operator=(LogMessage other);
|
||||
|
||||
|
||||
LogMessage(std::string file, const int line, std::string function, const LEVELS level);
|
||||
|
||||
explicit LogMessage(const std::string& fatalOsSignalCrashMessage);
|
||||
@ -82,7 +78,6 @@ namespace g3 {
|
||||
LogMessage(LogMessage&& other);
|
||||
virtual ~LogMessage() {}
|
||||
|
||||
|
||||
// helper log printing functions used by "toString()"
|
||||
static std::string splitFileName(const std::string& str);
|
||||
static std::string fatalSignalToString(const LogMessage& msg);
|
||||
@ -92,8 +87,6 @@ namespace g3 {
|
||||
static std::string fatalCheckToString(const LogMessage& msg);
|
||||
static std::string normalToString(const LogMessage& msg);
|
||||
|
||||
|
||||
|
||||
// the default formatting option
|
||||
static std::string DefaultLogDetailsToString(const LogMessage& msg);
|
||||
|
||||
@ -101,14 +94,11 @@ namespace g3 {
|
||||
// see this concept and it is easy to make your own custom formatting
|
||||
static std::string FullLogDetailsToString(const LogMessage& msg);
|
||||
|
||||
using LogDetailsFunc = std::string (*) (const LogMessage&);
|
||||
using LogDetailsFunc = std::string (*)(const LogMessage&);
|
||||
std::string toString(LogDetailsFunc formattingFunc = DefaultLogDetailsToString) const;
|
||||
|
||||
|
||||
void overrideLogDetailsFunc(LogDetailsFunc func) const;
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Complete access to the raw data in case the helper functions above
|
||||
// are not enough.
|
||||
@ -124,8 +114,6 @@ namespace g3 {
|
||||
std::string _expression; // only with content for CHECK(...) calls
|
||||
mutable std::string _message;
|
||||
|
||||
|
||||
|
||||
friend void swap(LogMessage& first, LogMessage& second) {
|
||||
using std::swap;
|
||||
swap(first._timestamp, second._timestamp);
|
||||
@ -137,12 +125,8 @@ namespace g3 {
|
||||
swap(first._expression, second._expression);
|
||||
swap(first._message, second._message);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** Trigger for flushing the message queue and exiting the application
|
||||
* A thread that causes a FatalMessage will sleep forever until the
|
||||
* application has exited (after message flush) */
|
||||
@ -158,8 +142,7 @@ namespace g3 {
|
||||
const SignalType _signal_id;
|
||||
};
|
||||
|
||||
|
||||
typedef MoveOnCopy<std::unique_ptr<FatalMessage>> FatalMessagePtr;
|
||||
typedef MoveOnCopy<std::unique_ptr<LogMessage>> LogMessagePtr;
|
||||
typedef MoveOnCopy<LogMessage> LogMessageMover;
|
||||
} // g3
|
||||
} // namespace g3
|
||||
|
@ -11,18 +11,17 @@
|
||||
*
|
||||
* PUBLIC DOMAIN and Not copyrighted. First published at KjellKod.cc
|
||||
* ********************************************* */
|
||||
#include "g3log/g3log.hpp"
|
||||
#include "g3log/sinkwrapper.hpp"
|
||||
#include "g3log/sinkhandle.hpp"
|
||||
#include "g3log/filesink.hpp"
|
||||
#include "g3log/logmessage.hpp"
|
||||
#include <memory>
|
||||
#include "g3log/filesink.hpp"
|
||||
#include "g3log/g3log.hpp"
|
||||
#include "g3log/logmessage.hpp"
|
||||
#include "g3log/sinkhandle.hpp"
|
||||
#include "g3log/sinkwrapper.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace g3 {
|
||||
class LogWorker;
|
||||
struct LogWorkerImpl;
|
||||
@ -44,7 +43,6 @@ namespace g3 {
|
||||
LogWorkerImpl& operator=(const LogWorkerImpl&) = delete;
|
||||
};
|
||||
|
||||
|
||||
/// Front end of the LogWorker. API that is useful is
|
||||
/// addSink( sink, default_call ) which returns a handle to the sink. See below and README for usage example
|
||||
/// save( msg ) : internal use
|
||||
@ -57,7 +55,6 @@ namespace g3 {
|
||||
LogWorker(const LogWorker&) = delete;
|
||||
LogWorker& operator=(const LogWorker&) = delete;
|
||||
|
||||
|
||||
public:
|
||||
~LogWorker();
|
||||
|
||||
@ -65,7 +62,6 @@ namespace g3 {
|
||||
/// if you want to use the default file logger then see below for @ref addDefaultLogger
|
||||
static std::unique_ptr<LogWorker> createLogWorker();
|
||||
|
||||
|
||||
/**
|
||||
A convenience function to add the default g3::FileSink to the log worker
|
||||
@param log_prefix that you want
|
||||
@ -89,26 +85,26 @@ namespace g3 {
|
||||
/// @param real_sink unique_ptr ownership is passed to the log worker
|
||||
/// @param call the default call that should receive either a std::string or a LogMessageMover message
|
||||
/// @return handle to the sink for API access. See usage example below at @ref addDefaultLogger
|
||||
template<typename T, typename DefaultLogCall>
|
||||
template <typename T, typename DefaultLogCall>
|
||||
std::unique_ptr<g3::SinkHandle<T>> addSink(std::unique_ptr<T> real_sink, DefaultLogCall call) {
|
||||
using namespace g3;
|
||||
using namespace g3::internal;
|
||||
auto sink = std::make_shared<Sink<T>> (std::move(real_sink), call);
|
||||
auto sink = std::make_shared<Sink<T>>(std::move(real_sink), call);
|
||||
addWrappedSink(sink);
|
||||
return std::make_unique<SinkHandle<T>> (sink);
|
||||
return std::make_unique<SinkHandle<T>>(sink);
|
||||
}
|
||||
|
||||
|
||||
/// Removes a sink. This is a synchronous call.
|
||||
/// You are guaranteed that the sink is removed by the time the call returns
|
||||
/// @param sink_handle the ownership of the sink handle is given
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
void removeSink(std::unique_ptr<SinkHandle<T>> sink_handle) {
|
||||
if (sink_handle) {
|
||||
// sink_handle->sink().use_count() is 1 at this point
|
||||
// i.e. this would be safe as long as no other weak_ptr to shared_ptr conversion
|
||||
// was made by the client: assert(sink_handle->sink().use_count() == 0);
|
||||
auto weak_ptr_sink = sink_handle->sink(); {
|
||||
auto weak_ptr_sink = sink_handle->sink();
|
||||
{
|
||||
auto bg_removesink_call = [this, weak_ptr_sink] {
|
||||
auto shared_sink = weak_ptr_sink.lock();
|
||||
if (shared_sink) {
|
||||
@ -127,13 +123,13 @@ namespace g3 {
|
||||
/// This will clear/remove all the sinks. If a sink shared_ptr was retrieved via the sink
|
||||
/// handle then the sink will be removed internally but will live on in the client's instance
|
||||
void removeAllSinks() {
|
||||
auto bg_clear_sink_call = [this]() noexcept { _impl._sinks.clear(); };
|
||||
auto bg_clear_sink_call = [this]() noexcept {
|
||||
_impl._sinks.clear();
|
||||
};
|
||||
auto token_cleared = g3::spawn_task(bg_clear_sink_call, _impl._bg.get());
|
||||
token_cleared.wait();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// internal:
|
||||
/// pushes in background thread (asynchronously) input messages to log file
|
||||
void save(LogMessagePtr entry);
|
||||
@ -143,7 +139,5 @@ namespace g3 {
|
||||
/// this way it's ensured that all existing entries were flushed before 'fatal'
|
||||
/// Will abort the application!
|
||||
void fatal(FatalMessagePtr fatal_message);
|
||||
|
||||
|
||||
};
|
||||
} // g3
|
||||
} // namespace g3
|
||||
|
@ -14,20 +14,23 @@ namespace g3 {
|
||||
// not CopyConstructible or CopyAssignable. To put them in a std container they need
|
||||
// to be wrapped and their internals "moved" when tried to be copied.
|
||||
|
||||
template<typename Moveable>
|
||||
template <typename Moveable>
|
||||
struct MoveOnCopy {
|
||||
mutable Moveable _move_only;
|
||||
|
||||
explicit MoveOnCopy(Moveable &&m) : _move_only(std::move(m)) {}
|
||||
MoveOnCopy(MoveOnCopy const &t) : _move_only(std::move(t._move_only)) {}
|
||||
MoveOnCopy(MoveOnCopy &&t) : _move_only(std::move(t._move_only)) {}
|
||||
explicit MoveOnCopy(Moveable&& m) :
|
||||
_move_only(std::move(m)) {}
|
||||
MoveOnCopy(MoveOnCopy const& t) :
|
||||
_move_only(std::move(t._move_only)) {}
|
||||
MoveOnCopy(MoveOnCopy&& t) :
|
||||
_move_only(std::move(t._move_only)) {}
|
||||
|
||||
MoveOnCopy &operator=(MoveOnCopy const &other) {
|
||||
MoveOnCopy& operator=(MoveOnCopy const& other) {
|
||||
_move_only = std::move(other._move_only);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MoveOnCopy &operator=(MoveOnCopy && other) {
|
||||
MoveOnCopy& operator=(MoveOnCopy&& other) {
|
||||
_move_only = std::move(other._move_only);
|
||||
return *this;
|
||||
}
|
||||
@ -36,7 +39,7 @@ namespace g3 {
|
||||
_move_only();
|
||||
}
|
||||
|
||||
Moveable &get() {
|
||||
Moveable& get() {
|
||||
return _move_only;
|
||||
}
|
||||
|
||||
@ -45,4 +48,4 @@ namespace g3 {
|
||||
}
|
||||
};
|
||||
|
||||
} // g3
|
||||
} // namespace g3
|
||||
|
@ -16,24 +16,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <exception>
|
||||
#include <condition_variable>
|
||||
#include <exception>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
/** Multiple producer, multiple consumer thread safe queue
|
||||
* Since 'return by reference' is used this queue won't throw */
|
||||
template<typename T>
|
||||
class shared_queue
|
||||
{
|
||||
template <typename T>
|
||||
class shared_queue {
|
||||
std::queue<T> queue_;
|
||||
mutable std::mutex m_;
|
||||
std::condition_variable data_cond_;
|
||||
|
||||
shared_queue &operator=(const shared_queue &) = delete;
|
||||
shared_queue(const shared_queue &other) = delete;
|
||||
shared_queue& operator=(const shared_queue&) = delete;
|
||||
shared_queue(const shared_queue& other) = delete;
|
||||
|
||||
public:
|
||||
public:
|
||||
shared_queue() = default;
|
||||
|
||||
void push(T item) {
|
||||
@ -45,7 +44,7 @@ public:
|
||||
}
|
||||
|
||||
/// \return immediately, with true if successful retrieval
|
||||
bool try_and_pop(T &popped_item) {
|
||||
bool try_and_pop(T& popped_item) {
|
||||
std::lock_guard<std::mutex> lock(m_);
|
||||
if (queue_.empty()) {
|
||||
return false;
|
||||
@ -56,10 +55,9 @@ public:
|
||||
}
|
||||
|
||||
/// Try to retrieve, if no items, wait till an item is available and try again
|
||||
void wait_and_pop(T &popped_item) {
|
||||
void wait_and_pop(T& popped_item) {
|
||||
std::unique_lock<std::mutex> lock(m_);
|
||||
while (queue_.empty())
|
||||
{
|
||||
while (queue_.empty()) {
|
||||
data_cond_.wait(lock);
|
||||
// This 'while' loop is equal to
|
||||
// data_cond_.wait(lock, [](bool result){return !queue_.empty();});
|
||||
|
@ -8,19 +8,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "g3log/sinkwrapper.hpp"
|
||||
#include "g3log/active.hpp"
|
||||
#include "g3log/future.hpp"
|
||||
#include "g3log/logmessage.hpp"
|
||||
#include "g3log/sinkwrapper.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace g3 {
|
||||
namespace internal {
|
||||
typedef std::function<void(LogMessageMover) > AsyncMessageCall;
|
||||
typedef std::function<void(LogMessageMover)> AsyncMessageCall;
|
||||
|
||||
/// The asynchronous Sink has an active object, incoming requests for actions
|
||||
// will be processed in the background by the specific object the Sink represents.
|
||||
@ -34,27 +33,26 @@ namespace g3 {
|
||||
// Ref: send(Call call, Args... args) deals with calls
|
||||
// to the real sink's API
|
||||
|
||||
template<class T>
|
||||
template <class T>
|
||||
struct Sink : public SinkWrapper {
|
||||
std::unique_ptr<T> _real_sink;
|
||||
std::unique_ptr<kjellkod::Active> _bg;
|
||||
AsyncMessageCall _default_log_call;
|
||||
|
||||
template<typename DefaultLogCall >
|
||||
Sink(std::unique_ptr<T> sink, DefaultLogCall call)
|
||||
: SinkWrapper(),
|
||||
_real_sink {std::move(sink)},
|
||||
template <typename DefaultLogCall>
|
||||
Sink(std::unique_ptr<T> sink, DefaultLogCall call) :
|
||||
SinkWrapper(),
|
||||
_real_sink{std::move(sink)},
|
||||
_bg(kjellkod::Active::createActive()),
|
||||
_default_log_call(std::bind(call, _real_sink.get(), std::placeholders::_1)) {
|
||||
}
|
||||
|
||||
|
||||
Sink(std::unique_ptr<T> sink, void(T::*Call)(std::string) )
|
||||
: SinkWrapper(),
|
||||
_real_sink {std::move(sink)},
|
||||
Sink(std::unique_ptr<T> sink, void (T::*Call)(std::string)) :
|
||||
SinkWrapper(),
|
||||
_real_sink{std::move(sink)},
|
||||
_bg(kjellkod::Active::createActive()) {
|
||||
std::function<void(std::string)> adapter = std::bind(Call, _real_sink.get(), std::placeholders::_1);
|
||||
_default_log_call = [ = ](LogMessageMover m) {
|
||||
_default_log_call = [=](LogMessageMover m) {
|
||||
adapter(m.get().toString());
|
||||
};
|
||||
}
|
||||
@ -69,10 +67,10 @@ namespace g3 {
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Call, typename... Args>
|
||||
auto async(Call call, Args &&... args)-> std::future<std::invoke_result_t<decltype(call), T, Args...>> {
|
||||
template <typename Call, typename... Args>
|
||||
auto async(Call call, Args&&... args) -> std::future<std::invoke_result_t<decltype(call), T, Args...>> {
|
||||
return g3::spawn_task(std::bind(call, _real_sink.get(), std::forward<Args>(args)...), _bg.get());
|
||||
}
|
||||
};
|
||||
} // internal
|
||||
} // g3
|
||||
} // namespace internal
|
||||
} // namespace g3
|
||||
|
@ -22,22 +22,21 @@ namespace g3 {
|
||||
// The real sink will be owned by g3log. If the real sink is deleted
|
||||
// calls to sink's API through the SinkHandle will return an exception embedded
|
||||
// in the resulting future. Ref: SinkHandle::call
|
||||
template<class T>
|
||||
template <class T>
|
||||
class SinkHandle {
|
||||
std::weak_ptr<internal::Sink<T>> _sink;
|
||||
|
||||
public:
|
||||
SinkHandle(std::shared_ptr<internal::Sink<T>> sink)
|
||||
: _sink(sink) {}
|
||||
SinkHandle(std::shared_ptr<internal::Sink<T>> sink) :
|
||||
_sink(sink) {}
|
||||
|
||||
~SinkHandle() = default;
|
||||
|
||||
|
||||
// Asynchronous call to the real sink. If the real sink is already deleted
|
||||
// the returned future will contain a bad_weak_ptr exception instead of the
|
||||
// call result.
|
||||
template<typename AsyncCall, typename... Args>
|
||||
auto call(AsyncCall func , Args&& ... args) -> std::future<std::invoke_result_t<decltype(func), T, Args...>> {
|
||||
template <typename AsyncCall, typename... Args>
|
||||
auto call(AsyncCall func, Args&&... args) -> std::future<std::invoke_result_t<decltype(func), T, Args...>> {
|
||||
try {
|
||||
std::shared_ptr<internal::Sink<T>> sink(_sink);
|
||||
return sink->async(func, std::forward<Args>(args)...);
|
||||
@ -57,6 +56,4 @@ namespace g3 {
|
||||
}
|
||||
};
|
||||
|
||||
} // g3
|
||||
|
||||
|
||||
} // namespace g3
|
||||
|
@ -14,9 +14,8 @@ namespace g3 {
|
||||
namespace internal {
|
||||
|
||||
struct SinkWrapper {
|
||||
virtual ~SinkWrapper() { }
|
||||
virtual ~SinkWrapper() {}
|
||||
virtual void send(LogMessageMover msg) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace g3
|
||||
|
@ -11,7 +11,6 @@
|
||||
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
|
||||
* ============================================================================*/
|
||||
|
||||
|
||||
#pragma once
|
||||
#if !(defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
||||
#error "stacktrace_win.cpp used but not on a windows system"
|
||||
@ -19,8 +18,8 @@
|
||||
|
||||
#include "g3log/crashhandler.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
|
||||
namespace stacktrace {
|
||||
/// return the text description of a Windows exception code
|
||||
@ -34,9 +33,9 @@ namespace stacktrace {
|
||||
std::string stackdump();
|
||||
|
||||
/// helper function: retrieve stackdump, starting from an exception pointer
|
||||
std::string stackdump(EXCEPTION_POINTERS *info);
|
||||
std::string stackdump(EXCEPTION_POINTERS* info);
|
||||
|
||||
/// main stackdump function. retrieve stackdump, from the given context
|
||||
std::string stackdump(CONTEXT *context);
|
||||
std::string stackdump(CONTEXT* context);
|
||||
|
||||
} // stacktrace
|
||||
} // namespace stacktrace
|
||||
|
@ -11,15 +11,12 @@
|
||||
* Ref: workarounds at http://connect.microsoft.com/VisualStudio/feedback/details/791185/std-packaged-task-t-where-t-is-void-or-a-reference-class-are-not-movable
|
||||
* ============================================================================*/
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(__MINGW32__) && (_MSC_VER <= 1800)
|
||||
namespace std {
|
||||
|
||||
template<class... _ArgTypes>
|
||||
class packaged_task<void(_ArgTypes...)>
|
||||
{
|
||||
template <class... _ArgTypes>
|
||||
class packaged_task<void(_ArgTypes...)> {
|
||||
promise<void> _my_promise;
|
||||
function<void(_ArgTypes...)> _my_func;
|
||||
|
||||
@ -27,29 +24,29 @@ namespace std {
|
||||
packaged_task() {
|
||||
}
|
||||
|
||||
template<class _Fty2>
|
||||
explicit packaged_task(_Fty2 &&_Fnarg)
|
||||
: _my_func(_Fnarg) {
|
||||
template <class _Fty2>
|
||||
explicit packaged_task(_Fty2&& _Fnarg) :
|
||||
_my_func(_Fnarg) {
|
||||
}
|
||||
|
||||
packaged_task(packaged_task &&_Other)
|
||||
: _my_promise(move(_Other._my_promise)),
|
||||
packaged_task(packaged_task&& _Other) :
|
||||
_my_promise(move(_Other._my_promise)),
|
||||
_my_func(move(_Other._my_func)) {
|
||||
}
|
||||
|
||||
packaged_task &operator=(packaged_task && _Other) {
|
||||
packaged_task& operator=(packaged_task&& _Other) {
|
||||
_my_promise = move(_Other._my_promise);
|
||||
_my_func = move(_Other._my_func);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
packaged_task(const packaged_task &) = delete;
|
||||
packaged_task &operator=(const packaged_task &) = delete;
|
||||
packaged_task(const packaged_task&) = delete;
|
||||
packaged_task& operator=(const packaged_task&) = delete;
|
||||
|
||||
~packaged_task() {
|
||||
}
|
||||
|
||||
void swap(packaged_task &_Other) {
|
||||
void swap(packaged_task& _Other) {
|
||||
swap(_my_promise, _Other._my_promise);
|
||||
swap(_my_func, _Other._my_func);
|
||||
}
|
||||
|
@ -13,9 +13,9 @@
|
||||
* PUBLIC DOMAIN and Not under copywrite protection. First published for g3log at KjellKod.cc
|
||||
* ********************************************* */
|
||||
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
|
||||
// FYI:
|
||||
// namespace g3::internal ONLY in g3time.cpp
|
||||
@ -28,7 +28,10 @@ namespace g3 {
|
||||
typedef std::chrono::microseconds microseconds;
|
||||
|
||||
namespace internal {
|
||||
enum class Fractional {Millisecond, Microsecond, Nanosecond, NanosecondDefault};
|
||||
enum class Fractional { Millisecond,
|
||||
Microsecond,
|
||||
Nanosecond,
|
||||
NanosecondDefault };
|
||||
Fractional getFractional(const std::string& format_buffer, size_t pos);
|
||||
std::string to_string(const g3::system_time_point& ts, Fractional fractional);
|
||||
std::string localtime_formatted_fractions(const g3::system_time_point& ts, std::string format_buffer);
|
||||
@ -38,8 +41,7 @@ namespace g3 {
|
||||
// %6: microseconds: 6 digits: 000001 --- default for the time_format
|
||||
// %f9, %f: nanoseconds, 9 digits: 000000001
|
||||
static const std::string time_formatted = "%H:%M:%S %f6";
|
||||
} // internal
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// This mimics the original "std::put_time(const std::tm* tmb, const charT* fmt)"
|
||||
// This is needed since latest version (at time of writing) of gcc4.7 does not implement this library function yet.
|
||||
@ -55,10 +57,9 @@ namespace g3 {
|
||||
* WARNING: At time of writing there is only so-so compiler support for
|
||||
* std::put_time. A possible fix if your c++11 library is not updated is to
|
||||
* modify this to use std::strftime instead */
|
||||
std::string localtime_formatted(const system_time_point& ts, const std::string& time_format) ;
|
||||
std::string localtime_formatted(const system_time_point& ts, const std::string& time_format);
|
||||
|
||||
inline system_time_point to_system_time(const high_resolution_time_point& ts)
|
||||
{
|
||||
inline system_time_point to_system_time(const high_resolution_time_point& ts) {
|
||||
// On some (windows) systems, the system_clock does not provide the highest possible time
|
||||
// resolution. Thus g3log uses high_resolution_clock for message time stamps. However,
|
||||
// unlike system_clock, high_resolution_clock cannot be converted to a time and date as
|
||||
@ -74,7 +75,4 @@ namespace g3 {
|
||||
|
||||
return time_point_cast<system_clock::duration>(sys_now + (ts - hrs_now));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace g3
|
||||
|
@ -7,8 +7,8 @@
|
||||
* ============================================================================*/
|
||||
|
||||
#include "g3log/logcapture.hpp"
|
||||
#include "g3log/g3log.hpp"
|
||||
#include "g3log/crashhandler.hpp"
|
||||
#include "g3log/g3log.hpp"
|
||||
|
||||
#ifdef G3_DYNAMIC_MAX_MESSAGE_SIZE
|
||||
#include <vector>
|
||||
@ -21,7 +21,9 @@
|
||||
#define SIGNAL_HANDLER_VERIFY() g3::installSignalHandlerForThread()
|
||||
#else
|
||||
// Does nothing --- enforces that semicolon must be written
|
||||
#define SIGNAL_HANDLER_VERIFY() do {} while(0)
|
||||
#define SIGNAL_HANDLER_VERIFY() \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef G3_DYNAMIC_MAX_MESSAGE_SIZE
|
||||
@ -30,7 +32,7 @@ static int MaxMessageSize = 2048;
|
||||
|
||||
void g3::only_change_at_initialization::setMaxMessageSize(size_t max_size) {
|
||||
MaxMessageSize = max_size;
|
||||
}
|
||||
}
|
||||
#endif /* G3_DYNAMIC_MAX_MESSAGE_SIZE */
|
||||
|
||||
/** logCapture is a simple struct for capturing log/fatal entries. At destruction the
|
||||
@ -38,15 +40,15 @@ void g3::only_change_at_initialization::setMaxMessageSize(size_t max_size) {
|
||||
* As a safety precaution: No memory allocated here will be moved into the background
|
||||
* worker in case of dynamic loaded library reasons instead the arguments are copied
|
||||
* inside of g3log.cpp::saveMessage*/
|
||||
LogCapture::~LogCapture() noexcept (false) {
|
||||
LogCapture::~LogCapture() noexcept(false) {
|
||||
using namespace g3::internal;
|
||||
SIGNAL_HANDLER_VERIFY();
|
||||
saveMessage(_stream.str().c_str(), _file, _line, _function, _level, _expression, _fatal_signal, _stack_trace.c_str());
|
||||
}
|
||||
|
||||
|
||||
/// Called from crash handler when a fatal signal has occurred (SIGSEGV etc)
|
||||
LogCapture::LogCapture(const LEVELS &level, g3::SignalType fatal_signal, const char *dump) : LogCapture("", 0, "", level, "", fatal_signal, dump) {
|
||||
LogCapture::LogCapture(const LEVELS& level, g3::SignalType fatal_signal, const char* dump) :
|
||||
LogCapture("", 0, "", level, "", fatal_signal, dump) {
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,9 +57,14 @@ LogCapture::LogCapture(const LEVELS &level, g3::SignalType fatal_signal, const c
|
||||
* @expression for CHECK calls
|
||||
* @fatal_signal for failed CHECK:SIGABRT or fatal signal caught in the signal handler
|
||||
*/
|
||||
LogCapture::LogCapture(const char *file, const int line, const char *function, const LEVELS &level,
|
||||
const char *expression, g3::SignalType fatal_signal, const char *dump)
|
||||
: _file(file), _line(line), _function(function), _level(level), _expression(expression), _fatal_signal(fatal_signal) {
|
||||
LogCapture::LogCapture(const char* file, const int line, const char* function, const LEVELS& level,
|
||||
const char* expression, g3::SignalType fatal_signal, const char* dump) :
|
||||
_file(file),
|
||||
_line(line),
|
||||
_function(function),
|
||||
_level(level),
|
||||
_expression(expression),
|
||||
_fatal_signal(fatal_signal) {
|
||||
|
||||
if (g3::internal::wasFatal(level)) {
|
||||
_stack_trace = std::string{"\n*******\tSTACKDUMP *******\n"};
|
||||
@ -65,17 +72,15 @@ LogCapture::LogCapture(const char *file, const int line, const char *function, c
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* capturef, used for "printf" like API in CHECKF, LOGF, LOGF_IF
|
||||
* See also for the attribute formatting ref: http://www.codemaestro.com/reviews/18
|
||||
*/
|
||||
void LogCapture::capturef(const char *printf_like_message, ...) {
|
||||
void LogCapture::capturef(const char* printf_like_message, ...) {
|
||||
static const std::string kTruncatedWarningText = "[...truncated...]";
|
||||
#ifdef G3_DYNAMIC_MAX_MESSAGE_SIZE
|
||||
std::vector<char> finished_message_backing(MaxMessageSize);
|
||||
char *finished_message = finished_message_backing.data();
|
||||
char* finished_message = finished_message_backing.data();
|
||||
auto finished_message_len = MaxMessageSize;
|
||||
#else
|
||||
static const int kMaxMessageSize = 2048;
|
||||
@ -106,5 +111,3 @@ void LogCapture::capturef(const char *printf_like_message, ...) {
|
||||
stream() << finished_message;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -19,15 +19,14 @@ namespace g3 {
|
||||
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
const std::map<int, LoggingLevel> g_log_level_defaults = {
|
||||
{G3LOG_DEBUG.value,{G3LOG_DEBUG}},
|
||||
{G3LOG_DEBUG.value, {G3LOG_DEBUG}},
|
||||
{INFO.value, {INFO}},
|
||||
{WARNING.value, {WARNING}},
|
||||
{FATAL.value, {FATAL}}
|
||||
};
|
||||
{FATAL.value, {FATAL}}};
|
||||
|
||||
std::map<int, g3::LoggingLevel> g_log_levels = g_log_level_defaults;
|
||||
#endif
|
||||
} // internal
|
||||
} // namespace internal
|
||||
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
namespace only_change_at_initialization {
|
||||
@ -37,7 +36,6 @@ namespace g3 {
|
||||
internal::g_log_levels[value] = {lvl, enabled};
|
||||
}
|
||||
|
||||
|
||||
void addLogLevel(LEVELS level) {
|
||||
addLogLevel(level, true);
|
||||
}
|
||||
@ -45,8 +43,7 @@ namespace g3 {
|
||||
void reset() {
|
||||
g3::internal::g_log_levels = g3::internal::g_log_level_defaults;
|
||||
}
|
||||
} // only_change_at_initialization
|
||||
|
||||
} // namespace only_change_at_initialization
|
||||
|
||||
namespace log_levels {
|
||||
|
||||
@ -59,12 +56,10 @@ namespace g3 {
|
||||
} else {
|
||||
enable(v.second.level);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void set(LEVELS level, bool enabled) {
|
||||
auto it = internal::g_log_levels.find(level.value);
|
||||
if (it != internal::g_log_levels.end()) {
|
||||
@ -72,7 +67,6 @@ namespace g3 {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void disable(LEVELS level) {
|
||||
set(level, false);
|
||||
}
|
||||
@ -81,7 +75,6 @@ namespace g3 {
|
||||
set(level, true);
|
||||
}
|
||||
|
||||
|
||||
void disableAll() {
|
||||
for (auto& v : internal::g_log_levels) {
|
||||
v.second.status = false;
|
||||
@ -94,7 +87,6 @@ namespace g3 {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string to_string(std::map<int, g3::LoggingLevel> levelsToPrint) {
|
||||
std::string levels;
|
||||
for (auto& v : levelsToPrint) {
|
||||
@ -107,7 +99,6 @@ namespace g3 {
|
||||
return to_string(internal::g_log_levels);
|
||||
}
|
||||
|
||||
|
||||
std::map<int, g3::LoggingLevel> getAll() {
|
||||
return internal::g_log_levels;
|
||||
}
|
||||
@ -120,13 +111,11 @@ namespace g3 {
|
||||
}
|
||||
|
||||
return (it->second.status.get().load() ? status::Enabled : status::Disabled);
|
||||
|
||||
}
|
||||
} // log_levels
|
||||
} // namespace log_levels
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
bool logLevel(const LEVELS& log_level) {
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
int level = log_level.value;
|
||||
@ -136,4 +125,4 @@ namespace g3 {
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
} // g3
|
||||
} // namespace g3
|
||||
|
@ -7,12 +7,9 @@
|
||||
* ============================================================================*/
|
||||
|
||||
#include "g3log/logmessage.hpp"
|
||||
#include <mutex>
|
||||
#include "g3log/crashhandler.hpp"
|
||||
#include "g3log/time.hpp"
|
||||
#include <mutex>
|
||||
|
||||
|
||||
|
||||
|
||||
namespace g3 {
|
||||
|
||||
@ -22,27 +19,20 @@ namespace g3 {
|
||||
return str.substr(found + 1);
|
||||
}
|
||||
|
||||
|
||||
// helper for fatal signal
|
||||
std::string LogMessage::fatalSignalToString(const LogMessage& msg) {
|
||||
std::string out; // clear any previous text and formatting
|
||||
out.append(msg.timestamp()
|
||||
+ "\n\n***** FATAL SIGNAL RECEIVED ******* \n"
|
||||
+ msg.message() + '\n');
|
||||
out.append(msg.timestamp() + "\n\n***** FATAL SIGNAL RECEIVED ******* \n" + msg.message() + '\n');
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
// helper for fatal exception (windows only)
|
||||
std::string LogMessage::fatalExceptionToString(const LogMessage& msg) {
|
||||
std::string out; // clear any previous text and formatting
|
||||
out.append(msg.timestamp()
|
||||
+ "\n\n***** FATAL EXCEPTION RECEIVED ******* \n"
|
||||
+ msg.message() + '\n');
|
||||
out.append(msg.timestamp() + "\n\n***** FATAL EXCEPTION RECEIVED ******* \n" + msg.message() + '\n');
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
// helper for fatal LOG
|
||||
std::string LogMessage::fatalLogToString(const LogMessage& msg) {
|
||||
auto out = msg._logDetailsToStringFunc(msg);
|
||||
@ -55,39 +45,23 @@ namespace g3 {
|
||||
std::string LogMessage::fatalCheckToString(const LogMessage& msg) {
|
||||
auto out = msg._logDetailsToStringFunc(msg);
|
||||
static const std::string contractExitReason = {"EXIT trigger caused by broken Contract:"};
|
||||
out.append("\n\t*******\t " + contractExitReason + " CHECK(" + msg.expression() + ")\n\t"
|
||||
+ '"' + msg. message() + '"');
|
||||
out.append("\n\t*******\t " + contractExitReason + " CHECK(" + msg.expression() + ")\n\t" + '"' + msg.message() + '"');
|
||||
return out;
|
||||
}
|
||||
|
||||
// helper for setting the normal log details in an entry
|
||||
std::string LogMessage::DefaultLogDetailsToString(const LogMessage& msg) {
|
||||
std::string out;
|
||||
out.append(msg.timestamp() + "\t"
|
||||
+ msg.level()
|
||||
+ " ["
|
||||
+ msg.file()
|
||||
+ "->"
|
||||
+ msg.function()
|
||||
+ ":" + msg.line() + "]\t");
|
||||
out.append(msg.timestamp() + "\t" + msg.level() + " [" + msg.file() + "->" + msg.function() + ":" + msg.line() + "]\t");
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
std::string LogMessage::FullLogDetailsToString(const LogMessage& msg) {
|
||||
std::string out;
|
||||
out.append(msg.timestamp() + "\t"
|
||||
+ msg.level()
|
||||
+ " ["
|
||||
+ msg.threadID()
|
||||
+ " "
|
||||
+ msg.file()
|
||||
+ "->"+ msg.function()
|
||||
+ ":" + msg.line() + "]\t");
|
||||
out.append(msg.timestamp() + "\t" + msg.level() + " [" + msg.threadID() + " " + msg.file() + "->" + msg.function() + ":" + msg.line() + "]\t");
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
// helper for normal
|
||||
std::string LogMessage::normalToString(const LogMessage& msg) {
|
||||
auto out = msg._logDetailsToStringFunc(msg);
|
||||
@ -95,16 +69,12 @@ namespace g3 {
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// end static functions section
|
||||
|
||||
void LogMessage::overrideLogDetailsFunc(LogDetailsFunc func) const{
|
||||
void LogMessage::overrideLogDetailsFunc(LogDetailsFunc func) const {
|
||||
_logDetailsToStringFunc = func;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Format the log message according to it's type
|
||||
std::string LogMessage::toString(LogDetailsFunc formattingFunc) const {
|
||||
overrideLogDetailsFunc(formattingFunc);
|
||||
@ -137,87 +107,80 @@ namespace g3 {
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string LogMessage::timestamp(const std::string& time_look) const {
|
||||
return g3::localtime_formatted(to_system_time(_timestamp), time_look);
|
||||
}
|
||||
|
||||
|
||||
// By copy, not by reference. See this explanation for details:
|
||||
// http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom
|
||||
// By copy, not by reference. See this explanation for details:
|
||||
// http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom
|
||||
LogMessage& LogMessage::operator=(LogMessage other) {
|
||||
swap(*this, other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
LogMessage::LogMessage(std::string file, const int line,
|
||||
std::string function, const LEVELS level)
|
||||
: _logDetailsToStringFunc(LogMessage::DefaultLogDetailsToString)
|
||||
, _timestamp(std::chrono::high_resolution_clock::now())
|
||||
, _call_thread_id(std::this_thread::get_id())
|
||||
std::string function, const LEVELS level) :
|
||||
_logDetailsToStringFunc(LogMessage::DefaultLogDetailsToString),
|
||||
_timestamp(std::chrono::high_resolution_clock::now()),
|
||||
_call_thread_id(std::this_thread::get_id())
|
||||
#if defined(G3_LOG_FULL_FILENAME)
|
||||
, _file(file)
|
||||
,
|
||||
_file(file)
|
||||
#else
|
||||
, _file(LogMessage::splitFileName(file))
|
||||
,
|
||||
_file(LogMessage::splitFileName(file))
|
||||
#endif
|
||||
, _file_path(file)
|
||||
, _line(line)
|
||||
, _function(std::move(function))
|
||||
, _level(level) {
|
||||
,
|
||||
_file_path(file),
|
||||
_line(line),
|
||||
_function(std::move(function)),
|
||||
_level(level) {
|
||||
}
|
||||
|
||||
|
||||
LogMessage::LogMessage(const std::string& fatalOsSignalCrashMessage)
|
||||
: LogMessage( {""}, 0, {""}, internal::FATAL_SIGNAL) {
|
||||
LogMessage::LogMessage(const std::string& fatalOsSignalCrashMessage) :
|
||||
LogMessage({""}, 0, {""}, internal::FATAL_SIGNAL) {
|
||||
_message.append(fatalOsSignalCrashMessage);
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const LogMessage& other)
|
||||
: _logDetailsToStringFunc(other._logDetailsToStringFunc)
|
||||
, _timestamp(other._timestamp)
|
||||
, _call_thread_id(other._call_thread_id)
|
||||
, _file(other._file)
|
||||
, _file_path(other._file_path)
|
||||
, _line(other._line)
|
||||
, _function(other._function)
|
||||
, _level(other._level)
|
||||
, _expression(other._expression)
|
||||
, _message(other._message) {
|
||||
LogMessage::LogMessage(const LogMessage& other) :
|
||||
_logDetailsToStringFunc(other._logDetailsToStringFunc),
|
||||
_timestamp(other._timestamp),
|
||||
_call_thread_id(other._call_thread_id),
|
||||
_file(other._file),
|
||||
_file_path(other._file_path),
|
||||
_line(other._line),
|
||||
_function(other._function),
|
||||
_level(other._level),
|
||||
_expression(other._expression),
|
||||
_message(other._message) {
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(LogMessage&& other)
|
||||
: _logDetailsToStringFunc(other._logDetailsToStringFunc)
|
||||
, _timestamp(other._timestamp)
|
||||
, _call_thread_id(other._call_thread_id)
|
||||
, _file(std::move(other._file))
|
||||
, _file_path(std::move(other._file_path))
|
||||
, _line(other._line)
|
||||
, _function(std::move(other._function))
|
||||
, _level(other._level)
|
||||
, _expression(std::move(other._expression))
|
||||
, _message(std::move(other._message)) {
|
||||
LogMessage::LogMessage(LogMessage&& other) :
|
||||
_logDetailsToStringFunc(other._logDetailsToStringFunc),
|
||||
_timestamp(other._timestamp),
|
||||
_call_thread_id(other._call_thread_id),
|
||||
_file(std::move(other._file)),
|
||||
_file_path(std::move(other._file_path)),
|
||||
_line(other._line),
|
||||
_function(std::move(other._function)),
|
||||
_level(other._level),
|
||||
_expression(std::move(other._expression)),
|
||||
_message(std::move(other._message)) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string LogMessage::threadID() const {
|
||||
std::ostringstream oss;
|
||||
oss << _call_thread_id;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
FatalMessage::FatalMessage(const LogMessage& details, g3::SignalType signal_id) :
|
||||
LogMessage(details),
|
||||
_signal_id(signal_id) {}
|
||||
|
||||
|
||||
FatalMessage::FatalMessage(const LogMessage& details, g3::SignalType signal_id)
|
||||
: LogMessage(details), _signal_id(signal_id) { }
|
||||
|
||||
|
||||
|
||||
FatalMessage::FatalMessage(const FatalMessage& other)
|
||||
: LogMessage(other), _signal_id(other._signal_id) {}
|
||||
|
||||
FatalMessage::FatalMessage(const FatalMessage& other) :
|
||||
LogMessage(other),
|
||||
_signal_id(other._signal_id) {}
|
||||
|
||||
LogMessage FatalMessage::copyToLogMessage() const {
|
||||
return LogMessage(*this);
|
||||
@ -227,5 +190,4 @@ namespace g3 {
|
||||
return internal::exitReasonName(_level, _signal_id);
|
||||
}
|
||||
|
||||
|
||||
} // g3
|
||||
} // namespace g3
|
||||
|
@ -7,17 +7,18 @@
|
||||
* ============================================================================*/
|
||||
|
||||
#include "g3log/logworker.hpp"
|
||||
#include "g3log/logmessage.hpp"
|
||||
#include "g3log/active.hpp"
|
||||
#include "g3log/g3log.hpp"
|
||||
#include "g3log/future.hpp"
|
||||
#include "g3log/crashhandler.hpp"
|
||||
#include "g3log/future.hpp"
|
||||
#include "g3log/g3log.hpp"
|
||||
#include "g3log/logmessage.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace g3 {
|
||||
|
||||
LogWorkerImpl::LogWorkerImpl() : _bg(kjellkod::Active::createActive()) { }
|
||||
LogWorkerImpl::LogWorkerImpl() :
|
||||
_bg(kjellkod::Active::createActive()) {}
|
||||
|
||||
void LogWorkerImpl::bgSave(g3::LogMessagePtr msgPtr) {
|
||||
std::unique_ptr<LogMessage> uniqueMsg(std::move(msgPtr.get()));
|
||||
@ -28,7 +29,7 @@ namespace g3 {
|
||||
}
|
||||
|
||||
if (_sinks.empty()) {
|
||||
std::string err_msg {"g3logworker has no sinks. Message: ["};
|
||||
std::string err_msg{"g3logworker has no sinks. Message: ["};
|
||||
err_msg.append(uniqueMsg.get()->toString()).append("]\n");
|
||||
std::cerr << err_msg;
|
||||
}
|
||||
@ -43,16 +44,13 @@ namespace g3 {
|
||||
const auto level = msgPtr.get()->_level;
|
||||
const auto fatal_id = msgPtr.get()->_signal_id;
|
||||
|
||||
|
||||
std::unique_ptr<LogMessage> uniqueMsg(std::move(msgPtr.get()));
|
||||
uniqueMsg->write().append("\nExiting after fatal event (").append(uniqueMsg->level());
|
||||
|
||||
|
||||
// Change output in case of a fatal signal (or windows exception)
|
||||
std::string exiting = {"Fatal type: "};
|
||||
|
||||
uniqueMsg->write().append("). ").append(exiting).append(" ").append(reason)
|
||||
.append("\nLog content flushed successfully to sink\n\n");
|
||||
uniqueMsg->write().append("). ").append(exiting).append(" ").append(reason).append("\nLog content flushed successfully to sink\n\n");
|
||||
|
||||
std::cerr << uniqueMsg->toString() << std::flush;
|
||||
for (auto& sink : _sinks) {
|
||||
@ -60,7 +58,6 @@ namespace g3 {
|
||||
sink->send(LogMessageMover(std::move(msg)));
|
||||
}
|
||||
|
||||
|
||||
// This clear is absolutely necessary
|
||||
// All sinks are forced to receive the fatal message above before we continue
|
||||
_sinks.clear(); // flush all queues
|
||||
@ -102,15 +99,17 @@ namespace g3 {
|
||||
}
|
||||
|
||||
void LogWorker::save(LogMessagePtr msg) {
|
||||
_impl._bg->send([this, msg] {_impl.bgSave(msg); });
|
||||
_impl._bg->send([this, msg] { _impl.bgSave(msg); });
|
||||
}
|
||||
|
||||
void LogWorker::fatal(FatalMessagePtr fatal_message) {
|
||||
_impl._bg->send([this, fatal_message] {_impl.bgFatal(fatal_message); });
|
||||
_impl._bg->send([this, fatal_message] { _impl.bgFatal(fatal_message); });
|
||||
}
|
||||
|
||||
void LogWorker::addWrappedSink(std::shared_ptr<g3::internal::SinkWrapper> sink) {
|
||||
auto bg_addsink_call = [this, sink] {_impl._sinks.push_back(sink);};
|
||||
auto bg_addsink_call = [this, sink] {
|
||||
_impl._sinks.push_back(sink);
|
||||
};
|
||||
auto token_done = g3::spawn_task(bg_addsink_call, _impl._bg.get());
|
||||
token_done.wait();
|
||||
}
|
||||
@ -119,8 +118,8 @@ namespace g3 {
|
||||
return std::unique_ptr<LogWorker>(new LogWorker);
|
||||
}
|
||||
|
||||
std::unique_ptr<FileSinkHandle>LogWorker::addDefaultLogger(const std::string& log_prefix, const std::string& log_directory, const std::string& default_id) {
|
||||
std::unique_ptr<FileSinkHandle> LogWorker::addDefaultLogger(const std::string& log_prefix, const std::string& log_directory, const std::string& default_id) {
|
||||
return addSink(std::make_unique<g3::FileSink>(log_prefix, log_directory, default_id), &FileSink::fileWrite);
|
||||
}
|
||||
|
||||
} // g3
|
||||
} // namespace g3
|
||||
|
@ -14,58 +14,35 @@
|
||||
|
||||
#include "g3log/stacktrace_windows.hpp"
|
||||
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
#include <windows.h>
|
||||
#include <cassert>
|
||||
#include <g3log/g3log.hpp>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <g3log/g3log.hpp>
|
||||
#include <vector>
|
||||
|
||||
#pragma comment(lib, "dbghelp.lib")
|
||||
|
||||
|
||||
#if !(defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
||||
#error "stacktrace_win.cpp used but not on a windows system"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define g3_MAP_PAIR_STRINGIFY(x) {x, #x}
|
||||
#define g3_MAP_PAIR_STRINGIFY(x) \
|
||||
{ x, #x }
|
||||
|
||||
namespace {
|
||||
thread_local size_t g_thread_local_recursive_crash_check = 0;
|
||||
|
||||
const std::map<g3::SignalType, std::string> kExceptionsAsText = {
|
||||
g3_MAP_PAIR_STRINGIFY(EXCEPTION_ACCESS_VIOLATION)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_ARRAY_BOUNDS_EXCEEDED)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_DATATYPE_MISALIGNMENT)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_DENORMAL_OPERAND)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_DIVIDE_BY_ZERO)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_INEXACT_RESULT)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_INEXACT_RESULT)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_INVALID_OPERATION)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_OVERFLOW)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_STACK_CHECK)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_UNDERFLOW)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_ILLEGAL_INSTRUCTION)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_IN_PAGE_ERROR)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_INT_DIVIDE_BY_ZERO)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_INT_OVERFLOW)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_INVALID_DISPOSITION)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_NONCONTINUABLE_EXCEPTION)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_PRIV_INSTRUCTION)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_STACK_OVERFLOW)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_BREAKPOINT)
|
||||
, g3_MAP_PAIR_STRINGIFY(EXCEPTION_SINGLE_STEP)
|
||||
g3_MAP_PAIR_STRINGIFY(EXCEPTION_ACCESS_VIOLATION), g3_MAP_PAIR_STRINGIFY(EXCEPTION_ARRAY_BOUNDS_EXCEEDED), g3_MAP_PAIR_STRINGIFY(EXCEPTION_DATATYPE_MISALIGNMENT), g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_DENORMAL_OPERAND), g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_DIVIDE_BY_ZERO), g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_INEXACT_RESULT), g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_INEXACT_RESULT), g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_INVALID_OPERATION), g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_OVERFLOW), g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_STACK_CHECK), g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_UNDERFLOW), g3_MAP_PAIR_STRINGIFY(EXCEPTION_ILLEGAL_INSTRUCTION), g3_MAP_PAIR_STRINGIFY(EXCEPTION_IN_PAGE_ERROR), g3_MAP_PAIR_STRINGIFY(EXCEPTION_INT_DIVIDE_BY_ZERO), g3_MAP_PAIR_STRINGIFY(EXCEPTION_INT_OVERFLOW), g3_MAP_PAIR_STRINGIFY(EXCEPTION_INVALID_DISPOSITION), g3_MAP_PAIR_STRINGIFY(EXCEPTION_NONCONTINUABLE_EXCEPTION), g3_MAP_PAIR_STRINGIFY(EXCEPTION_PRIV_INSTRUCTION), g3_MAP_PAIR_STRINGIFY(EXCEPTION_STACK_OVERFLOW), g3_MAP_PAIR_STRINGIFY(EXCEPTION_BREAKPOINT), g3_MAP_PAIR_STRINGIFY(EXCEPTION_SINGLE_STEP)
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Using the given context, fill in all the stack frames.
|
||||
// Which then later can be interpreted to human readable text
|
||||
void captureStackTrace(CONTEXT *context, std::vector<uint64_t> &frame_pointers) {
|
||||
void captureStackTrace(CONTEXT* context, std::vector<uint64_t>& frame_pointers) {
|
||||
DWORD machine_type = 0;
|
||||
STACKFRAME64 frame = {}; // force zeroing
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
@ -92,8 +69,7 @@ namespace {
|
||||
frame.AddrPC.Offset = context->Esp;
|
||||
machine_type = IMAGE_FILE_MACHINE_I386;
|
||||
#endif
|
||||
for (size_t index = 0; index < frame_pointers.size(); ++index)
|
||||
{
|
||||
for (size_t index = 0; index < frame_pointers.size(); ++index) {
|
||||
if (StackWalk64(machine_type,
|
||||
GetCurrentProcess(),
|
||||
GetCurrentThread(),
|
||||
@ -110,18 +86,16 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// extract readable text from a given stack frame. All thanks to
|
||||
// using SymFromAddr and SymGetLineFromAddr64 with the stack pointer
|
||||
std::string getSymbolInformation(const size_t index, const std::vector<uint64_t> &frame_pointers) {
|
||||
std::string getSymbolInformation(const size_t index, const std::vector<uint64_t>& frame_pointers) {
|
||||
auto addr = frame_pointers[index];
|
||||
std::string frame_dump = "stack dump [" + std::to_string(index) + "]\t";
|
||||
|
||||
DWORD64 displacement64;
|
||||
DWORD displacement;
|
||||
alignas(SYMBOL_INFO) char symbol_buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
|
||||
SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO *>(symbol_buffer);
|
||||
SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>(symbol_buffer);
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
symbol->MaxNameLen = MAX_SYM_NAME;
|
||||
|
||||
@ -140,9 +114,8 @@ namespace {
|
||||
return frame_dump;
|
||||
}
|
||||
|
||||
|
||||
// Retrieves all the symbols for the stack frames, fills them within a text representation and returns it
|
||||
std::string convertFramesToText(std::vector<uint64_t> &frame_pointers) {
|
||||
std::string convertFramesToText(std::vector<uint64_t>& frame_pointers) {
|
||||
std::string dump; // slightly more efficient than ostringstream
|
||||
const size_t kSize = frame_pointers.size();
|
||||
for (size_t index = 0; index < kSize && frame_pointers[index]; ++index) {
|
||||
@ -151,10 +124,7 @@ namespace {
|
||||
}
|
||||
return dump;
|
||||
}
|
||||
} // anonymous
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace stacktrace {
|
||||
const std::string kUnknown = {"UNKNOWN EXCEPTION"};
|
||||
@ -162,7 +132,7 @@ namespace stacktrace {
|
||||
/// From MSDN GetExceptionCode http://msdn.microsoft.com/en-us/library/windows/desktop/ms679356(v=vs.85).aspx
|
||||
std::string exceptionIdToText(g3::SignalType id) {
|
||||
const auto iter = kExceptionsAsText.find(id);
|
||||
if ( iter == kExceptionsAsText.end()) {
|
||||
if (iter == kExceptionsAsText.end()) {
|
||||
std::string unknown = {kUnknown + ":" + std::to_string(id)};
|
||||
return unknown;
|
||||
}
|
||||
@ -185,15 +155,13 @@ namespace stacktrace {
|
||||
}
|
||||
|
||||
/// helper function: retrieve stackdump, starting from an exception pointer
|
||||
std::string stackdump(EXCEPTION_POINTERS *info) {
|
||||
std::string stackdump(EXCEPTION_POINTERS* info) {
|
||||
auto context = info->ContextRecord;
|
||||
return stackdump(context);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// main stackdump function. retrieve stackdump, from the given context
|
||||
std::string stackdump(CONTEXT *context) {
|
||||
std::string stackdump(CONTEXT* context) {
|
||||
|
||||
if (g_thread_local_recursive_crash_check >= 2) { // In Debug scenarios we allow one extra pass
|
||||
std::string recursive_crash = {"\n\n\n***** Recursive crash detected"};
|
||||
@ -208,14 +176,13 @@ namespace stacktrace {
|
||||
const BOOL kLoadSymModules = TRUE;
|
||||
const auto initialized = SymInitialize(GetCurrentProcess(), nullptr, kLoadSymModules);
|
||||
if (TRUE != initialized) {
|
||||
return { "Error: Cannot call SymInitialize(...) for retrieving symbols in stack" };
|
||||
return {"Error: Cannot call SymInitialize(...) for retrieving symbols in stack"};
|
||||
}
|
||||
|
||||
std::shared_ptr<void> RaiiSymCleaner(nullptr, [&](void *) {
|
||||
std::shared_ptr<void> RaiiSymCleaner(nullptr, [&](void*) {
|
||||
SymCleanup(GetCurrentProcess());
|
||||
}); // Raii sym cleanup
|
||||
|
||||
|
||||
constexpr size_t kmax_frame_dump_size = 64;
|
||||
std::vector<uint64_t> frame_pointers(kmax_frame_dump_size);
|
||||
// C++11: size set and values are zeroed
|
||||
@ -226,4 +193,4 @@ namespace stacktrace {
|
||||
}
|
||||
}
|
||||
|
||||
} // stacktrace
|
||||
} // namespace stacktrace
|
||||
|
46
src/time.cpp
46
src/time.cpp
@ -8,13 +8,13 @@
|
||||
|
||||
#include "g3log/time.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
#include <iomanip>
|
||||
#ifdef __MACH__
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
@ -28,10 +28,18 @@ namespace g3 {
|
||||
char ch = (format_buffer.size() > pos + kFractionalIdentierSize ? format_buffer.at(pos + kFractionalIdentierSize) : '\0');
|
||||
Fractional type = Fractional::NanosecondDefault;
|
||||
switch (ch) {
|
||||
case '3': type = Fractional::Millisecond; break;
|
||||
case '6': type = Fractional::Microsecond; break;
|
||||
case '9': type = Fractional::Nanosecond; break;
|
||||
default: type = Fractional::NanosecondDefault; break;
|
||||
case '3':
|
||||
type = Fractional::Millisecond;
|
||||
break;
|
||||
case '6':
|
||||
type = Fractional::Microsecond;
|
||||
break;
|
||||
case '9':
|
||||
type = Fractional::Nanosecond;
|
||||
break;
|
||||
default:
|
||||
type = Fractional::NanosecondDefault;
|
||||
break;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
@ -49,22 +57,21 @@ namespace g3 {
|
||||
auto zeroes = 9; // default ns
|
||||
auto digitsToCut = 1; // default ns, divide by 1 makes no change
|
||||
switch (fractional) {
|
||||
case Fractional::Millisecond : {
|
||||
case Fractional::Millisecond: {
|
||||
zeroes = 3;
|
||||
digitsToCut = 1000000;
|
||||
break;
|
||||
}
|
||||
case Fractional::Microsecond : {
|
||||
case Fractional::Microsecond: {
|
||||
zeroes = 6;
|
||||
digitsToCut = 1000;
|
||||
break;
|
||||
}
|
||||
case Fractional::Nanosecond :
|
||||
case Fractional::Nanosecond:
|
||||
case Fractional::NanosecondDefault:
|
||||
default:
|
||||
zeroes = 9;
|
||||
digitsToCut = 1;
|
||||
|
||||
}
|
||||
|
||||
ns /= digitsToCut;
|
||||
@ -92,10 +99,8 @@ namespace g3 {
|
||||
return format_buffer;
|
||||
}
|
||||
|
||||
} // internal
|
||||
} // g3
|
||||
|
||||
|
||||
} // namespace internal
|
||||
} // namespace g3
|
||||
|
||||
namespace g3 {
|
||||
// This mimics the original "std::put_time(const std::tm* tmb, const charT* fmt)"
|
||||
@ -106,7 +111,7 @@ namespace g3 {
|
||||
std::ostringstream oss;
|
||||
oss.fill('0');
|
||||
// BOGUS hack done for VS2012: C++11 non-conformant since it SHOULD take a "const struct tm* "
|
||||
oss << std::put_time(const_cast<struct tm*> (tmb), c_time_format);
|
||||
oss << std::put_time(const_cast<struct tm*>(tmb), c_time_format);
|
||||
return oss.str();
|
||||
#else // LINUX
|
||||
const size_t size = 1024;
|
||||
@ -127,8 +132,6 @@ namespace g3 {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
tm localtime(std::time_t ts) {
|
||||
struct tm tm_snapshot;
|
||||
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
||||
@ -139,11 +142,10 @@ namespace g3 {
|
||||
return tm_snapshot;
|
||||
}
|
||||
|
||||
|
||||
std::string localtime_formatted(const g3::system_time_point& ts, const std::string& time_format) {
|
||||
auto format_buffer = internal::localtime_formatted_fractions(ts, time_format);
|
||||
auto time_point = std::chrono::system_clock::to_time_t(ts);
|
||||
std::tm t = localtime(time_point);
|
||||
return g3::put_time(&t, format_buffer.c_str()); // format example: //"%Y/%m/%d %H:%M:%S");
|
||||
}
|
||||
} // g3
|
||||
} // namespace g3
|
||||
|
@ -1,24 +0,0 @@
|
||||
{
|
||||
"AStyleFormatter":
|
||||
{
|
||||
"options_default":
|
||||
{
|
||||
"indent": "spaces",
|
||||
"indent-modifiers": false,
|
||||
"indent-namespaces": true,
|
||||
"indent-preproc-block": true,
|
||||
"indent-spaces": 3,
|
||||
"style": "googles"
|
||||
}
|
||||
},
|
||||
"color_scheme": "Packages/Color Scheme - Default/Twilight.tmTheme",
|
||||
"font_size": 11,
|
||||
"highlight_modified_tabs": true,
|
||||
"ignored_packages":
|
||||
[
|
||||
"Vintage"
|
||||
],
|
||||
"tab_size": 3,
|
||||
"translate_tabs_to_spaces": true,
|
||||
"word_wrap": true
|
||||
}
|
@ -7,11 +7,9 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int main(int argc, char* argv[]) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
int return_value = RUN_ALL_TESTS();
|
||||
std::cout << "FINISHED WITH THE TESTING" << std::endl;
|
||||
return return_value;
|
||||
}
|
||||
|
||||
|
@ -7,10 +7,10 @@
|
||||
* ============================================================================*/
|
||||
|
||||
// through CMakeLists.txt #define of GOOGLE_GLOG_PERFORMANCE and G3LOG_PERFORMANCE
|
||||
#include "performance.h"
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include "performance.h"
|
||||
|
||||
#if defined(G3LOG_PERFORMANCE)
|
||||
const std::string title = "G3LOG";
|
||||
@ -27,8 +27,7 @@ const std::string g_path = "/tmp/";
|
||||
#endif
|
||||
using namespace g3_test;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char** argv) {
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
std::cerr << "G3_DYNAMIC_LOGGING is enabled" << std::endl;
|
||||
#else
|
||||
@ -36,12 +35,10 @@ int main(int argc, char **argv)
|
||||
#endif
|
||||
|
||||
size_t number_of_threads = 0;
|
||||
if (argc == 2)
|
||||
{
|
||||
if (argc == 2) {
|
||||
number_of_threads = atoi(argv[1]);
|
||||
}
|
||||
if (argc != 2 || number_of_threads == 0)
|
||||
{
|
||||
if (argc != 2 || number_of_threads == 0) {
|
||||
std::cerr << "USAGE is: " << argv[0] << " number_threads" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
@ -53,41 +50,39 @@ int main(int argc, char **argv)
|
||||
|
||||
std::ostringstream oss;
|
||||
const uint64_t us_to_s = 1000000;
|
||||
oss << "\n\n" << title << " performance " << number_of_threads << " threads MEAN times\n";
|
||||
oss << "\n\n"
|
||||
<< title << " performance " << number_of_threads << " threads MEAN times\n";
|
||||
oss << "Each thread running #: " << g_loop << " * " << g_iterations << " iterations of log entries" << std::endl; // worst mean case is about 10us per log entry
|
||||
const uint64_t xtra_margin = 2;
|
||||
oss << "*** It can take som time. Please wait: Approximate wait time on MY PC was: " << number_of_threads* (uint64_t) (g_iterations * 10 * xtra_margin / us_to_s ) << " seconds" << std::endl;
|
||||
oss << "*** It can take som time. Please wait: Approximate wait time on MY PC was: " << number_of_threads * (uint64_t)(g_iterations * 10 * xtra_margin / us_to_s) << " seconds" << std::endl;
|
||||
writeTextToFile(g_measurement_dump, oss.str(), kAppend);
|
||||
oss.str(""); // clear the stream
|
||||
|
||||
#if defined(G3LOG_PERFORMANCE)
|
||||
auto worker = g3::LogWorker::createLogWorker();
|
||||
auto handle= worker->addDefaultLogger(g_prefix_log_name, g_path);
|
||||
auto handle = worker->addDefaultLogger(g_prefix_log_name, g_path);
|
||||
g3::initializeLogging(worker.get());
|
||||
|
||||
|
||||
#elif defined(GOOGLE_GLOG_PERFORMANCE)
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
#endif
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
std::thread *threads = new std::thread[number_of_threads];
|
||||
std::thread* threads = new std::thread[number_of_threads];
|
||||
// kiss: just loop, create threads, store them then join
|
||||
// could probably do this more elegant with lambdas
|
||||
for (size_t idx = 0; idx < number_of_threads; ++idx)
|
||||
{
|
||||
for (size_t idx = 0; idx < number_of_threads; ++idx) {
|
||||
std::ostringstream count;
|
||||
count << idx + 1;
|
||||
std::string thread_name = title + "_T" + count.str();
|
||||
std::cout << "Creating thread: " << thread_name << std::endl;
|
||||
threads[idx] = std::thread(doLogWrites, thread_name);
|
||||
}
|
||||
for (size_t idx = 0; idx < number_of_threads; ++idx)
|
||||
{
|
||||
for (size_t idx = 0; idx < number_of_threads; ++idx) {
|
||||
threads[idx].join();
|
||||
}
|
||||
auto application_end_time = std::chrono::high_resolution_clock::now();
|
||||
delete [] threads;
|
||||
delete[] threads;
|
||||
|
||||
#if defined(G3LOG_PERFORMANCE)
|
||||
worker.reset(); // will flush anything in the queue to file
|
||||
@ -99,9 +94,10 @@ int main(int argc, char **argv)
|
||||
uint64_t application_time_us = std::chrono::duration_cast<microsecond>(application_end_time - start_time).count();
|
||||
uint64_t total_time_us = std::chrono::duration_cast<microsecond>(worker_end_time - start_time).count();
|
||||
|
||||
oss << "\n" << number_of_threads << "*" << g_iterations << " log entries took: [" << total_time_us / 1000000 << " s] to write to disk" << std::endl;
|
||||
oss << "\n"
|
||||
<< number_of_threads << "*" << g_iterations << " log entries took: [" << total_time_us / 1000000 << " s] to write to disk" << std::endl;
|
||||
oss << "[Application(" << number_of_threads << "):\t\t:" << application_time_us / 1000 << " ms]" << std::endl;
|
||||
oss << "[Background thread to finish\t:" << total_time_us / uint64_t(1000 ) << " ms]" << std::endl;
|
||||
oss << "[Background thread to finish\t:" << total_time_us / uint64_t(1000) << " ms]" << std::endl;
|
||||
oss << "\nAverage time per log entry:" << std::endl;
|
||||
oss << "[Application: " << application_time_us / (number_of_threads * g_iterations) << " us]" << std::endl;
|
||||
oss << "[Background+Application: " << total_time_us / (number_of_threads * g_iterations) << " us]" << std::endl;
|
||||
|
@ -9,53 +9,42 @@
|
||||
// through CMakeLists.txt #define of GOOGLE_GLOG_PERFORMANCE and G3LOG_PERFORMANCE
|
||||
#include "performance.h"
|
||||
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#if defined(G3LOG_PERFORMANCE)
|
||||
const std::string title {
|
||||
"G3LOG"
|
||||
};
|
||||
const std::string title{
|
||||
"G3LOG"};
|
||||
#elif defined(GOOGLE_GLOG_PERFORMANCE)
|
||||
const std::string title {
|
||||
"GOOGLE__GLOG"
|
||||
};
|
||||
const std::string title{
|
||||
"GOOGLE__GLOG"};
|
||||
#else
|
||||
#error G3LOG_PERFORMANCE or GOOGLE_GLOG_PERFORMANCE was not defined
|
||||
#endif
|
||||
|
||||
|
||||
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
||||
const std::string g_path {
|
||||
"./"
|
||||
};
|
||||
const std::string g_path{
|
||||
"./"};
|
||||
#else
|
||||
const std::string g_path {
|
||||
"/tmp/"
|
||||
};
|
||||
const std::string g_path{
|
||||
"/tmp/"};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
using namespace g3_test;
|
||||
|
||||
|
||||
//
|
||||
// OK: The code below isn't pretty but it works. Lots and lots of log entries
|
||||
// to keep track of!
|
||||
//
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
size_t number_of_threads {0};
|
||||
if (argc == 2)
|
||||
{
|
||||
int main(int argc, char** argv) {
|
||||
size_t number_of_threads{0};
|
||||
if (argc == 2) {
|
||||
number_of_threads = atoi(argv[1]);
|
||||
}
|
||||
if (argc != 2 || number_of_threads == 0)
|
||||
{
|
||||
if (argc != 2 || number_of_threads == 0) {
|
||||
std::cerr << "USAGE is: " << argv[0] << " number_threads" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
@ -65,27 +54,24 @@ int main(int argc, char** argv)
|
||||
const std::string g_prefix_log_name = title + "-performance-" + thread_count_oss.str() + "threads-WORST_LOG";
|
||||
const std::string g_measurement_dump = g_path + g_prefix_log_name + "_RESULT.txt";
|
||||
const std::string g_measurement_bucket_dump = g_path + g_prefix_log_name + "_RESULT_buckets.txt";
|
||||
const uint64_t us_to_ms {
|
||||
1000
|
||||
};
|
||||
const uint64_t us_to_s {
|
||||
1000000
|
||||
};
|
||||
|
||||
const uint64_t us_to_ms{
|
||||
1000};
|
||||
const uint64_t us_to_s{
|
||||
1000000};
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "\n\n" << title << " performance " << number_of_threads << " threads WORST (PEAK) times\n";
|
||||
oss << "\n\n"
|
||||
<< title << " performance " << number_of_threads << " threads WORST (PEAK) times\n";
|
||||
oss << "Each thread running #: " << g_loop << " * " << g_iterations << " iterations of log entries" << std::endl; // worst mean case is about 10us per log entry
|
||||
const uint64_t xtra_margin {
|
||||
2
|
||||
};
|
||||
const uint64_t xtra_margin{
|
||||
2};
|
||||
oss << "*** It can take som time. Please wait: Approximate wait time on MY PC was: " << number_of_threads * (uint64_t)(g_iterations * 10 * xtra_margin / us_to_s) << " seconds" << std::endl;
|
||||
writeTextToFile(g_measurement_dump, oss.str(), kAppend);
|
||||
oss.str(""); // clear the stream
|
||||
|
||||
#if defined(G3LOG_PERFORMANCE)
|
||||
auto worker = g3::LogWorker::createLogWorker();
|
||||
auto handle= worker->addDefaultLogger(g_prefix_log_name, g_path);
|
||||
auto handle = worker->addDefaultLogger(g_prefix_log_name, g_path);
|
||||
g3::initializeLogging(worker.get());
|
||||
|
||||
#elif defined(GOOGLE_GLOG_PERFORMANCE)
|
||||
@ -97,14 +83,12 @@ int main(int argc, char** argv)
|
||||
|
||||
// kiss: just loop, create threads, store them then join
|
||||
// could probably do this more elegant with lambdas
|
||||
for (uint64_t idx = 0; idx < number_of_threads; ++idx)
|
||||
{
|
||||
for (uint64_t idx = 0; idx < number_of_threads; ++idx) {
|
||||
threads_result[idx].reserve(g_iterations);
|
||||
}
|
||||
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
for (uint64_t idx = 0; idx < number_of_threads; ++idx)
|
||||
{
|
||||
for (uint64_t idx = 0; idx < number_of_threads; ++idx) {
|
||||
std::ostringstream count;
|
||||
count << idx + 1;
|
||||
std::string thread_name = title + "_T" + count.str();
|
||||
@ -112,13 +96,11 @@ int main(int argc, char** argv)
|
||||
threads[idx] = std::thread(measurePeakDuringLogWrites, thread_name, std::ref(threads_result[idx]));
|
||||
}
|
||||
// wait for thread finishing
|
||||
for (uint64_t idx = 0; idx < number_of_threads; ++idx)
|
||||
{
|
||||
for (uint64_t idx = 0; idx < number_of_threads; ++idx) {
|
||||
threads[idx].join();
|
||||
}
|
||||
auto application_end_time = std::chrono::high_resolution_clock::now();
|
||||
delete [] threads;
|
||||
|
||||
delete[] threads;
|
||||
|
||||
#if defined(G3LOG_PERFORMANCE)
|
||||
worker.reset(); // will flush anything in the queue to file
|
||||
@ -130,15 +112,15 @@ int main(int argc, char** argv)
|
||||
uint64_t application_time_us = std::chrono::duration_cast<microsecond>(application_end_time - start_time).count();
|
||||
uint64_t total_time_us = std::chrono::duration_cast<microsecond>(worker_end_time - start_time).count();
|
||||
|
||||
oss << "\n" << number_of_threads << "*" << g_iterations << " log entries took: [" << total_time_us / us_to_s << " s] to write to disk" << std::endl;
|
||||
oss << "\n"
|
||||
<< number_of_threads << "*" << g_iterations << " log entries took: [" << total_time_us / us_to_s << " s] to write to disk" << std::endl;
|
||||
oss << "[Application(" << number_of_threads << "_threads+overhead time for measurement):\t" << application_time_us / us_to_ms << " ms]" << std::endl;
|
||||
oss << "[Background thread to finish:\t\t\t\t" << total_time_us / us_to_ms << " ms]" << std::endl;
|
||||
oss << "\nAverage time per log entry:" << std::endl;
|
||||
oss << "[Application: " << application_time_us / (number_of_threads * g_iterations) << " us]" << std::endl;
|
||||
|
||||
for (uint64_t idx = 0; idx < number_of_threads; ++idx)
|
||||
{
|
||||
std::vector<uint64_t> &t_result = threads_result[idx];
|
||||
for (uint64_t idx = 0; idx < number_of_threads; ++idx) {
|
||||
std::vector<uint64_t>& t_result = threads_result[idx];
|
||||
uint64_t worstUs = (*std::max_element(t_result.begin(), t_result.end()));
|
||||
oss << "[Application t" << idx + 1 << " worst took: " << worstUs / uint64_t(1000) << " ms (" << worstUs << " us)] " << std::endl;
|
||||
}
|
||||
@ -148,19 +130,17 @@ int main(int argc, char** argv)
|
||||
// now split the result in buckets of 10ms each so that it's obvious how the peaks go
|
||||
std::vector<uint64_t> all_measurements;
|
||||
all_measurements.reserve(g_iterations * number_of_threads);
|
||||
for (uint64_t idx = 0; idx < number_of_threads; ++idx)
|
||||
{
|
||||
std::vector<uint64_t> &t_result = threads_result[idx];
|
||||
for (uint64_t idx = 0; idx < number_of_threads; ++idx) {
|
||||
std::vector<uint64_t>& t_result = threads_result[idx];
|
||||
all_measurements.insert(all_measurements.end(), t_result.begin(), t_result.end());
|
||||
}
|
||||
delete [] threads_result; // finally get rid of them
|
||||
delete[] threads_result; // finally get rid of them
|
||||
|
||||
std::sort (all_measurements.begin(), all_measurements.end());
|
||||
std::sort(all_measurements.begin(), all_measurements.end());
|
||||
std::map<uint64_t, uint64_t> value_amounts;
|
||||
std::map<uint64_t, uint64_t> value_amounts_for_0ms_bucket;
|
||||
|
||||
for (auto iter = all_measurements.begin(); iter != all_measurements.end(); ++iter)
|
||||
{
|
||||
for (auto iter = all_measurements.begin(); iter != all_measurements.end(); ++iter) {
|
||||
uint64_t value = (*iter) / us_to_ms; // convert to ms
|
||||
++value_amounts[value]; // asuming uint64_t is default 0 when initialized
|
||||
|
||||
@ -172,11 +152,12 @@ int main(int argc, char** argv)
|
||||
oss.str("");
|
||||
oss << "Number of values rounded to milliseconds and put to [millisecond bucket] were dumped to file: " << g_measurement_bucket_dump << std::endl;
|
||||
if (1 == value_amounts.size()) {
|
||||
oss << "Format: bucket of us inside bucket0 for ms\nFormat:bucket_of_ms, number_of_values_in_bucket\n\n" << std::endl;
|
||||
oss << "Format: bucket of us inside bucket0 for ms\nFormat:bucket_of_ms, number_of_values_in_bucket\n\n"
|
||||
<< std::endl;
|
||||
oss << "\n";
|
||||
}
|
||||
else {
|
||||
oss << "Format:bucket_of_ms, number_of_values_in_bucket\n\n" << std::endl;
|
||||
} else {
|
||||
oss << "Format:bucket_of_ms, number_of_values_in_bucket\n\n"
|
||||
<< std::endl;
|
||||
}
|
||||
std::cout << oss.str() << std::endl;
|
||||
|
||||
@ -191,12 +172,10 @@ int main(int argc, char** argv)
|
||||
oss << "\n\n***** Millisecond bucket measurement ****\n";
|
||||
}
|
||||
|
||||
for (auto ms_bucket : value_amounts)
|
||||
{
|
||||
for (auto ms_bucket : value_amounts) {
|
||||
oss << ms_bucket.first << "\t, " << ms_bucket.second << std::endl;
|
||||
}
|
||||
writeTextToFile(g_measurement_bucket_dump, oss.str(), kAppend, false);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -11,17 +11,13 @@
|
||||
|
||||
# ============================================================================
|
||||
# TEST OPTIONS: Turn OFF the ones that is of no interest to you
|
||||
# ---- by default all is OFF: except 'g3log-FATAL-example -----
|
||||
# ---- the reason for this is that
|
||||
# ----- 1) the performance tests were only thoroughly tested on Ubuntu, not windows-
|
||||
# (g3log windows/linux, but Google's glog only on linux)
|
||||
#
|
||||
# 2) The unit test were tested windows/linux
|
||||
# ---- by default unit tests and g3log-FATAL-example are enabled.
|
||||
# Performance tests are turned off by default since they were not tested on Windows.
|
||||
# ============================================================================
|
||||
|
||||
|
||||
# Unit test for g3log (cmake -DUSE_G3LOG_UNIT_TEST=ON ..)
|
||||
option (ADD_G3LOG_UNIT_TEST "g3log unit tests" OFF)
|
||||
option (ADD_G3LOG_UNIT_TEST "g3log unit tests" ON)
|
||||
|
||||
|
||||
# 4. create the unit tests for g3log --- ONLY TESTED THE UNIT TEST ON LINUX
|
||||
|
@ -8,19 +8,19 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
#include "testing_helpers.h"
|
||||
#include "g3log/sink.hpp"
|
||||
#include "g3log/sinkwrapper.hpp"
|
||||
#include "g3log/sinkhandle.hpp"
|
||||
#include "g3log/logmessage.hpp"
|
||||
#include "g3log/generated_definitions.hpp"
|
||||
#include "g3log/logmessage.hpp"
|
||||
#include "g3log/sink.hpp"
|
||||
#include "g3log/sinkhandle.hpp"
|
||||
#include "g3log/sinkwrapper.hpp"
|
||||
#include "testing_helpers.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace testing_helpers;
|
||||
@ -29,24 +29,25 @@ class CoutSink {
|
||||
stringstream buffer;
|
||||
unique_ptr<ScopedOut> scope_ptr;
|
||||
|
||||
CoutSink() : scope_ptr(std::make_unique<ScopedOut>(std::cout, &buffer)) {}
|
||||
CoutSink() :
|
||||
scope_ptr(std::make_unique<ScopedOut>(std::cout, &buffer)) {}
|
||||
|
||||
public:
|
||||
void clear() { buffer.str(""); }
|
||||
std::string string() { return buffer.str(); }
|
||||
void save(g3::LogMessageMover msg) { std::cout << msg.get().message(); }
|
||||
virtual ~CoutSink() final {}
|
||||
static std::unique_ptr<CoutSink> createSink() { return std::unique_ptr<CoutSink>(new CoutSink);}
|
||||
static std::unique_ptr<CoutSink> createSink() { return std::unique_ptr<CoutSink>(new CoutSink); }
|
||||
};
|
||||
|
||||
struct StringSink {
|
||||
std::string raw;
|
||||
void append(g3::LogMessageMover entry) { raw.append(entry.get().message());}
|
||||
void append(g3::LogMessageMover entry) { raw.append(entry.get().message()); }
|
||||
std::string string() {
|
||||
return raw;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
namespace {
|
||||
typedef std::shared_ptr<g3::internal::SinkWrapper> SinkWrapperPtr;
|
||||
}
|
||||
@ -66,10 +67,9 @@ namespace g3 {
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Worker() : _bg {
|
||||
kjellkod::Active::createActive()
|
||||
} {
|
||||
Worker() :
|
||||
_bg{
|
||||
kjellkod::Active::createActive()} {
|
||||
}
|
||||
|
||||
~Worker() {
|
||||
@ -82,35 +82,31 @@ namespace g3 {
|
||||
_bg->send([this, msg] { bgSave(msg); });
|
||||
}
|
||||
|
||||
|
||||
template<typename T, typename DefaultLogCall>
|
||||
std::unique_ptr< SinkHandle<T> > addSink(std::unique_ptr<T> unique, DefaultLogCall call) {
|
||||
auto sink = std::make_shared < internal::Sink<T> > (std::move(unique), call);
|
||||
auto add_sink_call = [this, sink] { _container.push_back(sink); };
|
||||
template <typename T, typename DefaultLogCall>
|
||||
std::unique_ptr<SinkHandle<T>> addSink(std::unique_ptr<T> unique, DefaultLogCall call) {
|
||||
auto sink = std::make_shared<internal::Sink<T>>(std::move(unique), call);
|
||||
auto add_sink_call = [this, sink] {
|
||||
_container.push_back(sink);
|
||||
};
|
||||
auto wait_result = g3::spawn_task(add_sink_call, _bg.get());
|
||||
wait_result.wait();
|
||||
|
||||
auto handle = std::make_unique< SinkHandle<T> >(sink);
|
||||
auto handle = std::make_unique<SinkHandle<T>>(sink);
|
||||
return handle;
|
||||
}
|
||||
};
|
||||
|
||||
} // g3
|
||||
|
||||
|
||||
|
||||
} // namespace g3
|
||||
|
||||
using namespace g3;
|
||||
using namespace g3::internal;
|
||||
|
||||
|
||||
TEST(ConceptSink, CreateHandle) {
|
||||
Worker worker;
|
||||
auto handle = worker.addSink(CoutSink::createSink(), &CoutSink::save);
|
||||
ASSERT_NE(nullptr, handle.get());
|
||||
}
|
||||
|
||||
|
||||
TEST(ConceptSink, OneSink__VerifyMsgIn) {
|
||||
Worker worker;
|
||||
auto handle = worker.addSink(CoutSink::createSink(), &CoutSink::save);
|
||||
@ -122,19 +118,16 @@ TEST(ConceptSink, OneSink__VerifyMsgIn) {
|
||||
ASSERT_NE(pos, std::string::npos);
|
||||
}
|
||||
|
||||
|
||||
TEST(ConceptSink, DualSink__VerifyMsgIn) {
|
||||
Worker worker;
|
||||
auto h1 = worker.addSink(CoutSink::createSink(), &CoutSink::save);
|
||||
auto h2 = worker.addSink(std::make_unique<StringSink>(), &StringSink::append);
|
||||
worker.save("Hello World!");
|
||||
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
auto first = h1->call(&CoutSink::string);
|
||||
auto second = h2->call(&StringSink::string);
|
||||
|
||||
|
||||
ASSERT_EQ("Hello World!", first.get());
|
||||
ASSERT_EQ("Hello World!", second.get());
|
||||
}
|
||||
@ -151,10 +144,10 @@ TEST(ConceptSink, DeletedSink__Exptect_badweak_ptr___exception) {
|
||||
|
||||
namespace {
|
||||
using AtomicBooleanPtr = std::shared_ptr<std::atomic<bool>>;
|
||||
using AtomicIntegerPtr = std::shared_ptr<std::atomic<int>> ;
|
||||
using BoolList = std::vector<AtomicBooleanPtr> ;
|
||||
using AtomicIntegerPtr = std::shared_ptr<std::atomic<int>>;
|
||||
using BoolList = std::vector<AtomicBooleanPtr>;
|
||||
using IntVector = std::vector<AtomicIntegerPtr>;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(ConceptSink, OneHundredSinks_part1) {
|
||||
BoolList flags;
|
||||
@ -162,8 +155,8 @@ TEST(ConceptSink, OneHundredSinks_part1) {
|
||||
|
||||
size_t NumberOfItems = 100;
|
||||
for (size_t index = 0; index < NumberOfItems; ++index) {
|
||||
flags.push_back(make_shared < atomic<bool >> (false));
|
||||
counts.push_back(make_shared < atomic<int >> (0));
|
||||
flags.push_back(make_shared<atomic<bool>>(false));
|
||||
counts.push_back(make_shared<atomic<int>>(0));
|
||||
}
|
||||
|
||||
{
|
||||
@ -190,10 +183,9 @@ TEST(ConceptSink, OneHundredSinks_part1) {
|
||||
cout << "test one hundred sinks is finished\n";
|
||||
}
|
||||
|
||||
|
||||
TEST(ConceptSink, OneHundredSinks_part2) {
|
||||
using BoolPtrVector = std::vector<AtomicBooleanPtr> ;
|
||||
using IntPtrVector = vector<AtomicIntegerPtr> ;
|
||||
using BoolPtrVector = std::vector<AtomicBooleanPtr>;
|
||||
using IntPtrVector = vector<AtomicIntegerPtr>;
|
||||
BoolPtrVector flags;
|
||||
IntPtrVector counts;
|
||||
|
||||
@ -233,7 +225,6 @@ TEST(ConceptSink, OneHundredSinks_part2) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(ConceptSink, OneSinkWithHandleOutOfScope) {
|
||||
AtomicBooleanPtr flag = make_shared<atomic<bool>>(false);
|
||||
AtomicIntegerPtr count = make_shared<atomic<int>>(0);
|
||||
|
@ -9,19 +9,17 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <future>
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include "g3log/time.hpp"
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include "g3log/future.hpp"
|
||||
#include "g3log/time.hpp"
|
||||
|
||||
|
||||
std::future<std::string> sillyFutureReturn()
|
||||
{
|
||||
std::packaged_task<std::string()> task([](){return std::string("Hello Future");}); // wrap the function
|
||||
std::future<std::string> sillyFutureReturn() {
|
||||
std::packaged_task<std::string()> task([]() { return std::string("Hello Future"); }); // wrap the function
|
||||
std::future<std::string> result = task.get_future(); // get a future
|
||||
std::thread(std::move(task)).detach(); // launch on a thread
|
||||
std::cout << "Waiting...";
|
||||
@ -29,23 +27,19 @@ std::future<std::string> sillyFutureReturn()
|
||||
return result; // already wasted
|
||||
}
|
||||
|
||||
|
||||
TEST(Configuration, FutureSilly)
|
||||
{
|
||||
TEST(Configuration, FutureSilly) {
|
||||
std::string hello = sillyFutureReturn().get();
|
||||
ASSERT_STREQ(hello.c_str(), "Hello Future");
|
||||
}
|
||||
|
||||
struct MsgType
|
||||
{
|
||||
struct MsgType {
|
||||
std::string msg_;
|
||||
MsgType(std::string m): msg_(m){};
|
||||
std::string msg(){return msg_;}
|
||||
MsgType(std::string m) :
|
||||
msg_(m){};
|
||||
std::string msg() { return msg_; }
|
||||
};
|
||||
|
||||
|
||||
TEST(TestOf_CopyableCall, Expecting_SmoothSailing)
|
||||
{
|
||||
TEST(TestOf_CopyableCall, Expecting_SmoothSailing) {
|
||||
using namespace kjellkod;
|
||||
const std::string str("Hello from struct");
|
||||
MsgType type(str);
|
||||
@ -55,28 +49,23 @@ TEST(TestOf_CopyableCall, Expecting_SmoothSailing)
|
||||
ASSERT_STREQ(str.c_str(), fstring.get().c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST(TestOf_CopyableLambdaCall, Expecting_AllFine)
|
||||
{
|
||||
TEST(TestOf_CopyableLambdaCall, Expecting_AllFine) {
|
||||
using namespace kjellkod;
|
||||
std::unique_ptr<Active> bgWorker(Active::createActive());
|
||||
|
||||
// lambda task
|
||||
const std::string str_standalone("Hello from standalone");
|
||||
auto msg_lambda=[=](){return (str_standalone+str_standalone);};
|
||||
std::string expected(str_standalone+str_standalone);
|
||||
auto msg_lambda = [=]() {
|
||||
return (str_standalone + str_standalone);
|
||||
};
|
||||
std::string expected(str_standalone + str_standalone);
|
||||
|
||||
auto fstring_standalone = g3::spawn_task(msg_lambda, bgWorker.get());
|
||||
ASSERT_STREQ(expected.c_str(), fstring_standalone.get().c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename F>
|
||||
std::future<std::invoke_result_t<F>> ObsoleteSpawnTask(F f)
|
||||
{
|
||||
template <typename F>
|
||||
std::future<std::invoke_result_t<F>> ObsoleteSpawnTask(F f) {
|
||||
typedef std::invoke_result_t<F> result_type;
|
||||
typedef std::packaged_task<result_type()> task_type;
|
||||
|
||||
@ -90,11 +79,12 @@ std::future<std::invoke_result_t<F>> ObsoleteSpawnTask(F f)
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
TEST(TestOf_ObsoleteSpawnTaskWithStringReturn, Expecting_FutureString)
|
||||
{
|
||||
TEST(TestOf_ObsoleteSpawnTaskWithStringReturn, Expecting_FutureString) {
|
||||
std::string str("Hello");
|
||||
std::string expected(str+str);
|
||||
auto msg_lambda=[=](){return (str+str);};
|
||||
std::string expected(str + str);
|
||||
auto msg_lambda = [=]() {
|
||||
return (str + str);
|
||||
};
|
||||
auto future_string = ObsoleteSpawnTask(msg_lambda);
|
||||
|
||||
ASSERT_STREQ(expected.c_str(), future_string.get().c_str());
|
||||
@ -105,22 +95,20 @@ TEST(TestOf_ObsoleteSpawnTaskWithStringReturn, Expecting_FutureString)
|
||||
// http://gcc.gnu.org/ml/gcc-help/2011-11/msg00052.html
|
||||
|
||||
// --------------------------------------------------------------
|
||||
namespace WORKING
|
||||
{
|
||||
namespace WORKING {
|
||||
using namespace g3;
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
std::vector<std::function<void()>> vec;
|
||||
|
||||
template<typename F>
|
||||
std::future<std::invoke_result_t<F>> spawn_task(F f)
|
||||
{
|
||||
template <typename F>
|
||||
std::future<std::invoke_result_t<F>> spawn_task(F f) {
|
||||
typedef std::invoke_result_t<F> result_type;
|
||||
typedef std::packaged_task<result_type()> task_type;
|
||||
|
||||
@ -131,29 +119,25 @@ namespace WORKING
|
||||
MoveOnCopy<task_type>(
|
||||
std::move(task)));
|
||||
|
||||
std::thread([]()
|
||||
{
|
||||
std::thread([]() {
|
||||
auto task = std::move(vec.back());
|
||||
vec.pop_back();
|
||||
task();
|
||||
}
|
||||
).detach();
|
||||
}).detach();
|
||||
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
|
||||
|
||||
double get_res()
|
||||
{
|
||||
double get_res() {
|
||||
return 42.2;
|
||||
}
|
||||
|
||||
std::string msg3(){return "msg3";}
|
||||
} // WORKING
|
||||
std::string msg3() {
|
||||
return "msg3";
|
||||
}
|
||||
} // namespace WORKING
|
||||
|
||||
TEST(Yalla, Testar)
|
||||
{
|
||||
TEST(Yalla, Testar) {
|
||||
using namespace WORKING;
|
||||
auto f = spawn_task(get_res);
|
||||
ASSERT_EQ(42.2, f.get());
|
||||
@ -161,11 +145,5 @@ TEST(Yalla, Testar)
|
||||
auto f2 = spawn_task(msg3);
|
||||
ASSERT_EQ("msg3", f2.get());
|
||||
|
||||
|
||||
ASSERT_TRUE(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -6,13 +6,11 @@
|
||||
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
|
||||
* ============================================================================*/
|
||||
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
||||
#include "g3log/stacktrace_windows.hpp"
|
||||
#include <windows.h>
|
||||
|
||||
#include "g3log/stacktrace_windows.hpp"
|
||||
|
||||
TEST(CrashHandler_Windows, ExceptionType) {
|
||||
EXPECT_EQ(stacktrace::exceptionIdToText(123), "UNKNOWN EXCEPTION:123");
|
||||
|
@ -6,15 +6,12 @@
|
||||
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
|
||||
* ============================================================================*/
|
||||
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <thread>
|
||||
#include "g3log/g3log.hpp"
|
||||
@ -23,7 +20,6 @@
|
||||
|
||||
using namespace testing_helpers;
|
||||
|
||||
|
||||
namespace { // anonymous
|
||||
const char* name_path_1 = "./(some_fake_DirectoryOrName_1_)";
|
||||
const std::string kReplaceFileName = "(ReplaceLogFile)";
|
||||
@ -53,7 +49,8 @@ namespace { // anonymous
|
||||
std::string setLogName(std::string new_file_to_create, std::string logger_id = "g3log") {
|
||||
auto future_new_log = g_filesink_handler->call(&g3::FileSink::changeLogFile, new_file_to_create, logger_id);
|
||||
auto new_log = future_new_log.get();
|
||||
if (!new_log.empty()) g_cleaner_ptr->addLogToClean(new_log);
|
||||
if (!new_log.empty())
|
||||
g_cleaner_ptr->addLogToClean(new_log);
|
||||
return new_log;
|
||||
}
|
||||
|
||||
@ -61,7 +58,7 @@ namespace { // anonymous
|
||||
return g_filesink_handler->call(&g3::FileSink::fileName).get();
|
||||
}
|
||||
|
||||
} // anonymous
|
||||
} // namespace
|
||||
|
||||
TEST(TestOf_GetFileName, Expecting_ValidLogFile) {
|
||||
|
||||
@ -101,7 +98,8 @@ TEST(TestOf_ChangingLogFile_NoId, Expecting_NewLogFileUsed2) {
|
||||
|
||||
TEST(TestOf_ManyThreadsChangingLogFileName, Expecting_EqualNumberLogsCreated) {
|
||||
auto old_log = g_filesink_handler->call(&g3::FileSink::fileName).get();
|
||||
if (!old_log.empty()) g_cleaner_ptr->addLogToClean(old_log);
|
||||
if (!old_log.empty())
|
||||
g_cleaner_ptr->addLogToClean(old_log);
|
||||
|
||||
LOG(INFO) << "SoManyThreadsAllDoingChangeFileName";
|
||||
std::vector<std::thread> threads;
|
||||
@ -130,7 +128,7 @@ TEST(TestOf_IllegalLogFileName, Expecting_NoChangeToOriginalFileName) {
|
||||
TEST(TestOf_SinkHandleDifferentId, Expecting_DifferentId) {
|
||||
auto sink = std::make_unique<g3::FileSink>("AnotherLogFile", name_path_1, "logger_id");
|
||||
auto name = sink->fileName();
|
||||
ASSERT_STREQ( name.substr(0, 26).c_str(), "./AnotherLogFile.logger_id");
|
||||
ASSERT_STREQ(name.substr(0, 26).c_str(), "./AnotherLogFile.logger_id");
|
||||
g_cleaner_ptr->addLogToClean(name);
|
||||
}
|
||||
|
||||
@ -142,7 +140,6 @@ TEST(TestOf_LegalLogFileNam, With_parenthesis) {
|
||||
EXPECT_TRUE(std::string::npos != post_legal.find("(test)")) << "filename was: " << post_legal;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
LogFileCleaner cleaner;
|
||||
g_cleaner_ptr = &cleaner;
|
||||
@ -162,7 +159,6 @@ int main(int argc, char* argv[]) {
|
||||
std::cout << "log file at: " << last_log_file << std::endl;
|
||||
cleaner.addLogToClean(last_log_file);
|
||||
|
||||
|
||||
g3::initializeLogging(g_logger_ptr);
|
||||
LOG(INFO) << "test_filechange demo*" << std::endl;
|
||||
|
||||
|
@ -8,19 +8,19 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "g3log/g3log.hpp"
|
||||
#include "g3log/generated_definitions.hpp"
|
||||
#include "g3log/loglevels.hpp"
|
||||
#include "g3log/logworker.hpp"
|
||||
#include "testing_helpers.h"
|
||||
#include "g3log/loglevels.hpp"
|
||||
#include "g3log/generated_definitions.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <exception>
|
||||
#include <iomanip>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
|
||||
namespace {
|
||||
const std::string log_directory = "./";
|
||||
@ -38,10 +38,8 @@ namespace {
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
using namespace testing_helpers;
|
||||
|
||||
|
||||
/// THIS MUST BE THE FIRST UNIT TEST TO RUN! If any unit test run before this
|
||||
/// one then it could fail. For dynamic levels all levels are turned on only AT
|
||||
/// instantiation so we do different test for dynamic logging levels
|
||||
@ -140,7 +138,6 @@ TEST(Basics, Levels_StdFind) {
|
||||
EXPECT_FALSE(wasNotFoundIterator != levels.end());
|
||||
}
|
||||
|
||||
|
||||
TEST(Basics, Levels_Operator) {
|
||||
auto info = INFO;
|
||||
auto warning = WARNING;
|
||||
@ -195,7 +192,8 @@ TEST(Basics, ShutdownActiveLogger) {
|
||||
file_content = logger.resetAndRetrieveContent();
|
||||
SCOPED_TRACE("LOG_INFO"); // Scope exit be prepared for destructor failure
|
||||
}
|
||||
EXPECT_TRUE(verifyContent(file_content, "Not yet shutdown. This message should make it")) << "\n\n\n***************************\n" << file_content;
|
||||
EXPECT_TRUE(verifyContent(file_content, "Not yet shutdown. This message should make it")) << "\n\n\n***************************\n"
|
||||
<< file_content;
|
||||
EXPECT_FALSE(verifyContent(file_content, "Logger is shutdown,. this message will not make it (but it's safe to try)"));
|
||||
}
|
||||
|
||||
@ -214,7 +212,6 @@ TEST(Basics, DoNotShutdownActiveLogger) {
|
||||
EXPECT_TRUE(verifyContent(file_content, "Logger is (NOT) shutdown,. this message WILL make it")) << file_content;
|
||||
}
|
||||
|
||||
|
||||
TEST(LOGTest, LOG) {
|
||||
std::string file_content;
|
||||
{
|
||||
@ -231,11 +228,8 @@ TEST(LOGTest, LOG) {
|
||||
EXPECT_TRUE(g3::logLevel(FATAL));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// printf-type log
|
||||
|
||||
|
||||
TEST(LogTest, LOG_F) {
|
||||
std::string file_content;
|
||||
{
|
||||
@ -254,9 +248,6 @@ TEST(LogTest, LOG_F) {
|
||||
ASSERT_TRUE(verifyContent(file_content, t_warning3));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// stream-type log
|
||||
TEST(LogTest, LOG) {
|
||||
std::string file_content;
|
||||
@ -278,7 +269,7 @@ TEST(LogTest, LOG_after_if) {
|
||||
std::string file_content;
|
||||
{
|
||||
RestoreFileLogger logger(log_directory);
|
||||
if(false == file_content.empty())
|
||||
if (false == file_content.empty())
|
||||
LOG(INFO) << "This-should-NOT-show-up";
|
||||
else
|
||||
LOG(INFO) << "This-should-show-up";
|
||||
@ -291,12 +282,11 @@ TEST(LogTest, LOG_after_if) {
|
||||
ASSERT_TRUE(verifyContent(file_content, "This-should-show-up"));
|
||||
}
|
||||
|
||||
|
||||
TEST(LogTest, LOG_after_if_with_parentesis) {
|
||||
std::string file_content;
|
||||
{
|
||||
RestoreFileLogger logger(log_directory);
|
||||
if(false == file_content.empty()) {
|
||||
if (false == file_content.empty()) {
|
||||
LOG(INFO) << "This-should-NOT-show-up";
|
||||
} else {
|
||||
LOG(INFO) << "This-should-show-up";
|
||||
@ -310,8 +300,6 @@ TEST(LogTest, LOG_after_if_with_parentesis) {
|
||||
ASSERT_TRUE(verifyContent(file_content, "This-should-show-up"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST(LogTest, LOG_F_IF) {
|
||||
std::string file_content;
|
||||
{
|
||||
@ -326,7 +314,6 @@ TEST(LogTest, LOG_F_IF) {
|
||||
ASSERT_FALSE(verifyContent(file_content, t_debug3));
|
||||
}
|
||||
|
||||
|
||||
TEST(LogTest, LOG_IF) {
|
||||
std::string file_content;
|
||||
{
|
||||
@ -382,7 +369,6 @@ namespace {
|
||||
sigaction(SIGTERM, &action, nullptr);
|
||||
}
|
||||
|
||||
|
||||
std::atomic<bool> oldSigTermCheck = {false};
|
||||
void customOldSignalHandler(int signal_number, siginfo_t* info, void* unused_context) {
|
||||
lastEncounteredSignal.store(signal_number);
|
||||
@ -397,7 +383,7 @@ namespace {
|
||||
sigaction(SIGTERM, &action, nullptr);
|
||||
}
|
||||
|
||||
} // anonymous
|
||||
} // namespace
|
||||
|
||||
// Override of signal handling and testing of it should be fairly easy to port to windows
|
||||
// ref: https://github.com/KjellKod/g3log/blob/master/src/crashhandler_windows.cpp
|
||||
@ -422,13 +408,12 @@ namespace {
|
||||
// ASSERT_TRUE(SIG_ERR != signal(SIGTERM, customSignalHandler));
|
||||
//}
|
||||
|
||||
|
||||
TEST(LogTest, FatalSIGTERM__UsingCustomHandler) {
|
||||
RestoreFileLogger logger(log_directory);
|
||||
g_fatal_counter.store(0);
|
||||
g3::setFatalPreLoggingHook(fatalCounter);
|
||||
installCustomSIGTERM();
|
||||
g3::overrideSetupSignals({ {SIGABRT, "SIGABRT"}, {SIGFPE, "SIGFPE"}, {SIGILL, "SIGILL"}});
|
||||
g3::overrideSetupSignals({{SIGABRT, "SIGABRT"}, {SIGFPE, "SIGFPE"}, {SIGILL, "SIGILL"}});
|
||||
|
||||
installCustomSIGTERM();
|
||||
EXPECT_EQ(customFatalCounter.load(), size_t{0});
|
||||
@ -449,7 +434,7 @@ TEST(LogTest, FatalSIGTERM__VerifyingOldCustomHandler) {
|
||||
|
||||
g3::setFatalPreLoggingHook(fatalCounter);
|
||||
installCustomOldSIGTERM();
|
||||
g3::overrideSetupSignals({ {SIGABRT, "SIGABRT"}, {SIGFPE, "SIGFPE"}, {SIGILL, "SIGILL"}, {SIGTERM, "SIGTERM"}});
|
||||
g3::overrideSetupSignals({{SIGABRT, "SIGABRT"}, {SIGFPE, "SIGFPE"}, {SIGILL, "SIGILL"}, {SIGTERM, "SIGTERM"}});
|
||||
g3::restoreSignalHandler(SIGTERM); // revert SIGTERM installation
|
||||
|
||||
EXPECT_EQ(customFatalCounter.load(), size_t{0});
|
||||
@ -462,10 +447,6 @@ TEST(LogTest, FatalSIGTERM__VerifyingOldCustomHandler) {
|
||||
EXPECT_TRUE(oldSigTermCheck.load());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@ -490,14 +471,10 @@ TEST(LogTest, LOG_preFatalLogging_hook) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST(LogTest, LOG_FATAL) {
|
||||
RestoreFileLogger logger(log_directory);
|
||||
ASSERT_FALSE(mockFatalWasCalled());
|
||||
|
||||
|
||||
|
||||
LOG(FATAL) << "This message is fatal";
|
||||
EXPECT_TRUE(mockFatalWasCalled());
|
||||
EXPECT_TRUE(verifyContent(mockFatalMessage(), "EXIT trigger caused by "));
|
||||
@ -516,7 +493,8 @@ TEST(LogTest, LOGF_IF__FATAL) {
|
||||
EXPECT_FALSE(mockFatalWasCalled());
|
||||
LOGF_IF(FATAL, (2 < 3), "This message %s be worse", "could");
|
||||
EXPECT_TRUE(mockFatalWasCalled());
|
||||
EXPECT_TRUE(verifyContent(mockFatalMessage(), "EXIT trigger caused by ")) << "\n" << mockFatalMessage();
|
||||
EXPECT_TRUE(verifyContent(mockFatalMessage(), "EXIT trigger caused by ")) << "\n"
|
||||
<< mockFatalMessage();
|
||||
EXPECT_TRUE(verifyContent(mockFatalMessage(), "FATAL"));
|
||||
EXPECT_TRUE(verifyContent(mockFatalMessage(), "This message could be worse"));
|
||||
|
||||
@ -549,7 +527,6 @@ TEST(LogTest, LOG_IF__FATAL__NO_THROW) {
|
||||
ASSERT_FALSE(mockFatalWasCalled());
|
||||
}
|
||||
|
||||
|
||||
// CHECK_F
|
||||
TEST(CheckTest, CHECK_F__thisWILL_PrintErrorMsg) {
|
||||
RestoreFileLogger logger(log_directory);
|
||||
@ -566,7 +543,6 @@ TEST(CheckTest, CHECK_F__thisWILL_PrintErrorMsg) {
|
||||
EXPECT_TRUE(verifyContent(file_content, "CONTRACT")) << "**** " << mockFatalMessage();
|
||||
}
|
||||
|
||||
|
||||
TEST(CHECK_F_Test, CHECK_F__thisWILL_PrintErrorMsg) {
|
||||
RestoreFileLogger logger(log_directory);
|
||||
std::string msg = "This message is added to throw %s and %s";
|
||||
@ -580,7 +556,6 @@ TEST(CHECK_F_Test, CHECK_F__thisWILL_PrintErrorMsg) {
|
||||
EXPECT_TRUE(verifyContent(file_content, "CONTRACT"));
|
||||
}
|
||||
|
||||
|
||||
TEST(CHECK_Test, CHECK__thisWILL_PrintErrorMsg) {
|
||||
RestoreFileLogger logger(log_directory);
|
||||
std::string msg = "This message is added to throw message and log";
|
||||
@ -616,11 +591,11 @@ TEST(CHECK, CHECK_runtimeError) {
|
||||
class dynamic_int_array {
|
||||
std::unique_ptr<int[]> data_;
|
||||
const int size_;
|
||||
|
||||
public:
|
||||
explicit dynamic_int_array(int size)
|
||||
: data_{std::make_unique<int[]>(size)}
|
||||
, size_(size)
|
||||
{}
|
||||
explicit dynamic_int_array(int size) :
|
||||
data_{std::make_unique<int[]>(size)},
|
||||
size_(size) {}
|
||||
|
||||
int& at(int i) {
|
||||
CHECK(i < size_);
|
||||
@ -637,22 +612,25 @@ TEST(CHECK, CHECK_runtimeError) {
|
||||
|
||||
TEST(CustomLogLevels, AddANonFatal) {
|
||||
RestoreFileLogger logger(log_directory);
|
||||
const LEVELS MYINFO {WARNING.value + 1, {"MY_INFO_LEVEL"}};
|
||||
const LEVELS MYINFO{WARNING.value + 1, {"MY_INFO_LEVEL"}};
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
g3::only_change_at_initialization::addLogLevel(MYINFO, true);
|
||||
#endif
|
||||
// clang-format off
|
||||
LOG(MYINFO) << "Testing my own custom level"; auto line = __LINE__;
|
||||
// clang-format on
|
||||
logger.reset();
|
||||
std::string file_content = readFileToText(logger.logFile());
|
||||
std::string expected;
|
||||
expected += "MY_INFO_LEVEL [test_io.cpp->" + std::string(G3LOG_PRETTY_FUNCTION) + ":" + std::to_string(line);
|
||||
EXPECT_TRUE(verifyContent(file_content, expected)) << file_content
|
||||
<< "\n\nExpected: \n" << expected;
|
||||
<< "\n\nExpected: \n"
|
||||
<< expected;
|
||||
}
|
||||
|
||||
TEST(CustomLogLevels, AddFatal) {
|
||||
RestoreFileLogger logger(log_directory);
|
||||
const LEVELS DEADLY {FATAL.value + 1, {"DEADLY"}};
|
||||
const LEVELS DEADLY{FATAL.value + 1, {"DEADLY"}};
|
||||
EXPECT_TRUE(g3::internal::wasFatal(DEADLY));
|
||||
g_fatal_counter.store(0);
|
||||
ASSERT_FALSE(mockFatalWasCalled());
|
||||
@ -660,8 +638,9 @@ TEST(CustomLogLevels, AddFatal) {
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
g3::only_change_at_initialization::addLogLevel(DEADLY, true);
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
LOG(DEADLY) << "Testing my own custom level"; auto line = __LINE__;
|
||||
// clang-format on
|
||||
logger.reset();
|
||||
ASSERT_TRUE(mockFatalWasCalled());
|
||||
EXPECT_EQ(size_t{1}, g_fatal_counter.load());
|
||||
@ -670,18 +649,17 @@ TEST(CustomLogLevels, AddFatal) {
|
||||
std::string expected;
|
||||
expected += "DEADLY [test_io.cpp->" + std::string(G3LOG_PRETTY_FUNCTION) + ":" + std::to_string(line);
|
||||
EXPECT_TRUE(verifyContent(file_content, expected)) << file_content
|
||||
<< "\n\nExpected: \n" << expected;
|
||||
<< "\n\nExpected: \n"
|
||||
<< expected;
|
||||
g_fatal_counter.store(0); // restore
|
||||
}
|
||||
|
||||
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
namespace {
|
||||
// Restore dynamic levels if turned off
|
||||
|
||||
struct RestoreDynamicLoggingLevels {
|
||||
RestoreDynamicLoggingLevels() {
|
||||
};
|
||||
RestoreDynamicLoggingLevels(){};
|
||||
~RestoreDynamicLoggingLevels() {
|
||||
g3::only_change_at_initialization::reset();
|
||||
g3::only_change_at_initialization::addLogLevel(G3LOG_DEBUG, false);
|
||||
@ -690,12 +668,11 @@ namespace {
|
||||
g3::only_change_at_initialization::addLogLevel(FATAL, false);
|
||||
}
|
||||
};
|
||||
} // anonymous
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(CustomLogLevels, AddANonFatal__ThenReset) {
|
||||
RestoreFileLogger logger(log_directory);
|
||||
const LEVELS MYINFO {WARNING.value + 2, {"MY_INFO_LEVEL"}};
|
||||
const LEVELS MYINFO{WARNING.value + 2, {"MY_INFO_LEVEL"}};
|
||||
EXPECT_FALSE(g3::logLevel(MYINFO));
|
||||
g3::only_change_at_initialization::addLogLevel(MYINFO, true);
|
||||
EXPECT_TRUE(g3::logLevel(MYINFO));
|
||||
@ -703,48 +680,57 @@ TEST(CustomLogLevels, AddANonFatal__ThenReset) {
|
||||
EXPECT_FALSE(g3::logLevel(MYINFO));
|
||||
}
|
||||
|
||||
|
||||
TEST(CustomLogLevels, AddANonFatal__DidNotAddItToEnabledValue1) {
|
||||
RestoreFileLogger logger(log_directory);
|
||||
const LEVELS MYINFO {WARNING.value + 2, {"MY_INFO_LEVEL"}};
|
||||
const LEVELS MYINFO{WARNING.value + 2, {"MY_INFO_LEVEL"}};
|
||||
// clang-format off
|
||||
LOG(MYINFO) << "Testing my own custom level"; auto line = __LINE__;
|
||||
// clang-format on
|
||||
logger.reset();
|
||||
|
||||
std::string file_content = readFileToText(logger.logFile());
|
||||
std::string expected;
|
||||
expected += "MY_INFO_LEVEL [test_io.cpp:" + std::to_string(line);
|
||||
EXPECT_FALSE(verifyContent(file_content, expected)) << file_content
|
||||
<< "\n\nExpected: \n" << expected << "\nLevels:\n" << g3::log_levels::to_string();
|
||||
<< "\n\nExpected: \n"
|
||||
<< expected << "\nLevels:\n"
|
||||
<< g3::log_levels::to_string();
|
||||
}
|
||||
|
||||
TEST(CustomLogLevels, AddANonFatal__DidNotAddItToEnabledValue2) {
|
||||
RestoreFileLogger logger(log_directory);
|
||||
const LEVELS MYINFO {WARNING.value + 2, {"MY_INFO_LEVEL"}};
|
||||
const LEVELS MYINFO{WARNING.value + 2, {"MY_INFO_LEVEL"}};
|
||||
EXPECT_FALSE(g3::logLevel(MYINFO));
|
||||
// clang-format off
|
||||
LOG(MYINFO) << "Testing my own custom level"; auto line = __LINE__;
|
||||
// clang-format on
|
||||
logger.reset();
|
||||
|
||||
std::string file_content = readFileToText(logger.logFile());
|
||||
std::string expected;
|
||||
expected += "MY_INFO_LEVEL [test_io.cpp:" + std::to_string(line);
|
||||
EXPECT_FALSE(verifyContent(file_content, expected)) << file_content
|
||||
<< "\n\nExpected: \n" << expected << "\nLevels:\n" << g3::log_levels::to_string();
|
||||
<< "\n\nExpected: \n"
|
||||
<< expected << "\nLevels:\n"
|
||||
<< g3::log_levels::to_string();
|
||||
}
|
||||
|
||||
TEST(CustomLogLevels, AddANonFatal__DidtAddItToEnabledValue) {
|
||||
RestoreFileLogger logger(log_directory);
|
||||
const LEVELS MYINFO {WARNING.value + 3, {"MY_INFO_LEVEL"}};
|
||||
const LEVELS MYINFO{WARNING.value + 3, {"MY_INFO_LEVEL"}};
|
||||
g3::only_change_at_initialization::addLogLevel(MYINFO, true);
|
||||
// clang-format off
|
||||
LOG(MYINFO) << "Testing my own custom level"; auto line = __LINE__;
|
||||
// clang-format on
|
||||
logger.reset();
|
||||
std::string file_content = readFileToText(logger.logFile());
|
||||
std::string expected;
|
||||
expected += "MY_INFO_LEVEL [test_io.cpp->" + std::string(G3LOG_PRETTY_FUNCTION) + ":" + std::to_string(line);
|
||||
EXPECT_TRUE(verifyContent(file_content, expected)) << file_content
|
||||
<< "\n\nExpected: \n" << expected;
|
||||
<< "\n\nExpected: \n"
|
||||
<< expected;
|
||||
}
|
||||
|
||||
|
||||
TEST(DynamicLogging, DynamicLogging_IS_ENABLED) {
|
||||
RestoreDynamicLoggingLevels raiiLevelRestore;
|
||||
|
||||
@ -828,7 +814,6 @@ TEST(DynamicLogging, DynamicLogging_No_Fatal_If_Disabled) {
|
||||
clearMockFatal();
|
||||
EXPECT_FALSE(mockFatalWasCalled());
|
||||
|
||||
|
||||
g3::only_change_at_initialization::addLogLevel(FATAL, false);
|
||||
std::string msg3 = "This is NOT fatal (not crash, since it is unit test. FATAL is disabled";
|
||||
LOG(FATAL) << msg3;
|
||||
@ -836,7 +821,6 @@ TEST(DynamicLogging, DynamicLogging_No_Fatal_If_Disabled) {
|
||||
EXPECT_TRUE(mockFatalMessage().empty());
|
||||
}
|
||||
|
||||
|
||||
TEST(DynamicLogging, DynamicLogging_Check_WillAlsoBeTurnedOffWhen_Fatal_Is_Disabled) {
|
||||
RestoreFileLogger logger(log_directory);
|
||||
RestoreDynamicLoggingLevels raiiLevelRestore;
|
||||
@ -858,9 +842,6 @@ TEST(DynamicLogging, DynamicLogging_Check_WillAlsoBeTurnedOffWhen_Fatal_Is_Disab
|
||||
EXPECT_FALSE(mockFatalWasCalled());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#else
|
||||
TEST(DynamicLogging, DynamicLogging_IS_NOT_ENABLED) {
|
||||
ASSERT_TRUE(g3::logLevel(G3LOG_DEBUG));
|
||||
@ -868,6 +849,3 @@ TEST(DynamicLogging, DynamicLogging_IS_NOT_ENABLED) {
|
||||
//ASSERT_FALSE(g3::logLevel(G3LOG_DEBUG));
|
||||
}
|
||||
#endif // Dynamic logging
|
||||
|
||||
|
||||
|
||||
|
@ -6,22 +6,22 @@
|
||||
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
|
||||
* ============================================================================*/
|
||||
|
||||
|
||||
#include <g3log/filesink.hpp>
|
||||
#include <g3log/g3log.hpp>
|
||||
#include <g3log/logworker.hpp>
|
||||
#include <g3log/filesink.hpp>
|
||||
#include <memory>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "tester_sharedlib.h"
|
||||
#include <dlfcn.h>
|
||||
#include "tester_sharedlib.h"
|
||||
|
||||
struct LogMessageCounter {
|
||||
std::vector<std::string>& bank;
|
||||
LogMessageCounter(std::vector<std::string>& storeMessages) : bank(storeMessages) {
|
||||
LogMessageCounter(std::vector<std::string>& storeMessages) :
|
||||
bank(storeMessages) {
|
||||
}
|
||||
|
||||
void countMessages(std::string msg) {
|
||||
@ -42,7 +42,7 @@ TEST(DynamicLoadOfLibrary, JustLoadAndExit) {
|
||||
|
||||
void* libHandle = dlopen("libtester_sharedlib.so", RTLD_LAZY | RTLD_GLOBAL);
|
||||
EXPECT_FALSE(nullptr == libHandle);
|
||||
LibraryFactory* factory = reinterpret_cast<LibraryFactory*> ((dlsym(libHandle, "testRealFactory")));
|
||||
LibraryFactory* factory = reinterpret_cast<LibraryFactory*>((dlsym(libHandle, "testRealFactory")));
|
||||
EXPECT_FALSE(nullptr == factory);
|
||||
SomeLibrary* loadedLibrary = factory->CreateLibrary();
|
||||
|
||||
|
@ -7,14 +7,14 @@
|
||||
* ============================================================================*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <testing_helpers.h>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <g3log/filesink.hpp>
|
||||
#include <g3log/g3log.hpp>
|
||||
#include <g3log/generated_definitions.hpp>
|
||||
#include <g3log/time.hpp>
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
#include <cstdlib>
|
||||
#include <g3log/generated_definitions.hpp>
|
||||
#include <testing_helpers.h>
|
||||
#include <g3log/filesink.hpp>
|
||||
namespace {
|
||||
// https://www.epochconverter.com/
|
||||
// epoc value for: Thu, 27 Apr 2017 06:22:49 GMT
|
||||
@ -27,9 +27,7 @@ namespace {
|
||||
const LEVELS kLevel = INFO;
|
||||
const std::string testdirectory = "./";
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(Message, DefaultLogDetals_toString) {
|
||||
using namespace g3;
|
||||
@ -47,7 +45,6 @@ TEST(Message, Default_toString) {
|
||||
testing_helpers::verifyContent(output, details);
|
||||
}
|
||||
|
||||
|
||||
TEST(Message, UseOverride_4_DetailsWithThreadID_toString) {
|
||||
using namespace g3;
|
||||
LogMessage msg{kFile, kLine, kFunction, kLevel};
|
||||
@ -79,8 +76,6 @@ TEST(Message, UseLogCall_4_DetailsWithThreadID_toString) {
|
||||
std::cout << output << std::endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST(Message, DefaultFormattingToLogFile) {
|
||||
using namespace g3;
|
||||
std::string file_content;
|
||||
@ -96,8 +91,6 @@ TEST(Message, DefaultFormattingToLogFile) {
|
||||
EXPECT_FALSE(testing_helpers::verifyContent(file_content, thread_id_oss.str()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST(Message, FullFormattingToLogFile) {
|
||||
using namespace g3;
|
||||
std::string file_content;
|
||||
@ -115,8 +108,6 @@ TEST(Message, FullFormattingToLogFile) {
|
||||
EXPECT_TRUE(testing_helpers::verifyContent(file_content, thread_id_oss.str()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST(Message, CppSupport) {
|
||||
// ref: http://www.cplusplus.com/reference/clibrary/ctime/strftime/
|
||||
// ref: http://en.cppreference.com/w/cpp/io/manip/put_time
|
||||
@ -132,11 +123,12 @@ TEST(Message, CppSupport) {
|
||||
std::cerr << "Formatting options skipped due to VS2012, C++11 non-conformance for" << std::endl;
|
||||
std::cerr << " some formatting options. The skipped code was:\n\t\t %EX %Ec, \n(see http://en.cppreference.com/w/cpp/io/manip/put_time for details)" << std::endl;
|
||||
#else
|
||||
std::cout << "C++11 new formatting options:\n" << g3::localtime_formatted(std::chrono::system_clock::now(), "%%EX: %EX\n%%z: %z\n%%Ec: %Ec") << std::endl;
|
||||
std::cout << "C++11 new formatting options:\n"
|
||||
<< g3::localtime_formatted(std::chrono::system_clock::now(), "%%EX: %EX\n%%z: %z\n%%Ec: %Ec") << std::endl;
|
||||
#endif
|
||||
}
|
||||
// This does not work. Other kinds of fatal exits (on Windows) seems to be used instead of exceptions
|
||||
// Maybe a signal handler catch would be better? --- TODO: Make it better, both failing and correct
|
||||
// This does not work. Other kinds of fatal exits (on Windows) seems to be used instead of exceptions
|
||||
// Maybe a signal handler catch would be better? --- TODO: Make it better, both failing and correct
|
||||
catch (...) {
|
||||
ADD_FAILURE() << "On this platform the library does not support given (C++11?) specifiers";
|
||||
return;
|
||||
@ -144,8 +136,6 @@ TEST(Message, CppSupport) {
|
||||
ASSERT_TRUE(true); // no exception. all good
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST(Message, GetFractional_Empty_buffer_ExpectDefaults) {
|
||||
auto fractional = g3::internal::getFractional("", 0);
|
||||
const auto expected = g3::internal::Fractional::NanosecondDefault;
|
||||
@ -200,8 +190,6 @@ TEST(Message, GetFractional_All) {
|
||||
EXPECT_EQ(fractional, expected);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST(Message, FractionalToString_SizeCheck) {
|
||||
auto value = g3::internal::to_string(kTimePoint_2017_April_27th, g3::internal::Fractional::Nanosecond);
|
||||
EXPECT_EQ("000000000", value);
|
||||
@ -211,7 +199,7 @@ TEST(Message, FractionalToString_SizeCheck) {
|
||||
// us
|
||||
value = g3::internal::to_string(kTimePoint_2017_April_27th, g3::internal::Fractional::Microsecond);
|
||||
EXPECT_EQ("000000", value);
|
||||
// ms
|
||||
// ms
|
||||
value = g3::internal::to_string(kTimePoint_2017_April_27th, g3::internal::Fractional::Millisecond);
|
||||
EXPECT_EQ("000", value);
|
||||
}
|
||||
@ -233,16 +221,13 @@ TEST(Message, FractionalToString12NanoPadded) {
|
||||
EXPECT_EQ("000000000", value);
|
||||
}
|
||||
|
||||
|
||||
TEST(Message, FractionalToStringMicroPadded) {
|
||||
auto value = g3::internal::to_string(k1970_January_1st, g3::internal::Fractional::Microsecond);
|
||||
EXPECT_EQ("000000", value);
|
||||
value = g3::internal::to_string(k1970_January_1st, g3::internal::Fractional::Microsecond);
|
||||
EXPECT_EQ("000000", value);
|
||||
|
||||
}
|
||||
|
||||
|
||||
TEST(Message, FractionalToStringMilliPadded) {
|
||||
auto value = g3::internal::to_string(k1970_January_1st, g3::internal::Fractional::Millisecond);
|
||||
EXPECT_EQ("000", value);
|
||||
@ -250,7 +235,6 @@ TEST(Message, FractionalToStringMilliPadded) {
|
||||
EXPECT_EQ("000", value);
|
||||
}
|
||||
|
||||
|
||||
#if !(defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
||||
|
||||
TEST(Message, localtime_formatted) {
|
||||
@ -262,13 +246,11 @@ TEST(Message, localtime_formatted) {
|
||||
else
|
||||
unsetenv("TZ");
|
||||
tzset();
|
||||
|
||||
});
|
||||
tz = getenv("TZ");
|
||||
setenv("TZ", "", 1);
|
||||
tzset();
|
||||
|
||||
|
||||
auto time_point = std::chrono::system_clock::from_time_t(k2017_April_27th);
|
||||
auto format = g3::localtime_formatted(time_point, "%Y-%m-%d %H:%M:%S"); // %Y/%m/%d
|
||||
std::string expected = {"2017-04-27 06:22:27"};
|
||||
@ -282,7 +264,6 @@ TEST(Message, localtime_formatted) {
|
||||
|
||||
auto ms_format = g3::localtime_formatted(time_point, "%H:%M:%S %f3");
|
||||
EXPECT_EQ("06:22:27 000", ms_format);
|
||||
|
||||
}
|
||||
#endif // timezone
|
||||
|
||||
@ -298,7 +279,6 @@ TEST(Level, G3LogDebug_is_DEBUG) {
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
namespace {
|
||||
using LevelsContainer = std::map<int, g3::LoggingLevel>;
|
||||
@ -306,27 +286,23 @@ namespace {
|
||||
{G3LOG_DEBUG.value, {G3LOG_DEBUG}},
|
||||
{INFO.value, {INFO}},
|
||||
{WARNING.value, {WARNING}},
|
||||
{FATAL.value, {FATAL}}
|
||||
};
|
||||
{FATAL.value, {FATAL}}};
|
||||
|
||||
const LevelsContainer g_test_all_disabled = {
|
||||
{G3LOG_DEBUG.value, {G3LOG_DEBUG,false}},
|
||||
{G3LOG_DEBUG.value, {G3LOG_DEBUG, false}},
|
||||
{INFO.value, {INFO, false}},
|
||||
{WARNING.value, {WARNING, false}},
|
||||
{FATAL.value, {FATAL, false}}
|
||||
};
|
||||
{FATAL.value, {FATAL, false}}};
|
||||
|
||||
|
||||
bool mapCompare (LevelsContainer const& lhs, LevelsContainer const& rhs) {
|
||||
auto pred = [] (auto a, auto b) {
|
||||
bool mapCompare(LevelsContainer const& lhs, LevelsContainer const& rhs) {
|
||||
auto pred = [](auto a, auto b) {
|
||||
return (a.first == b.first) &&
|
||||
(a.second == b.second);
|
||||
};
|
||||
|
||||
return lhs.size() == rhs.size()
|
||||
&& std::equal(lhs.begin(), lhs.end(), rhs.begin(), pred);
|
||||
return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin(), pred);
|
||||
}
|
||||
} // anonymous
|
||||
} // namespace
|
||||
TEST(Level, Default) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
auto defaults = g3::log_levels::getAll();
|
||||
@ -349,8 +325,7 @@ TEST(Level, DefaultChanged_only_change_at_initialization) {
|
||||
{G3LOG_DEBUG.value, {G3LOG_DEBUG, true}},
|
||||
{INFO.value, {INFO, false}},
|
||||
{WARNING.value, {WARNING, true}},
|
||||
{FATAL.value, {FATAL, true}}
|
||||
};
|
||||
{FATAL.value, {FATAL, true}}};
|
||||
EXPECT_TRUE(mapCompare(defaults, defaultsWithInfoChangged));
|
||||
}
|
||||
|
||||
@ -369,8 +344,7 @@ TEST(Level, DefaultChanged_log_levels) {
|
||||
{G3LOG_DEBUG.value, {G3LOG_DEBUG, true}},
|
||||
{INFO.value, {INFO, false}},
|
||||
{WARNING.value, {WARNING, true}},
|
||||
{FATAL.value, {FATAL, true}}
|
||||
};
|
||||
{FATAL.value, {FATAL, true}}};
|
||||
EXPECT_TRUE(mapCompare(defaults, defaultsWithInfoChangged));
|
||||
}
|
||||
|
||||
@ -386,20 +360,14 @@ TEST(Level, Reset) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
all_levels = g3::log_levels::getAll();
|
||||
EXPECT_TRUE(mapCompare(all_levels, g_test_log_level_defaults));
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST(Level, AllDisabled) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
std::shared_ptr<void> RaiiLeveReset(nullptr, [&](void*) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
});
|
||||
|
||||
|
||||
auto all_levels = g3::log_levels::getAll();
|
||||
EXPECT_EQ(all_levels.size(), g_test_all_disabled.size());
|
||||
EXPECT_FALSE(mapCompare(all_levels, g_test_all_disabled));
|
||||
@ -409,79 +377,64 @@ TEST(Level, AllDisabled) {
|
||||
EXPECT_TRUE(mapCompare(all_levels, g_test_all_disabled));
|
||||
}
|
||||
|
||||
|
||||
TEST(Level, setHighestLogLevel_high_end) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
std::shared_ptr<void> RaiiLeveReset(nullptr, [&](void*) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
});
|
||||
|
||||
|
||||
g3::log_levels::enableAll();
|
||||
g3::log_levels::disable(FATAL);
|
||||
g3::log_levels::setHighest(FATAL);
|
||||
|
||||
|
||||
LevelsContainer expected = {
|
||||
{G3LOG_DEBUG.value, {G3LOG_DEBUG, false}},
|
||||
{INFO.value, {INFO, false}},
|
||||
{WARNING.value, {WARNING, false}},
|
||||
{FATAL.value, {FATAL, true}}
|
||||
};
|
||||
{FATAL.value, {FATAL, true}}};
|
||||
|
||||
auto all_levels = g3::log_levels::getAll();
|
||||
EXPECT_TRUE(mapCompare(all_levels, expected)) << g3::log_levels::to_string();
|
||||
}
|
||||
|
||||
|
||||
TEST(Level, setHighestLogLevel_low_end) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
std::shared_ptr<void> RaiiLeveReset(nullptr, [&](void*) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
});
|
||||
|
||||
|
||||
g3::log_levels::disableAll();
|
||||
g3::log_levels::setHighest(G3LOG_DEBUG);
|
||||
|
||||
|
||||
LevelsContainer expected = {
|
||||
{G3LOG_DEBUG.value,{G3LOG_DEBUG, true}},
|
||||
{G3LOG_DEBUG.value, {G3LOG_DEBUG, true}},
|
||||
{INFO.value, {INFO, true}},
|
||||
{WARNING.value, {WARNING, true}},
|
||||
{FATAL.value, {FATAL, true}}
|
||||
};
|
||||
{FATAL.value, {FATAL, true}}};
|
||||
|
||||
auto all_levels = g3::log_levels::getAll();
|
||||
EXPECT_TRUE(mapCompare(all_levels, expected)) << g3::log_levels::to_string();
|
||||
}
|
||||
|
||||
|
||||
TEST(Level, setHighestLogLevel_middle) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
std::shared_ptr<void> RaiiLeveReset(nullptr, [&](void*) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
});
|
||||
|
||||
|
||||
g3::log_levels::enableAll();
|
||||
g3::log_levels::setHighest(WARNING);
|
||||
|
||||
|
||||
LevelsContainer expected = {
|
||||
{G3LOG_DEBUG.value, {G3LOG_DEBUG, false}},
|
||||
{INFO.value, {INFO, false}},
|
||||
{WARNING.value, {WARNING, true}},
|
||||
{FATAL.value, {FATAL, true}}
|
||||
};
|
||||
{FATAL.value, {FATAL, true}}};
|
||||
|
||||
auto all_levels = g3::log_levels::getAll();
|
||||
EXPECT_TRUE(mapCompare(all_levels, expected));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
TEST(Level, setHighestLogLevel_StepWiseDisableAll) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
std::shared_ptr<void> RaiiLeveReset(nullptr, [&](void*) {
|
||||
@ -492,8 +445,7 @@ TEST(Level, setHighestLogLevel_StepWiseDisableAll) {
|
||||
{G3LOG_DEBUG.value, {G3LOG_DEBUG, true}},
|
||||
{INFO.value, {INFO, true}},
|
||||
{WARNING.value, {WARNING, true}},
|
||||
{FATAL.value, {FATAL, true}}
|
||||
};
|
||||
{FATAL.value, {FATAL, true}}};
|
||||
|
||||
auto all_levels = g3::log_levels::getAll();
|
||||
EXPECT_TRUE(mapCompare(all_levels, g_test_log_level_defaults));
|
||||
@ -503,11 +455,9 @@ TEST(Level, setHighestLogLevel_StepWiseDisableAll) {
|
||||
g3::log_levels::setHighest(lvl.second.level);
|
||||
all_levels = g3::log_levels::getAll();
|
||||
|
||||
ASSERT_TRUE(mapCompare(all_levels, changing_levels)) <<
|
||||
"counter: " << counter << "\nsystem:\n" <<
|
||||
g3::log_levels::to_string(all_levels) <<
|
||||
"\nexpected:\n" <<
|
||||
g3::log_levels::to_string(changing_levels);
|
||||
ASSERT_TRUE(mapCompare(all_levels, changing_levels)) << "counter: " << counter << "\nsystem:\n"
|
||||
<< g3::log_levels::to_string(all_levels) << "\nexpected:\n"
|
||||
<< g3::log_levels::to_string(changing_levels);
|
||||
|
||||
++counter;
|
||||
if (counter != changing_levels.size()) {
|
||||
@ -516,26 +466,20 @@ TEST(Level, setHighestLogLevel_StepWiseDisableAll) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// in the end all except the last should be disabled
|
||||
auto mostly_disabled = g_test_all_disabled;
|
||||
mostly_disabled[FATAL.value].status = true;
|
||||
EXPECT_TRUE(mapCompare(changing_levels, mostly_disabled));
|
||||
|
||||
all_levels = g3::log_levels::getAll();
|
||||
EXPECT_TRUE(mapCompare(all_levels, mostly_disabled)) <<
|
||||
"\nsystem:\n" <<
|
||||
g3::log_levels::to_string(all_levels) <<
|
||||
"\nexpected:\n" <<
|
||||
g3::log_levels::to_string(mostly_disabled);
|
||||
EXPECT_TRUE(mapCompare(all_levels, mostly_disabled)) << "\nsystem:\n"
|
||||
<< g3::log_levels::to_string(all_levels) << "\nexpected:\n"
|
||||
<< g3::log_levels::to_string(mostly_disabled);
|
||||
}
|
||||
|
||||
TEST(Level, Print) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
std::string expected = std::string{"name: DEBUG level: 100 status: 1\n"}
|
||||
+ "name: INFO level: 300 status: 1\n"
|
||||
+ "name: WARNING level: 500 status: 1\n"
|
||||
+ "name: FATAL level: 1000 status: 1\n";
|
||||
std::string expected = std::string{"name: DEBUG level: 100 status: 1\n"} + "name: INFO level: 300 status: 1\n" + "name: WARNING level: 500 status: 1\n" + "name: FATAL level: 1000 status: 1\n";
|
||||
EXPECT_EQ(g3::log_levels::to_string(), expected);
|
||||
}
|
||||
|
||||
@ -544,19 +488,16 @@ TEST(Level, AddOneEnabled_option1) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
});
|
||||
|
||||
|
||||
LEVELS MYINFO {WARNING.value + 1, "MyInfoLevel"};
|
||||
LEVELS MYINFO{WARNING.value + 1, "MyInfoLevel"};
|
||||
g3::only_change_at_initialization::addLogLevel(MYINFO, true);
|
||||
|
||||
auto modified = g_test_log_level_defaults;
|
||||
modified[MYINFO.value] = MYINFO;
|
||||
|
||||
auto all_levels = g3::log_levels::getAll();
|
||||
EXPECT_TRUE(mapCompare(modified, all_levels)) << "\nsystem:\n" <<
|
||||
g3::log_levels::to_string(all_levels) <<
|
||||
"\nexpected:\n" <<
|
||||
g3::log_levels::to_string(modified);
|
||||
|
||||
EXPECT_TRUE(mapCompare(modified, all_levels)) << "\nsystem:\n"
|
||||
<< g3::log_levels::to_string(all_levels) << "\nexpected:\n"
|
||||
<< g3::log_levels::to_string(modified);
|
||||
}
|
||||
|
||||
TEST(Level, AddOneEnabled_option2) {
|
||||
@ -564,30 +505,24 @@ TEST(Level, AddOneEnabled_option2) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
});
|
||||
|
||||
|
||||
LEVELS MYINFO {WARNING.value + 1, "MyInfoLevel"};
|
||||
LEVELS MYINFO{WARNING.value + 1, "MyInfoLevel"};
|
||||
g3::only_change_at_initialization::addLogLevel(MYINFO);
|
||||
|
||||
auto modified = g_test_log_level_defaults;
|
||||
modified[MYINFO.value] = MYINFO;
|
||||
|
||||
auto all_levels = g3::log_levels::getAll();
|
||||
EXPECT_TRUE(mapCompare(modified, all_levels)) << "\nsystem:\n" <<
|
||||
g3::log_levels::to_string(all_levels) <<
|
||||
"\nexpected:\n" <<
|
||||
g3::log_levels::to_string(modified);
|
||||
|
||||
EXPECT_TRUE(mapCompare(modified, all_levels)) << "\nsystem:\n"
|
||||
<< g3::log_levels::to_string(all_levels) << "\nexpected:\n"
|
||||
<< g3::log_levels::to_string(modified);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
TEST(Level, Addlevel_using_addLevel) {
|
||||
std::shared_ptr<void> RaiiLeveReset(nullptr, [&](void*) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
});
|
||||
|
||||
LEVELS MYINFO {WARNING.value + 1, "MyInfoLevel"};
|
||||
LEVELS MYINFO{WARNING.value + 1, "MyInfoLevel"};
|
||||
auto status = g3::log_levels::getStatus(MYINFO);
|
||||
EXPECT_EQ(status, g3::log_levels::status::Absent);
|
||||
|
||||
@ -601,7 +536,7 @@ TEST(Level, Addlevel_using_addLogLevel_disabled) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
});
|
||||
|
||||
LEVELS MYINFO {WARNING.value + 1, "MyInfoLevel"};
|
||||
LEVELS MYINFO{WARNING.value + 1, "MyInfoLevel"};
|
||||
auto status = g3::log_levels::getStatus(MYINFO);
|
||||
EXPECT_EQ(status, g3::log_levels::status::Absent);
|
||||
|
||||
@ -615,7 +550,7 @@ TEST(Level, Addlevel__disabled) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
});
|
||||
|
||||
LEVELS MYINFO {WARNING.value + 1, "MyInfoLevel"};
|
||||
LEVELS MYINFO{WARNING.value + 1, "MyInfoLevel"};
|
||||
auto status = g3::log_levels::getStatus(MYINFO);
|
||||
EXPECT_EQ(status, g3::log_levels::status::Absent);
|
||||
|
||||
@ -637,15 +572,13 @@ TEST(Level, Addlevel__enabled) {
|
||||
g3::only_change_at_initialization::reset();
|
||||
});
|
||||
|
||||
LEVELS MYINFO {WARNING.value + 1, "MyInfoLevel"};
|
||||
LEVELS MYINFO{WARNING.value + 1, "MyInfoLevel"};
|
||||
auto status = g3::log_levels::getStatus(MYINFO);
|
||||
EXPECT_EQ(status, g3::log_levels::status::Absent);
|
||||
|
||||
|
||||
g3::only_change_at_initialization::addLogLevel(MYINFO);
|
||||
status = g3::log_levels::getStatus(MYINFO);
|
||||
EXPECT_EQ(status, g3::log_levels::status::Enabled);
|
||||
}
|
||||
|
||||
#endif // G3_DYNAMIC_LOGGING
|
||||
|
||||
|
@ -7,26 +7,25 @@
|
||||
* ============================================================================*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <iostream>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <future>
|
||||
#include <g3log/generated_definitions.hpp>
|
||||
#include "testing_helpers.h"
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include "g3log/logmessage.hpp"
|
||||
#include "g3log/logworker.hpp"
|
||||
|
||||
#include "testing_helpers.h"
|
||||
|
||||
using namespace testing_helpers;
|
||||
using namespace std;
|
||||
TEST(Sink, OneSink) {
|
||||
using namespace g3;
|
||||
AtomicBoolPtr flag = make_shared < atomic<bool >> (false);
|
||||
AtomicIntPtr count = make_shared < atomic<int >> (0);
|
||||
AtomicBoolPtr flag = make_shared<atomic<bool>>(false);
|
||||
AtomicIntPtr count = make_shared<atomic<int>>(0);
|
||||
{
|
||||
auto worker = g3::LogWorker::createLogWorker();
|
||||
auto handle = worker->addSink(std::make_unique<ScopedSetTrue>(flag, count), &ScopedSetTrue::ReceiveMsg);
|
||||
@ -40,12 +39,10 @@ TEST(Sink, OneSink) {
|
||||
EXPECT_TRUE(1 == count->load());
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST(Sink, OneSinkRemove) {
|
||||
using namespace g3;
|
||||
AtomicBoolPtr flag = make_shared < atomic<bool >> (false);
|
||||
AtomicIntPtr count = make_shared < atomic<int >> (0);
|
||||
AtomicBoolPtr flag = make_shared<atomic<bool>>(false);
|
||||
AtomicIntPtr count = make_shared<atomic<int>>(0);
|
||||
{
|
||||
auto worker = g3::LogWorker::createLogWorker();
|
||||
auto handle = worker->addSink(std::make_unique<ScopedSetTrue>(flag, count), &ScopedSetTrue::ReceiveMsg);
|
||||
@ -67,10 +64,10 @@ TEST(Sink, OneSinkRemove) {
|
||||
}
|
||||
|
||||
// just compile test
|
||||
TEST(Sink, DefaultSinkRemove){
|
||||
TEST(Sink, DefaultSinkRemove) {
|
||||
using namespace g3;
|
||||
AtomicBoolPtr flag = make_shared < atomic<bool >> (false);
|
||||
AtomicIntPtr count = make_shared < atomic<int >> (0);
|
||||
AtomicBoolPtr flag = make_shared<atomic<bool>>(false);
|
||||
AtomicIntPtr count = make_shared<atomic<int>>(0);
|
||||
{
|
||||
auto worker = g3::LogWorker::createLogWorker();
|
||||
auto handle1 = worker->addDefaultLogger("test1", "./");
|
||||
@ -82,8 +79,8 @@ TEST(Sink, DefaultSinkRemove){
|
||||
|
||||
TEST(Sink, NullSinkRemove) {
|
||||
using namespace g3;
|
||||
AtomicBoolPtr flag = make_shared < atomic<bool >> (false);
|
||||
AtomicIntPtr count = make_shared < atomic<int >> (0);
|
||||
AtomicBoolPtr flag = make_shared<atomic<bool>>(false);
|
||||
AtomicIntPtr count = make_shared<atomic<int>>(0);
|
||||
{
|
||||
auto worker = g3::LogWorker::createLogWorker();
|
||||
std::unique_ptr<g3::SinkHandle<ScopedSetTrue>> nullsink;
|
||||
@ -91,8 +88,6 @@ TEST(Sink, NullSinkRemove) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace {
|
||||
using AtomicBoolPtr = std::shared_ptr<std::atomic<bool>>;
|
||||
using AtomicIntPtr = std::shared_ptr<std::atomic<int>>;
|
||||
@ -125,8 +120,7 @@ namespace {
|
||||
return total_count;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(ConceptSink, OneHundredSinks) {
|
||||
using namespace g3;
|
||||
@ -135,8 +129,8 @@ TEST(ConceptSink, OneHundredSinks) {
|
||||
|
||||
size_t kNumberOfItems = 100;
|
||||
for (size_t index = 0; index < kNumberOfItems; ++index) {
|
||||
flags.push_back(make_shared < atomic<bool >> (false));
|
||||
counts.push_back(make_shared < atomic<int >> (0));
|
||||
flags.push_back(make_shared<atomic<bool>>(false));
|
||||
counts.push_back(make_shared<atomic<int>>(0));
|
||||
}
|
||||
|
||||
{
|
||||
@ -180,7 +174,6 @@ void AddManySinks(size_t kNumberOfSinks, BoolList& flags, IntVector& counts,
|
||||
flags.push_back(make_shared<atomic<bool>>(false));
|
||||
counts.push_back(make_shared<atomic<int>>(0));
|
||||
sink_handles.push_back(worker->addSink(std::make_unique<ScopedSetTrue>(flags[idx], counts[idx]), &ScopedSetTrue::ReceiveMsg));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,12 +225,13 @@ TEST(ConceptSink, OneHundredRemoveAllSinks) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct VoidReceiver {
|
||||
std::atomic<int>* _atomicCounter;
|
||||
explicit VoidReceiver(std::atomic<int>* counter) : _atomicCounter(counter) {}
|
||||
explicit VoidReceiver(std::atomic<int>* counter) :
|
||||
_atomicCounter(counter) {}
|
||||
|
||||
void receiveMsg(std::string msg) { /*ignored*/}
|
||||
void receiveMsg(std::string msg) { /*ignored*/
|
||||
}
|
||||
void incrementAtomic() {
|
||||
(*_atomicCounter)++;
|
||||
}
|
||||
@ -275,12 +269,13 @@ TEST(ConceptSink, VoidCall__TwoCalls_ExpectingTwoAdd) {
|
||||
EXPECT_EQ(counter, 2);
|
||||
}
|
||||
|
||||
|
||||
struct IntReceiver {
|
||||
std::atomic<int>* _atomicCounter;
|
||||
explicit IntReceiver(std::atomic<int>* counter) : _atomicCounter(counter) {}
|
||||
explicit IntReceiver(std::atomic<int>* counter) :
|
||||
_atomicCounter(counter) {}
|
||||
|
||||
void receiveMsgDoNothing(std::string msg) { /*ignored*/}
|
||||
void receiveMsgDoNothing(std::string msg) { /*ignored*/
|
||||
}
|
||||
void receiveMsgIncrementAtomic(std::string msg) { incrementAtomic(); }
|
||||
int incrementAtomic() {
|
||||
(*_atomicCounter)++;
|
||||
@ -300,13 +295,10 @@ TEST(ConceptSink, IntCall__TwoCalls_ExpectingTwoAdd) {
|
||||
|
||||
auto intFuture2 = handle->call(&IntReceiver::incrementAtomic);
|
||||
EXPECT_EQ(intFuture2.get(), 2);
|
||||
|
||||
}
|
||||
EXPECT_EQ(counter, 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DoLogCalls(std::atomic<bool>* doWhileTrue, size_t counter) {
|
||||
while (doWhileTrue->load()) {
|
||||
LOG(INFO) << "Calling from #" << counter;
|
||||
@ -328,11 +320,10 @@ void DoSlowLogCalls(std::atomic<bool>* doWhileTrue, size_t counter) {
|
||||
std::cout << out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
TEST(ConceptSink, CannotCallSpawnTaskOnNullptrWorker) {
|
||||
auto FailedHelloWorld = [] { std::cout << "Hello World" << std::endl; };
|
||||
auto FailedHelloWorld = [] {
|
||||
std::cout << "Hello World" << std::endl;
|
||||
};
|
||||
kjellkod::Active* active = nullptr;
|
||||
auto failed = g3::spawn_task(FailedHelloWorld, active);
|
||||
EXPECT_ANY_THROW(failed.get());
|
||||
@ -390,7 +381,6 @@ TEST(ConceptSink, AggressiveThreadCallsDuringAddAndRemoveSink) {
|
||||
std::cout << "\nAll threads are joined " << std::endl;
|
||||
}
|
||||
|
||||
|
||||
// This test is commented out but kept here for documentation purposes.
|
||||
// Actually shutting down and re-initializing the logger is not the intention of g3log.
|
||||
// the are several initial setups that happen ONCE and the logger relies on the client
|
||||
@ -424,7 +414,6 @@ TEST(ConceptSink, AggressiveThreadCallsDuringAddAndRemoveSink) {
|
||||
// for (size_t create = 0; create < numberOfCycles; ++create) {
|
||||
// std::cout << ".";
|
||||
|
||||
|
||||
// std::unique_ptr<g3::LogWorker> worker{g3::LogWorker::createLogWorker()};
|
||||
// auto handle = worker->addSink(std::make_unique<IntReceiver>(&atomicCounter), &IntReceiver::receiveMsgIncrementAtomic);
|
||||
// g3::initializeLogging(worker.get());
|
||||
|
@ -6,10 +6,9 @@
|
||||
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
|
||||
* ============================================================================*/
|
||||
|
||||
|
||||
#include "tester_sharedlib.h"
|
||||
#include <g3log/g3log.hpp>
|
||||
#include <g3log/logworker.hpp>
|
||||
#include "tester_sharedlib.h"
|
||||
|
||||
struct RuntimeLoadedLib : public SomeLibrary {
|
||||
|
||||
@ -34,4 +33,3 @@ struct RealLibraryFactory : public LibraryFactory {
|
||||
};
|
||||
|
||||
RealLibraryFactory testRealFactory;
|
||||
|
||||
|
@ -6,17 +6,15 @@
|
||||
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
|
||||
* ============================================================================*/
|
||||
|
||||
|
||||
#include <g3log/g3log.hpp>
|
||||
#include <g3log/logworker.hpp>
|
||||
#include <g3log/logmessage.hpp>
|
||||
#include <g3log/logworker.hpp>
|
||||
|
||||
#include "testing_helpers.h"
|
||||
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace g3;
|
||||
@ -58,7 +56,7 @@ namespace testing_helpers {
|
||||
return (0 == std::remove(path_to_file.c_str()));
|
||||
}
|
||||
|
||||
bool verifyContent(const std::string &total_text, std::string msg_to_find) {
|
||||
bool verifyContent(const std::string& total_text, std::string msg_to_find) {
|
||||
std::string content(total_text);
|
||||
size_t location = content.find(msg_to_find);
|
||||
return (location != std::string::npos);
|
||||
@ -68,9 +66,7 @@ namespace testing_helpers {
|
||||
std::ifstream in;
|
||||
in.open(filename.c_str(), std::ios_base::in);
|
||||
if (!in.is_open()) {
|
||||
return
|
||||
{
|
||||
}; // error just return empty string - test will 'fault'
|
||||
return {}; // error just return empty string - test will 'fault'
|
||||
}
|
||||
std::ostringstream oss;
|
||||
oss << in.rdbuf();
|
||||
@ -82,7 +78,6 @@ namespace testing_helpers {
|
||||
return logs_to_clean_.size();
|
||||
}
|
||||
|
||||
|
||||
LogFileCleaner::~LogFileCleaner() {
|
||||
std::lock_guard<std::mutex> lock(g_mutex);
|
||||
{
|
||||
@ -103,23 +98,25 @@ namespace testing_helpers {
|
||||
}
|
||||
}
|
||||
|
||||
ScopedLogger::ScopedLogger() : _currentWorker(g3::LogWorker::createLogWorker()) {}
|
||||
ScopedLogger::ScopedLogger() :
|
||||
_currentWorker(g3::LogWorker::createLogWorker()) {}
|
||||
ScopedLogger::~ScopedLogger() {}
|
||||
|
||||
g3::LogWorker* ScopedLogger::get() {
|
||||
return _currentWorker.get();
|
||||
}
|
||||
|
||||
RestoreFileLogger::RestoreFileLogger(std::string directory)
|
||||
: _scope(new ScopedLogger), _handle(_scope->get()->addSink(std::make_unique<g3::FileSink>("UNIT_TEST_LOGGER",
|
||||
directory, "g3log", kFlushToDiskWithThisInterval), &g3::FileSink::fileWrite)) {
|
||||
RestoreFileLogger::RestoreFileLogger(std::string directory) :
|
||||
_scope(new ScopedLogger),
|
||||
_handle(_scope->get()->addSink(std::make_unique<g3::FileSink>("UNIT_TEST_LOGGER", directory, "g3log", kFlushToDiskWithThisInterval), &g3::FileSink::fileWrite)) {
|
||||
using namespace g3;
|
||||
g3::initializeLogging(_scope->_currentWorker.get());
|
||||
clearMockFatal();
|
||||
setFatalExitHandler(&mockFatalCall);
|
||||
|
||||
auto filename = _handle->call(&FileSink::fileName);
|
||||
if (!filename.valid()) ADD_FAILURE();
|
||||
if (!filename.valid())
|
||||
ADD_FAILURE();
|
||||
_log_file = filename.get();
|
||||
|
||||
#ifdef G3_DYNAMIC_LOGGING
|
||||
@ -162,4 +159,4 @@ namespace testing_helpers {
|
||||
auto file = filename.get();
|
||||
return readFileToText(file);
|
||||
}
|
||||
} // testing_helpers
|
||||
} // namespace testing_helpers
|
||||
|
Loading…
Reference in New Issue
Block a user