mirror of
https://github.com/KjellKod/g3log.git
synced 2024-12-12 18:30:25 +01:00
Added signalhandler and a little bit of stackdump for linux.
BUGS: how to test fatal unit tests? BUGS: the stack dump is fugly
This commit is contained in:
parent
9dbc9023fc
commit
b7240a610b
BIN
3rdParty/glog/glog-0.3.1_hacked_to_be_truly_synchronous.tgz
vendored
Normal file
BIN
3rdParty/glog/glog-0.3.1_hacked_to_be_truly_synchronous.tgz
vendored
Normal file
Binary file not shown.
@ -1,16 +1,25 @@
|
|||||||
# CMakeLists.txt cmake configuration for g2log test
|
# CMakeLists.txt cmake configuration for g2log test
|
||||||
|
# g2log is a KjellKod Logger
|
||||||
# 2011 @author Kjell Hedström, hedstrom@kjellkod.cc */
|
# 2011 @author Kjell Hedström, hedstrom@kjellkod.cc */
|
||||||
#
|
#
|
||||||
# g2log is a KjellKod Logger
|
|
||||||
|
|
||||||
|
# WINDOWS == README: Example how to setup environment + running an example
|
||||||
|
# 1. please use the "Visual Studio Command Prompt 2010)"
|
||||||
|
# 2. from the g2log folder
|
||||||
|
# mkdir build
|
||||||
|
# cd build;
|
||||||
|
# 3. cmake -G "Visual Studio 10" ..
|
||||||
|
# 4. msbuild g2log-example.sln
|
||||||
|
# 5. Debug\g2log-example.exe
|
||||||
#
|
#
|
||||||
# == README: Example how to setup environment + running tests ===============
|
|
||||||
|
# LINUX == README: Example how to setup environment + running tests for ===============
|
||||||
# 1. Install gtest
|
# 1. Install gtest
|
||||||
# cmake
|
# cmake
|
||||||
# make
|
# make
|
||||||
# make install (possibly as root)
|
# make install (possibly as root)
|
||||||
#
|
#
|
||||||
#
|
|
||||||
#
|
|
||||||
# 2. update path to libraries
|
# 2. update path to libraries
|
||||||
# sudo /sbin/ldconfig -v | grep gtest
|
# sudo /sbin/ldconfig -v | grep gtest
|
||||||
#
|
#
|
||||||
@ -19,9 +28,7 @@
|
|||||||
# libgtest.so.0 -> libgtest.so.0.0.0
|
# libgtest.so.0 -> libgtest.so.0.0.0
|
||||||
# libgtest_main.so.0 -> libgtest_main.so.0.0.0
|
# libgtest_main.so.0 -> libgtest_main.so.0.0.0
|
||||||
#
|
#
|
||||||
#
|
# 3. LINUX:To try this out from folder g2log:
|
||||||
#
|
|
||||||
# 3. To try this out from folder g2log:
|
|
||||||
# mkdir build
|
# mkdir build
|
||||||
# cd build
|
# cd build
|
||||||
# cmake .. # create makefiles in g2log/build directory
|
# cmake .. # create makefiles in g2log/build directory
|
||||||
@ -31,12 +38,24 @@
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
cmake_minimum_required (VERSION 2.6)
|
cmake_minimum_required (VERSION 2.6)
|
||||||
project (kjellkod_logger)
|
project (g2log_by_kjellkod)
|
||||||
set(LOG_SRC ${kjellkod_logger_SOURCE_DIR}/src)
|
set(LOG_SRC ${g2log_by_kjellkod_SOURCE_DIR}/src)
|
||||||
MESSAGE(" LOG_SRC = : ${LOG_SRC}")
|
MESSAGE(" LOG_SRC = : ${LOG_SRC}")
|
||||||
|
include_directories(${LOG_SRC})
|
||||||
|
SET(ACTIVE_CPP0xx_DIR "Release")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
IF(UNIX)
|
IF(UNIX)
|
||||||
|
MESSAGE("")
|
||||||
|
MESSAGE("cmake for *NIX ")
|
||||||
|
MESSAGE("if cmake finishes OK, do make")
|
||||||
|
MESSAGE("then run './g2log-example' or whatever performance test you feel like trying")
|
||||||
|
MESSAGE("")
|
||||||
|
set(PLATFORM_LINK_LIBRIES justthread rt)
|
||||||
set(CMAKE_CXX_FLAGS "-Wall -Wunused -std=c++0x ${CMAKE_CXX_FLAGS_DEBUG} -pthread -I/usr/include/justthread")
|
set(CMAKE_CXX_FLAGS "-Wall -Wunused -std=c++0x ${CMAKE_CXX_FLAGS_DEBUG} -pthread -I/usr/include/justthread")
|
||||||
|
set(G2_LOG_FILES ${LOG_SRC}/logworker.h ${LOG_SRC}/logworker.cpp ${LOG_SRC}/g2log.h ${LOG_SRC}/g2log.cpp ${LOG_SRC}/crashhandler.h ${LOG_SRC}/crashhandler_unix.cpp)
|
||||||
|
include_directories("/usr/include/justthread")
|
||||||
|
|
||||||
# SETUP for GTEST
|
# SETUP for GTEST
|
||||||
set(GTEST_DIR ../3rdParty/gtest/gtest-1.6.0__stripped)
|
set(GTEST_DIR ../3rdParty/gtest/gtest-1.6.0__stripped)
|
||||||
@ -44,80 +63,95 @@ IF(UNIX)
|
|||||||
include_directories(${GTEST_INCLUDE_DIRECTORIES})
|
include_directories(${GTEST_INCLUDE_DIRECTORIES})
|
||||||
add_library(gtest_160_lib ${GTEST_DIR}/src/gtest-all.cc ${GTEST_DIR}/src/gtest_main.cc)
|
add_library(gtest_160_lib ${GTEST_DIR}/src/gtest-all.cc ${GTEST_DIR}/src/gtest_main.cc)
|
||||||
enable_testing(true)
|
enable_testing(true)
|
||||||
|
ENDIF(UNIX)
|
||||||
|
|
||||||
|
#Visual Studio 2010
|
||||||
|
IF(WIN32)
|
||||||
|
MESSAGE("")
|
||||||
|
MESSAGE("cmake for Visual Studio 2010")
|
||||||
|
MESSAGE("if cmake finishes OK, do 'msbuild g2log_by_kjellkod.sln'")
|
||||||
|
MESSAGE("then run 'Debug\\g2log-example.exe' or whatever performance test you feel like trying")
|
||||||
|
MESSAGE("")
|
||||||
|
set(PLATFORM_LINK_LIBRIES $ENV{PROGRAMFILES}/JustSoftwareSolutions/JustThread/lib/justthread_vc10_mdd.lib)
|
||||||
|
set(G2_LOG_FILES ${LOG_SRC}/logworker.h ${LOG_SRC}/logworker.cpp ${LOG_SRC}/g2log.h ${LOG_SRC}/g2log.cpp ${LOG_SRC}/crashhandler.h ${LOG_SRC}/crashhandler_win.cpp)
|
||||||
|
include_directories("$ENV{PROGRAMFILES}/JustSoftwareSolutions/JustThread/include")
|
||||||
|
ENDIF(WIN32)
|
||||||
|
|
||||||
|
|
||||||
# make the src directory available
|
|
||||||
include_directories(/usr/include/justthread) #not necessarily needed if it's in the path
|
|
||||||
|
|
||||||
|
# GENERIC STEPS
|
||||||
# add a ActiveObject library
|
# add a ActiveObject library
|
||||||
set(ACTIVE_DIR ${LOG_SRC})
|
add_library(lib_activeobject ${LOG_SRC}/active.cpp ${LOG_SRC}/active.h ${LOG_SRC}/shared_queue.h)
|
||||||
include_directories(${ACTIVE_DIR})
|
|
||||||
MESSAGE(" ACTIVE_DIR = : ${ACTIVE_DIR}")
|
|
||||||
SET(ACTIVE_CPP0xx_DIR "Release")
|
|
||||||
add_library(lib_activeobject ${ACTIVE_DIR}/active.cpp ${ACTIVE_DIR}/active.h ${ACTIVE_DIR}/shared_queue.h)
|
|
||||||
set_target_properties(lib_activeobject PROPERTIES LINKER_LANGUAGE CXX)
|
set_target_properties(lib_activeobject PROPERTIES LINKER_LANGUAGE CXX)
|
||||||
|
|
||||||
|
# add a g2log library
|
||||||
include_directories(src)
|
include_directories(src)
|
||||||
include_directories(${LOG_SRC})
|
include_directories(${LOG_SRC})
|
||||||
#MESSAGE(" LOG_SRC = : ${LOG_SRC}")
|
MESSAGE(" LOG_SRC = : ${LOG_SRC}")
|
||||||
add_library(lib_logger ${LOG_SRC}/logworker.h ${LOG_SRC}/logworker.cpp ${LOG_SRC}/g2log.h ${LOG_SRC}/g2log.cpp )
|
MESSAGE(" g2logger files: [${G2_LOG_FILES}]")
|
||||||
set_target_properties(lib_logger PROPERTIES LINKER_LANGUAGE CXX)
|
add_library(lib_g2logger ${G2_LOG_FILES})
|
||||||
target_link_libraries(lib_logger lib_activeobject)
|
set_target_properties(lib_g2logger PROPERTIES LINKER_LANGUAGE CXX)
|
||||||
|
target_link_libraries(lib_g2logger lib_activeobject)
|
||||||
|
|
||||||
|
|
||||||
# create the the example EXECUTABLE
|
# create the the example EXECUTABLE
|
||||||
add_executable(g2log-example src/main.cpp)
|
add_executable(g2log-example src/main.cpp)
|
||||||
# link executable with the src library
|
target_link_libraries(g2log-example lib_activeobject lib_g2logger ${PLATFORM_LINK_LIBRIES})
|
||||||
target_link_libraries(g2log-example lib_activeobject lib_logger justthread rt)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Below are g2log unit testTEST
|
# Below are g2log unit testTEST
|
||||||
# and PERFORMANCE comparisons between g2log and google's glog
|
# and PERFORMANCE comparisons between g2log and google's glog
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
include_directories(build)
|
|
||||||
|
|
||||||
# create the the TEST executable
|
|
||||||
add_executable(g2log-unit_test ../test_main/test_main.cpp test/test_io.cpp)
|
|
||||||
target_link_libraries(g2log-unit_test lib_activeobject lib_logger gtest_160_lib justthread rt)
|
|
||||||
|
|
||||||
# ---- Below g2log Performance -----
|
# ---- Below g2log Performance -----
|
||||||
# create the the g2log MEAN_PERFORMANCE executable
|
# create the the g2log MEAN_PERFORMANCE executable
|
||||||
add_executable(g2log-performance-mean test/main_mean.cpp test/performance.h)
|
add_executable(g2log-performance-mean test/main_mean.cpp test/performance.h)
|
||||||
set_target_properties(g2log-performance-mean PROPERTIES COMPILE_DEFINITIONS "G2LOG_PERFORMANCE=1")
|
set_target_properties(g2log-performance-mean PROPERTIES COMPILE_DEFINITIONS "G2LOG_PERFORMANCE=1")
|
||||||
target_link_libraries(g2log-performance-mean lib_activeobject lib_logger justthread rt)
|
target_link_libraries(g2log-performance-mean lib_activeobject lib_g2logger ${PLATFORM_LINK_LIBRIES})
|
||||||
|
|
||||||
# create the the g2log TWO_THREADS_MEAN_PERFORMANCE executable
|
# create the the g2log TWO_THREADS_MEAN_PERFORMANCE executable
|
||||||
add_executable(g2log-performance-2threads_mean test/main_2threads_mean.cpp test/performance.h)
|
add_executable(g2log-performance-2threads_mean test/main_2threads_mean.cpp test/performance.h)
|
||||||
set_target_properties(g2log-performance-2threads_mean PROPERTIES COMPILE_DEFINITIONS "G2LOG_PERFORMANCE=1")
|
set_target_properties(g2log-performance-2threads_mean PROPERTIES COMPILE_DEFINITIONS "G2LOG_PERFORMANCE=1")
|
||||||
target_link_libraries(g2log-performance-2threads_mean lib_activeobject lib_logger justthread rt)
|
target_link_libraries(g2log-performance-2threads_mean lib_activeobject lib_g2logger ${PLATFORM_LINK_LIBRIES})
|
||||||
|
|
||||||
# create the the g2log TWO_THREADS_WORST_CASE_PERFORMANCE executable
|
# create the the g2log TWO_THREADS_WORST_CASE_PERFORMANCE executable
|
||||||
add_executable(g2log-performance-2threads_worst test/main_2threads_worst.cpp test/performance.h)
|
add_executable(g2log-performance-2threads_worst test/main_2threads_worst.cpp test/performance.h)
|
||||||
set_target_properties(g2log-performance-2threads_worst PROPERTIES COMPILE_DEFINITIONS "G2LOG_PERFORMANCE=1")
|
set_target_properties(g2log-performance-2threads_worst PROPERTIES COMPILE_DEFINITIONS "G2LOG_PERFORMANCE=1")
|
||||||
target_link_libraries(g2log-performance-2threads_worst lib_activeobject lib_logger justthread rt)
|
target_link_libraries(g2log-performance-2threads_worst lib_activeobject lib_g2logger ${PLATFORM_LINK_LIBRIES})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
IF(UNIX)
|
||||||
#
|
#
|
||||||
# ---- Below GOOGLE glog Performance -----
|
# ---- Below GOOGLE glog Performance -----
|
||||||
# create the the GOOGLE MEAN_PERFORMANCE executable
|
# create the the GOOGLE MEAN_PERFORMANCE executable
|
||||||
# Generate the DEFINE (for glog) needed to differentiate between the glog and the g2log test
|
# Generate the DEFINE (for glog) needed to differentiate between the glog and the g2log test
|
||||||
add_executable(google_glog-performance-mean test/main_mean.cpp test/performance.h)
|
add_executable(google_glog-performance-mean test/main_mean.cpp test/performance.h)
|
||||||
set_target_properties(google_glog-performance-mean PROPERTIES COMPILE_DEFINITIONS "GOOGLE_GLOG_PERFORMANCE=1")
|
set_target_properties(google_glog-performance-mean PROPERTIES COMPILE_DEFINITIONS "GOOGLE_GLOG_PERFORMANCE=1")
|
||||||
target_link_libraries(google_glog-performance-mean lib_activeobject glog justthread rt)
|
target_link_libraries(google_glog-performance-mean lib_activeobject glog ${PLATFORM_LINK_LIBRIES})
|
||||||
|
|
||||||
# create the the GOOGLE MEAN_PERFORMANCE executable
|
# create the the GOOGLE MEAN_PERFORMANCE executable
|
||||||
add_executable(google_glog-performance-2threads_mean test/main_2threads_mean.cpp test/performance.h)
|
add_executable(google_glog-performance-2threads_mean test/main_2threads_mean.cpp test/performance.h)
|
||||||
set_target_properties(google_glog-performance-2threads_mean PROPERTIES COMPILE_DEFINITIONS "GOOGLE_GLOG_PERFORMANCE=1")
|
set_target_properties(google_glog-performance-2threads_mean PROPERTIES COMPILE_DEFINITIONS "GOOGLE_GLOG_PERFORMANCE=1")
|
||||||
target_link_libraries(google_glog-performance-2threads_mean lib_activeobject glog justthread rt)
|
target_link_libraries(google_glog-performance-2threads_mean lib_activeobject glog ${PLATFORM_LINK_LIBRIES})
|
||||||
|
|
||||||
# create the the GOOGLE MEAN_PERFORMANCE executable
|
# create the the GOOGLE MEAN_PERFORMANCE executable
|
||||||
add_executable(google_glog-performance-2threads_worst test/main_2threads_worst.cpp test/performance.h)
|
add_executable(google_glog-performance-2threads_worst test/main_2threads_worst.cpp test/performance.h)
|
||||||
set_target_properties(google_glog-performance-2threads_worst PROPERTIES COMPILE_DEFINITIONS "GOOGLE_GLOG_PERFORMANCE=1")
|
set_target_properties(google_glog-performance-2threads_worst PROPERTIES COMPILE_DEFINITIONS "GOOGLE_GLOG_PERFORMANCE=1")
|
||||||
target_link_libraries(google_glog-performance-2threads_worst lib_activeobject glog justthread rt)
|
target_link_libraries(google_glog-performance-2threads_worst lib_activeobject glog ${PLATFORM_LINK_LIBRIES})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# create the the TEST executable
|
||||||
|
add_executable(g2log-unit_test ../test_main/test_main.cpp test/test_io.cpp)
|
||||||
|
add_library(lib_test_logger ${LOG_SRC}/logworker.h ${LOG_SRC}/logworker.cpp ${LOG_SRC}/g2log.h ${LOG_SRC}/g2log.cpp ${LOG_SRC}/crashhandler.h ${LOG_SRC}/crashhandler.cpp)
|
||||||
|
set_target_properties(lib_test_logger PROPERTIES LINKER_LANGUAGE CXX)
|
||||||
|
set_target_properties(lib_test_logger PROPERTIES COMPILE_DEFINITIONS "YALLA=1")
|
||||||
|
target_link_libraries(lib_test_logger lib_activeobject)
|
||||||
|
# For unit-test only, dont 'crash' by signals, instead just throw a std::runtime_error
|
||||||
|
set_target_properties(g2log-unit_test PROPERTIES COMPILE_DEFINITIONS "YALLA=1")
|
||||||
|
target_link_libraries(g2log-unit_test lib_activeobject lib_test_logger gtest_160_lib justthread rt)
|
||||||
ENDIF(UNIX)
|
ENDIF(UNIX)
|
||||||
|
|
||||||
|
@ -34,8 +34,8 @@ typedef std::function<void()> Callback;
|
|||||||
|
|
||||||
class Active {
|
class Active {
|
||||||
private:
|
private:
|
||||||
Active(const Active&) = delete;
|
Active(const Active&); // c++11 feature not yet in vs2010 = delete;
|
||||||
Active& operator=(const Active&) = delete;
|
Active& operator=(const Active&); // c++11 feature not yet in vs2010 = delete;
|
||||||
|
|
||||||
Active(); // Construction ONLY through factory createActive();
|
Active(); // Construction ONLY through factory createActive();
|
||||||
|
|
||||||
|
33
g2log/src/crashhandler.h
Normal file
33
g2log/src/crashhandler.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#ifndef CRASH_HANDLER_H_
|
||||||
|
#define CRASH_HANDLER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <csignal>
|
||||||
|
|
||||||
|
namespace g2
|
||||||
|
{
|
||||||
|
|
||||||
|
// PRIVATE-INTERNAL API
|
||||||
|
namespace internal
|
||||||
|
{
|
||||||
|
/** \return signal_name. Ref: signum.h and \ref installSignalHandler */
|
||||||
|
std::string signalName(int signal_number);
|
||||||
|
|
||||||
|
/** Re-"throw" a fatal signal, previously caught. This will exit the application
|
||||||
|
* This is an internal only function. Do not use it elsewhere. It is triggered
|
||||||
|
* from g2log, LogWorker after flushing messages to file */
|
||||||
|
void exitWithDefaultSignalHandler(int signal_number);
|
||||||
|
} // end g2::interal
|
||||||
|
|
||||||
|
|
||||||
|
// PUBLIC API:
|
||||||
|
/** Install signal handler that catches FATAL C-runtime or OS signals
|
||||||
|
SIGABRT ABORT (ANSI), abnormal termination
|
||||||
|
SIGFPE Floating point exception (ANSI): http://en.wikipedia.org/wiki/SIGFPE
|
||||||
|
SIGILL ILlegal instruction (ANSI)
|
||||||
|
SIGSEGV Segmentation violation i.e. illegal memory reference
|
||||||
|
SIGTERM TERMINATION (ANSI) */
|
||||||
|
void installSignalHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CRASH_HANDLER_H_
|
125
g2log/src/crashhandler_unix.cpp
Normal file
125
g2log/src/crashhandler_unix.cpp
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
#include "crashhandler.h"
|
||||||
|
#include "g2log.h"
|
||||||
|
|
||||||
|
#include <csignal>
|
||||||
|
#include <cstring>
|
||||||
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
|
||||||
|
// or? gcc on windows I guess,.
|
||||||
|
#error "crashhandler_unix.cpp used but it's a windows system"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <unistd.h> // getpid,
|
||||||
|
#include <execinfo.h>
|
||||||
|
#include <ucontext.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// simple dump of stack,. then exit through g2log background worker
|
||||||
|
// Ref: http://stackoverflow.com/questions/77005/how-to-generate-a-stacktrace-when-my-gcc-c-app-crashes
|
||||||
|
void crashHandler(int signal_number, siginfo_t *info, void *unused_context)
|
||||||
|
{
|
||||||
|
const size_t max_dump_size = 100;
|
||||||
|
void* dump[max_dump_size];
|
||||||
|
size_t size = backtrace(dump, max_dump_size);
|
||||||
|
// overwrite sigaction with caller's address
|
||||||
|
char** messages = backtrace_symbols(dump, size);
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Received fatal signal: " << g2::internal::signalName(signal_number);
|
||||||
|
oss << "(" << signal_number << ")" << std::endl;
|
||||||
|
oss << "\tPID: " << getpid() << std::endl;
|
||||||
|
// dump stack: skip first frame, since that is here
|
||||||
|
for(size_t idx = 1; idx < size && messages != nullptr; ++idx)
|
||||||
|
{
|
||||||
|
oss << "\tstack dump [" << idx << "] " << messages[idx] << std::endl;
|
||||||
|
}
|
||||||
|
free(messages);
|
||||||
|
{ // Local scope, trigger send
|
||||||
|
using namespace g2::internal;
|
||||||
|
std::ostringstream fatal_stream;
|
||||||
|
fatal_stream << "\n\n***** FATAL TRIGGER RECEIVED ******* " << std::endl;
|
||||||
|
fatal_stream << oss.str() << std::endl;
|
||||||
|
fatal_stream << "\n***** RETHROWING SIGNAL " << signalName(signal_number) << "(" << signal_number << ")" << std::endl;
|
||||||
|
|
||||||
|
FatalMessage fatal_message(fatal_stream.str(),FatalMessage::kReasonOS_FATAL_SIGNAL, signal_number);
|
||||||
|
FatalTrigger trigger(fatal_message); std::ostringstream oss;
|
||||||
|
std::cerr << fatal_message.message_ << std::endl << std::flush;
|
||||||
|
} // message sent to LogWorker
|
||||||
|
// wait to die -- will be inside the FatalTrigger
|
||||||
|
}
|
||||||
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Redirecting and using signals. In case of fatal signals g2log should log the fatal signal
|
||||||
|
// and flush the log queue and then "rethrow" the signal to exit
|
||||||
|
namespace g2
|
||||||
|
{
|
||||||
|
// References:
|
||||||
|
// sigaction : change the default action if a specific signal is received
|
||||||
|
// http://linux.die.net/man/2/sigaction
|
||||||
|
// http://publib.boulder.ibm.com/infocenter/aix/v6r1/index.jsp?topic=%2Fcom.ibm.aix.basetechref%2Fdoc%2Fbasetrf2%2Fsigaction.html
|
||||||
|
//
|
||||||
|
// signal: http://linux.die.net/man/7/signal and
|
||||||
|
// http://msdn.microsoft.com/en-us/library/xdkz3x12%28vs.71%29.asp
|
||||||
|
//
|
||||||
|
// memset + sigemptyset: Maybe unnecessary to do both but there seems to be some confusion here
|
||||||
|
// ,plenty of examples when both or either are used
|
||||||
|
// http://stackoverflow.com/questions/6878546/why-doesnt-parent-process-return-to-the-exact-location-after-handling-signal_number
|
||||||
|
namespace internal
|
||||||
|
{
|
||||||
|
std::string signalName(int signal_number)
|
||||||
|
{
|
||||||
|
switch(signal_number)
|
||||||
|
{
|
||||||
|
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(" << signal_number << ")";
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triggered by g2log::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
|
||||||
|
void exitWithDefaultSignalHandler(int signal_number)
|
||||||
|
{
|
||||||
|
struct sigaction action;
|
||||||
|
memset(&action, 0, sizeof(action)); //
|
||||||
|
sigemptyset(&action.sa_mask);
|
||||||
|
action.sa_handler = SIG_DFL; // take default action for the signal
|
||||||
|
sigaction(signal_number, &action, NULL);
|
||||||
|
kill(getpid(), signal_number);
|
||||||
|
}
|
||||||
|
} // end g2::internal
|
||||||
|
|
||||||
|
|
||||||
|
void installSignalHandler()
|
||||||
|
{
|
||||||
|
struct sigaction action;
|
||||||
|
memset(&action, 0, sizeof(action));
|
||||||
|
sigemptyset(&action.sa_mask);
|
||||||
|
action.sa_sigaction = &crashHandler; // callback to crashHandler for fatal signals
|
||||||
|
// sigaction to use sa_sigaction file. ref: http://www.linuxprogrammingblog.com/code-examples/sigaction
|
||||||
|
action.sa_flags = SA_SIGINFO;
|
||||||
|
|
||||||
|
// do it verbose style - install all signal actions
|
||||||
|
if(sigaction(SIGABRT, &action, NULL) < 0)
|
||||||
|
perror("sigaction - SIGABRT");
|
||||||
|
if(sigaction(SIGFPE, &action, NULL) < 0)
|
||||||
|
perror("sigaction - SIGFPE");
|
||||||
|
if(sigaction(SIGILL, &action, NULL) < 0)
|
||||||
|
perror("sigaction - SIGILL");
|
||||||
|
if(sigaction(SIGSEGV, &action, NULL) < 0)
|
||||||
|
perror("sigaction - SIGSEGV");
|
||||||
|
if(sigaction(SIGTERM, &action, NULL) < 0)
|
||||||
|
perror("sigaction - SIGTERM");
|
||||||
|
}
|
||||||
|
} // end namespace g2
|
86
g2log/src/crashhandler_win.cpp
Normal file
86
g2log/src/crashhandler_win.cpp
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#include "crashhandler.h"
|
||||||
|
#include "g2log.h"
|
||||||
|
|
||||||
|
#include <csignal>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
#if !(defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
||||||
|
#error "crashhandler_win.cpp used but not on a windows system"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <process.h> // getpid
|
||||||
|
#define getpid _getpid
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
void crashHandler(int signal_number)
|
||||||
|
{
|
||||||
|
using namespace g2::internal;
|
||||||
|
std::ostringstream fatal_stream;
|
||||||
|
fatal_stream << "\n\n***** FATAL TRIGGER RECEIVED ******* " << std::endl;
|
||||||
|
fatal_stream << "\n***** RETHROWING SIGNAL " << signalName(signal_number) << "(" << signal_number << ")" << std::endl;
|
||||||
|
|
||||||
|
FatalMessage fatal_message(fatal_stream.str(),FatalMessage::kReasonOS_FATAL_SIGNAL, signal_number);
|
||||||
|
FatalTrigger trigger(fatal_message); std::ostringstream oss;
|
||||||
|
std::cerr << fatal_message.message_ << std::endl << std::flush;
|
||||||
|
} // scope exit - message sent to LogWorker, wait to die...
|
||||||
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
|
namespace g2
|
||||||
|
{
|
||||||
|
namespace internal
|
||||||
|
{
|
||||||
|
std::string signalName(int signal_number)
|
||||||
|
{
|
||||||
|
switch(signal_number)
|
||||||
|
{
|
||||||
|
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(" << signal_number << ")";
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Triggered by g2log::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
|
||||||
|
void exitWithDefaultSignalHandler(int signal_number)
|
||||||
|
{
|
||||||
|
// Restore our signalhandling to default
|
||||||
|
if(SIG_ERR == signal (SIGABRT, SIG_DFL))
|
||||||
|
perror("signal - SIGABRT");
|
||||||
|
if(SIG_ERR == signal (SIGFPE, SIG_DFL))
|
||||||
|
perror("signal - SIGABRT");
|
||||||
|
if(SIG_ERR == signal (SIGSEGV, SIG_DFL))
|
||||||
|
perror("signal - SIGABRT");
|
||||||
|
if(SIG_ERR == signal (SIGILL, SIG_DFL))
|
||||||
|
perror("signal - SIGABRT");
|
||||||
|
if(SIG_ERR == signal (SIGTERM, SIG_DFL))
|
||||||
|
perror("signal - SIGABRT");
|
||||||
|
|
||||||
|
raise(signal_number);
|
||||||
|
}
|
||||||
|
} // end g2::internal
|
||||||
|
|
||||||
|
|
||||||
|
void installSignalHandler()
|
||||||
|
{
|
||||||
|
if(SIG_ERR == signal (SIGABRT, crashHandler))
|
||||||
|
perror("signal - SIGABRT");
|
||||||
|
if(SIG_ERR == signal (SIGFPE, crashHandler))
|
||||||
|
perror("signal - SIGFPE");
|
||||||
|
if(SIG_ERR == signal (SIGSEGV, crashHandler))
|
||||||
|
perror("signal - SIGSEGV");
|
||||||
|
if(SIG_ERR == signal (SIGILL, crashHandler))
|
||||||
|
perror("signal - SIGILL");
|
||||||
|
if(SIG_ERR == signal (SIGTERM, crashHandler))
|
||||||
|
perror("signal - SIGTERM");
|
||||||
|
}
|
||||||
|
} // end namespace g2
|
@ -20,7 +20,10 @@
|
|||||||
#include <cstdio> // vsnprintf
|
#include <cstdio> // vsnprintf
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "logworker.h"
|
#include "logworker.h"
|
||||||
|
#include "crashhandler.h"
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
namespace g2
|
namespace g2
|
||||||
{
|
{
|
||||||
@ -52,10 +55,17 @@ std::string splitFileName(const std::string& str)
|
|||||||
|
|
||||||
void initializeLogging(LogWorker *bgworker)
|
void initializeLogging(LogWorker *bgworker)
|
||||||
{
|
{
|
||||||
|
static bool once_only_signalhandler = false;
|
||||||
std::lock_guard<std::mutex> lock(internal::g_logging_init_mutex);
|
std::lock_guard<std::mutex> lock(internal::g_logging_init_mutex);
|
||||||
CHECK(!internal::isLoggingInitialized());
|
CHECK(!internal::isLoggingInitialized());
|
||||||
CHECK(bgworker != nullptr);
|
CHECK(bgworker != nullptr);
|
||||||
internal::g_logger_instance = bgworker;
|
internal::g_logger_instance = bgworker;
|
||||||
|
|
||||||
|
if(false == once_only_signalhandler)
|
||||||
|
{
|
||||||
|
installSignalHandler();
|
||||||
|
once_only_signalhandler = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogWorker* shutDownLogging()
|
LogWorker* shutDownLogging()
|
||||||
@ -83,11 +93,11 @@ LogContractMessage::~LogContractMessage()
|
|||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
if(0 == expression_.compare(k_fatal_log_expression))
|
if(0 == expression_.compare(k_fatal_log_expression))
|
||||||
{
|
{
|
||||||
oss << "[ *******\tRUNTIME EXCEPTION caused by LOG(FATAL):\t";
|
oss << "\n[ *******\tEXIT trigger caused by LOG(FATAL): \n\t";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
oss << "\nRUNTIME EXCEPTION caused by broken Contract: [" << expression_ << "]\t";
|
oss << "\n[ *******\tEXIT trigger caused by broken Contract: CHECK(" << expression_ << ")\n\t";
|
||||||
}
|
}
|
||||||
log_entry_ = oss.str();
|
log_entry_ = oss.str();
|
||||||
}
|
}
|
||||||
@ -103,11 +113,12 @@ LogMessage::LogMessage(const std::string &file, const int line, const std::strin
|
|||||||
|
|
||||||
LogMessage::~LogMessage()
|
LogMessage::~LogMessage()
|
||||||
{
|
{
|
||||||
|
using namespace internal;
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
const bool fatal = (0 == level_.compare("FATAL"));
|
const bool fatal = (0 == level_.compare("FATAL"));
|
||||||
oss << level_ << " [" << internal::splitFileName(file_);
|
oss << level_ << " [" << splitFileName(file_);
|
||||||
if(fatal)
|
if(fatal)
|
||||||
oss << " F: " << function_ ;
|
oss << " at: " << function_ ;
|
||||||
oss << " L: " << line_ << "]\t";
|
oss << " L: " << line_ << "]\t";
|
||||||
|
|
||||||
const std::string str(stream_.str());
|
const std::string str(stream_.str());
|
||||||
@ -117,24 +128,49 @@ LogMessage::~LogMessage()
|
|||||||
}
|
}
|
||||||
log_entry_ += oss.str();
|
log_entry_ += oss.str();
|
||||||
|
|
||||||
if(!internal::isLoggingInitialized() )
|
if(!isLoggingInitialized() )
|
||||||
{
|
{
|
||||||
std::cerr << "Did you forget to call g2::InitializeLogging(LogWorker*) in your main.cpp?" << std::endl;
|
std::cerr << "Did you forget to call g2::InitializeLogging(LogWorker*) in your main.cpp?" << std::endl;
|
||||||
std::cerr << log_entry_ << std::endl << std::flush;
|
std::cerr << log_entry_ << std::endl << std::flush;
|
||||||
throw std::runtime_error("Logger not initialized with g2::InitializeLogging(LogWorker*) for msg:\n" + log_entry_);
|
throw std::runtime_error("Logger not initialized with g2::InitializeLogging(LogWorker*) for msg:\n" + log_entry_);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal::g_logger_instance->save(log_entry_); // message saved
|
|
||||||
if(fatal)
|
if(fatal) // os_fatal is handled by crashhandlers
|
||||||
{
|
{
|
||||||
|
{ // local scope - to trigger FatalMessage sending
|
||||||
|
FatalMessage::FatalType fatal_type(FatalMessage::kReasonFatal);
|
||||||
|
FatalMessage fatal_message(log_entry_, fatal_type, SIGABRT);
|
||||||
|
FatalTrigger trigger(fatal_message);
|
||||||
std::cerr << log_entry_ << "\t******* ]" << std::endl << std::flush;
|
std::cerr << log_entry_ << "\t******* ]" << std::endl << std::flush;
|
||||||
throw std::runtime_error(log_entry_);
|
} // will send to worker
|
||||||
|
}
|
||||||
|
internal::g_logger_instance->save(log_entry_); // message saved
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// represents the actual fatal message
|
||||||
|
FatalMessage::FatalMessage(std::string message, FatalType type, int signal_id)
|
||||||
|
: message_(message)
|
||||||
|
, type_(type)
|
||||||
|
, signal_id_(signal_id){}
|
||||||
|
|
||||||
|
// used to RAII trigger fatal message sending to LogWorker
|
||||||
|
FatalTrigger::FatalTrigger(const FatalMessage &message)
|
||||||
|
: message_(message){}
|
||||||
|
|
||||||
|
// at destruction, flushes fatal message to LogWorker
|
||||||
|
FatalTrigger::~FatalTrigger()
|
||||||
|
{
|
||||||
|
internal::g_logger_instance->fatal(message_);
|
||||||
|
#if !defined(YALLA) // don't sleep if unit-testing
|
||||||
|
// wait to die
|
||||||
|
while(true){std::this_thread::sleep_for(std::chrono::seconds(1));}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void LogMessage::messageSave(const char *printf_like_message, ...)
|
void LogMessage::messageSave(const char *printf_like_message, ...)
|
||||||
{
|
{
|
||||||
char finished_message[constants::kMaxMessageSize];
|
char finished_message[constants::kMaxMessageSize];
|
||||||
|
@ -23,8 +23,14 @@
|
|||||||
|
|
||||||
class LogWorker;
|
class LogWorker;
|
||||||
|
|
||||||
|
#if !(defined(__PRETTY_FUNCTION__))
|
||||||
|
#define __PRETTY_FUNCTION__ __FUNCTION__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Levels for logging, made so that it would be easy to change, remove, add levels -- KjellKod
|
// Levels for logging, made so that it would be easy to change, remove, add levels -- KjellKod
|
||||||
const int DEBUG = 0, INFO = 1, WARNING = 2, FATAL = 3;
|
const int DEBUG = 0, INFO = 1, WARNING = 2, FATAL = 3;
|
||||||
|
static const std::string k_os_signal_fatal_text = "OS_SIGNAL_FATAL";
|
||||||
static const std::string k_fatal_log_expression = ""; // using LogContractMessage but no boolean expression
|
static const std::string k_fatal_log_expression = ""; // using LogContractMessage but no boolean expression
|
||||||
|
|
||||||
// GCC Predefined macros: http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
|
// GCC Predefined macros: http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
|
||||||
@ -155,6 +161,28 @@ typedef std::chrono::duration<long,std::ratio<1, 1000> > millisecond;
|
|||||||
typedef std::chrono::duration<long long,std::ratio<1, 1000000> > microsecond;
|
typedef std::chrono::duration<long long,std::ratio<1, 1000000> > microsecond;
|
||||||
typedef const std::string& LogEntry;
|
typedef const std::string& LogEntry;
|
||||||
|
|
||||||
|
/** Trigger for flushing the message queue and exiting the applicaition
|
||||||
|
A thread that causes a FatalMessage will sleep forever until the
|
||||||
|
application has exited (after message flush) */
|
||||||
|
struct FatalMessage
|
||||||
|
{
|
||||||
|
enum FatalType {kReasonFatal, kReasonOS_FATAL_SIGNAL};
|
||||||
|
FatalMessage(std::string message, FatalType type, int signal_id);
|
||||||
|
|
||||||
|
std::string message_;
|
||||||
|
FatalType type_;
|
||||||
|
int signal_id_;
|
||||||
|
};
|
||||||
|
// Will trigger a FatalMessage sending
|
||||||
|
struct FatalTrigger
|
||||||
|
{
|
||||||
|
FatalTrigger(const FatalMessage& message);
|
||||||
|
~FatalTrigger();
|
||||||
|
FatalMessage message_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Log message for 'printf-like' or stream logging, it's a temporary message constructions
|
// Log message for 'printf-like' or stream logging, it's a temporary message constructions
|
||||||
class LogMessage
|
class LogMessage
|
||||||
{
|
{
|
||||||
@ -168,6 +196,10 @@ class LogMessage
|
|||||||
// IMPORTANT: You muse enable the compiler flag '-Wall' for this to work!
|
// IMPORTANT: You muse enable the compiler flag '-Wall' for this to work!
|
||||||
// ref: http://www.unixwiz.net/techtips/gnu-c-attributes.html
|
// ref: http://www.unixwiz.net/techtips/gnu-c-attributes.html
|
||||||
//
|
//
|
||||||
|
//If the compiler does not support attributes, disable them
|
||||||
|
#ifndef __GNUC__
|
||||||
|
#define __attribute__(x)
|
||||||
|
#endif
|
||||||
// Coder note: Since it's C++ and not C EVERY CLASS FUNCTION always get a first
|
// Coder note: Since it's C++ and not C EVERY CLASS FUNCTION always get a first
|
||||||
// compiler given argument 'this' this must be supplied as well, hence '2,3'
|
// compiler given argument 'this' this must be supplied as well, hence '2,3'
|
||||||
// ref: http://www.codemaestro.com/reviews/18 -- ref KjellKod
|
// ref: http://www.codemaestro.com/reviews/18 -- ref KjellKod
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* ********************************************* */
|
* ********************************************* */
|
||||||
|
|
||||||
#include "logworker.h"
|
#include "logworker.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -16,8 +17,13 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
|
#if defined(YALLA)
|
||||||
|
#include <stdexcept> // exceptions
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "active.h"
|
#include "active.h"
|
||||||
#include "g2log.h"
|
#include "g2log.h"
|
||||||
|
#include "crashhandler.h"
|
||||||
|
|
||||||
using namespace g2::internal;
|
using namespace g2::internal;
|
||||||
namespace
|
namespace
|
||||||
@ -57,6 +63,7 @@ struct LogWorkerImpl
|
|||||||
~LogWorkerImpl();
|
~LogWorkerImpl();
|
||||||
|
|
||||||
void backgroundFileWrite(g2::internal::LogEntry message);
|
void backgroundFileWrite(g2::internal::LogEntry message);
|
||||||
|
void backgroundExitFatal(g2::internal::FatalMessage fatal_message);
|
||||||
|
|
||||||
std::string log_file_with_path_;
|
std::string log_file_with_path_;
|
||||||
std::unique_ptr<kjellkod::Active> bg_;
|
std::unique_ptr<kjellkod::Active> bg_;
|
||||||
@ -64,9 +71,8 @@ struct LogWorkerImpl
|
|||||||
g2::internal::time_point start_time_;
|
g2::internal::time_point start_time_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LogWorkerImpl& operator=(const LogWorkerImpl&) = delete; // no assignment, no copy
|
LogWorkerImpl& operator=(const LogWorkerImpl&); // c++11 feature not yet in vs2010 = delete;
|
||||||
LogWorkerImpl(const LogWorkerImpl& other) = delete;
|
LogWorkerImpl(const LogWorkerImpl& other); // c++11 feature not yet in vs2010 = delete;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -127,9 +133,24 @@ void LogWorkerImpl::backgroundFileWrite(LogEntry message)
|
|||||||
out << "\n" << t.year << "/" << setw(2) << t.month << "/" << setw(2) << t.day;
|
out << "\n" << t.year << "/" << setw(2) << t.month << "/" << setw(2) << t.day;
|
||||||
out << " " << setw(2) << t.hour << ":"<< setw(2) << t.minute <<":"<< setw(2) << t.second;
|
out << " " << setw(2) << t.hour << ":"<< setw(2) << t.minute <<":"<< setw(2) << t.second;
|
||||||
out << "." << chrono::duration_cast<microsecond>(timesnapshot - start_time_).count(); //microseconds
|
out << "." << chrono::duration_cast<microsecond>(timesnapshot - start_time_).count(); //microseconds
|
||||||
out << "\t" << message;
|
out << "\t" << message << std::flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LogWorkerImpl::backgroundExitFatal(FatalMessage fatal_message)
|
||||||
|
{
|
||||||
|
backgroundFileWrite(fatal_message.message_);
|
||||||
|
|
||||||
|
#if defined(YALLA)
|
||||||
|
// If running unit test - we simplify matters by not sending the signal, but
|
||||||
|
// by just throwing an exception
|
||||||
|
throw std::runtime_error(fatal_message.message_);
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
out.close();
|
||||||
|
exitWithDefaultSignalHandler(fatal_message.signal_id_);
|
||||||
|
perror("g2log exited after receiving FATAL trigger. Flush message status: "); // should never reach this point
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -144,7 +165,7 @@ void LogWorkerImpl::backgroundFileWrite(LogEntry message)
|
|||||||
LogWorker::~LogWorker()
|
LogWorker::~LogWorker()
|
||||||
{
|
{
|
||||||
pimpl_.reset();
|
pimpl_.reset();
|
||||||
//std::cout << "\nLogWorker finished with log: " << log_file_with_path_ << std::endl << std::flush;
|
std::cout << "\nExiting, log location: " << log_file_with_path_ << std::endl << std::flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogWorker::save(g2::internal::LogEntry msg)
|
void LogWorker::save(g2::internal::LogEntry msg)
|
||||||
@ -152,6 +173,10 @@ void LogWorkerImpl::backgroundFileWrite(LogEntry message)
|
|||||||
pimpl_->bg_->send(std::tr1::bind(&LogWorkerImpl::backgroundFileWrite, pimpl_.get(), msg));
|
pimpl_->bg_->send(std::tr1::bind(&LogWorkerImpl::backgroundFileWrite, pimpl_.get(), msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LogWorker::fatal(g2::internal::FatalMessage fatal_message)
|
||||||
|
{
|
||||||
|
pimpl_->bg_->send(std::tr1::bind(&LogWorkerImpl::backgroundExitFatal, pimpl_.get(), fatal_message));
|
||||||
|
}
|
||||||
|
|
||||||
std::string LogWorker::logFileName() const
|
std::string LogWorker::logFileName() const
|
||||||
{
|
{
|
||||||
|
@ -22,7 +22,12 @@ public:
|
|||||||
virtual ~LogWorker();
|
virtual ~LogWorker();
|
||||||
|
|
||||||
/// pushes in background thread (asynchronously) input messages to log file
|
/// pushes in background thread (asynchronously) input messages to log file
|
||||||
void save(g2::internal::LogEntry);
|
void save(g2::internal::LogEntry entry);
|
||||||
|
|
||||||
|
/// Will push a fatal message on the queue, this is the last message to be processed
|
||||||
|
/// this way it's ensured that all existing entries were flushed before 'fatal'
|
||||||
|
/// Will abort the application!
|
||||||
|
void fatal(g2::internal::FatalMessage fatal_message);
|
||||||
|
|
||||||
/// basically only needed for unit-testing or specific log management post logging
|
/// basically only needed for unit-testing or specific log management post logging
|
||||||
std::string logFileName() const;
|
std::string logFileName() const;
|
||||||
@ -31,8 +36,8 @@ private:
|
|||||||
std::unique_ptr<LogWorkerImpl> pimpl_;
|
std::unique_ptr<LogWorkerImpl> pimpl_;
|
||||||
const std::string log_file_with_path_;
|
const std::string log_file_with_path_;
|
||||||
|
|
||||||
LogWorker(const LogWorker&) = delete; // no assignment, no copy
|
LogWorker(const LogWorker&); // c++11 feature not yet in vs2010 = delete;
|
||||||
LogWorker& operator=(const LogWorker&) = delete;
|
LogWorker& operator=(const LogWorker&); // c++11 feature not yet in vs2010 = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,13 +10,22 @@
|
|||||||
#include "logworker.h"
|
#include "logworker.h"
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
double pi_d = 3.1415926535897932384626433832795;
|
double pi_d = 3.1415926535897932384626433832795;
|
||||||
float pi_f = 3.1415926535897932384626433832795f;
|
float pi_f = 3.1415926535897932384626433832795f;
|
||||||
|
|
||||||
|
|
||||||
LogWorker logger(argv[0], "/tmp/");
|
LogWorker logger(argv[0], path_to_log_file);
|
||||||
g2::initializeLogging(&logger);
|
g2::initializeLogging(&logger);
|
||||||
|
|
||||||
std::cout << "****** A NUMBER of 'runtime exceptions' will be printed on this screen" << std::endl;
|
std::cout << "****** A NUMBER of 'runtime exceptions' will be printed on this screen" << std::endl;
|
||||||
@ -90,7 +99,7 @@ int main(int argc, char** argv)
|
|||||||
CHECK(1<2) << "SHOULD NOT SEE THIS MESSAGE";
|
CHECK(1<2) << "SHOULD NOT SEE THIS MESSAGE";
|
||||||
CHECK(1>2) << "Test to see if contract works: onetwothree: " << 123 << ". This should be inside an exception";
|
CHECK(1>2) << "Test to see if contract works: onetwothree: " << 123 << ". This should be inside an exception";
|
||||||
}
|
}
|
||||||
catch(std::exception& exc)
|
catch(...)
|
||||||
{
|
{
|
||||||
std::cout << "\n***** All good, the 'exception' was part of the example\n\n\n" << std::endl;
|
std::cout << "\n***** All good, the 'exception' was part of the example\n\n\n" << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -29,8 +29,8 @@ class shared_queue
|
|||||||
mutable std::mutex m_;
|
mutable std::mutex m_;
|
||||||
std::condition_variable data_cond_;
|
std::condition_variable data_cond_;
|
||||||
|
|
||||||
shared_queue& operator=(const shared_queue&) = delete;
|
shared_queue& operator=(const shared_queue&); // c++11 feature not yet in vs2010 = delete;
|
||||||
shared_queue(const shared_queue& other) = delete;
|
shared_queue(const shared_queue& other); // c++11 feature not yet in vs2010 = delete;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
shared_queue(){}
|
shared_queue(){}
|
||||||
|
@ -97,7 +97,7 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
oss.str("");
|
oss.str("");
|
||||||
oss << "Number of values rounted to milliseconds and put to [millisecond bucket] were dumped to file: " << g_measurement_bucket_dump << std::endl;
|
oss << "Number of values rounted to milliseconds and put to [millisecond bucket] were dumped to file: " << g_measurement_bucket_dump << std::endl;
|
||||||
oss << "Format: bucket_of_ms, number_of_values_in_bucket";
|
oss << "Format: bucket_of_ms, number_of_values_in_bucket\n\n" << std::endl;
|
||||||
std::cout << oss.str() << std::endl;
|
std::cout << oss.str() << std::endl;
|
||||||
|
|
||||||
for(auto iter = value_amounts.begin(); iter != value_amounts.end(); ++iter)
|
for(auto iter = value_amounts.begin(); iter != value_amounts.end(); ++iter)
|
||||||
|
@ -40,8 +40,6 @@ int main(int argc, char** argv)
|
|||||||
google::InitGoogleLogging(argv[0]);
|
google::InitGoogleLogging(argv[0]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
auto start_time = std::chrono::steady_clock::now();
|
auto start_time = std::chrono::steady_clock::now();
|
||||||
doLogWrites(title);
|
doLogWrites(title);
|
||||||
auto application_end_time = std::chrono::steady_clock::now();
|
auto application_end_time = std::chrono::steady_clock::now();
|
||||||
|
@ -66,6 +66,7 @@ bool writeTextToFile(const std::string& filename, const std::string& msg, const
|
|||||||
std::cerr << ss_error.str().c_str() << std::endl << std::flush;
|
std::cerr << ss_error.str().c_str() << std::endl << std::flush;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
out << msg;
|
out << msg;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
const int k_wait_time = 5; // 5s wait between LOG/CHECK FATAL till we say it's too long time
|
||||||
|
|
||||||
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);
|
std::string content(total_text);
|
||||||
@ -173,6 +175,7 @@ TEST(LogTest, LOGF__FATAL)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
LOGF(FATAL, "This message should throw %d",0);
|
LOGF(FATAL, "This message should throw %d",0);
|
||||||
|
sleep(k_wait_time);
|
||||||
}
|
}
|
||||||
catch (std::exception const &e)
|
catch (std::exception const &e)
|
||||||
{
|
{
|
||||||
@ -200,6 +203,7 @@ TEST(LogTest, LOG_FATAL)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
LOG(FATAL) << "This message should throw";
|
LOG(FATAL) << "This message should throw";
|
||||||
|
sleep(k_wait_time);
|
||||||
}
|
}
|
||||||
catch (std::exception const &e)
|
catch (std::exception const &e)
|
||||||
{
|
{
|
||||||
@ -227,6 +231,7 @@ TEST(LogTest, LOGF_IF__FATAL)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
LOGF_IF(FATAL, (2<3), "This message%sshould throw"," ");
|
LOGF_IF(FATAL, (2<3), "This message%sshould throw"," ");
|
||||||
|
sleep(k_wait_time);
|
||||||
}
|
}
|
||||||
catch (std::exception const &e)
|
catch (std::exception const &e)
|
||||||
{
|
{
|
||||||
@ -255,6 +260,7 @@ TEST(LogTest, LOG_IF__FATAL)
|
|||||||
{
|
{
|
||||||
LOG_IF(WARNING, (0 != t_info.compare(t_info))) << "This message should NOT be written";
|
LOG_IF(WARNING, (0 != t_info.compare(t_info))) << "This message should NOT be written";
|
||||||
LOG_IF(FATAL, (0 != t_info.compare(t_info2))) << "This message should throw";
|
LOG_IF(FATAL, (0 != t_info.compare(t_info2))) << "This message should throw";
|
||||||
|
sleep(k_wait_time);
|
||||||
}
|
}
|
||||||
catch (std::exception const &e)
|
catch (std::exception const &e)
|
||||||
{
|
{
|
||||||
@ -326,6 +332,7 @@ TEST(CHECK_F_Test, CHECK_F__thisWILL_PrintErrorMsg)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
CHECK_F(1 >= 2, msg.c_str(), arg1.c_str(), arg2.c_str());
|
CHECK_F(1 >= 2, msg.c_str(), arg1.c_str(), arg2.c_str());
|
||||||
|
sleep(k_wait_time);
|
||||||
}
|
}
|
||||||
catch (std::exception const &e)
|
catch (std::exception const &e)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user