Ed Tanous | 50c50c2 | 2017-05-12 16:58:06 -0700 | [diff] [blame] | 1 | /** ========================================================================== |
| 2 | * 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes |
| 3 | * with no warranties. This code is yours to share, use and modify with no |
| 4 | * strings attached and no restrictions or obligations. |
| 5 | * |
| 6 | * For more information see g3log/LICENSE or refer refer to http://unlicense.org |
| 7 | * ============================================================================*/ |
| 8 | |
| 9 | #include "g3log/logcapture.hpp" |
| 10 | #include "g3log/crashhandler.hpp" |
| 11 | |
| 12 | // For Windows we need force a thread_local install per thread of three |
| 13 | // signals that must have a signal handler instealled per thread-basis |
| 14 | // It is really a royal pain. Seriously Microsoft? Seriously? |
| 15 | #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) |
| 16 | #define SIGNAL_HANDLER_VERIFY() g3::installSignalHandlerForThread() |
| 17 | #else |
| 18 | // Does nothing --- enforces that semicolon must be written |
| 19 | #define SIGNAL_HANDLER_VERIFY() do {} while(0) |
| 20 | #endif |
| 21 | |
| 22 | |
| 23 | |
| 24 | /** logCapture is a simple struct for capturing log/fatal entries. At destruction the |
| 25 | * captured message is forwarded to background worker. |
| 26 | * As a safety precaution: No memory allocated here will be moved into the background |
| 27 | * worker in case of dynamic loaded library reasons instead the arguments are copied |
| 28 | * inside of g3log.cpp::saveMessage*/ |
| 29 | LogCapture::~LogCapture() { |
| 30 | using namespace g3::internal; |
| 31 | SIGNAL_HANDLER_VERIFY(); |
| 32 | saveMessage(_stream.str().c_str(), _file, _line, _function, _level, _expression, _fatal_signal, _stack_trace.c_str()); |
| 33 | } |
| 34 | |
| 35 | |
| 36 | /// Called from crash handler when a fatal signal has occurred (SIGSEGV etc) |
| 37 | LogCapture::LogCapture(const LEVELS &level, g3::SignalType fatal_signal, const char *dump) : LogCapture("", 0, "", level, "", fatal_signal, dump) { |
| 38 | } |
| 39 | |
| 40 | /** |
| 41 | * @file, line, function are given in g3log.hpp from macros |
| 42 | * @level INFO/DEBUG/WARNING/FATAL |
| 43 | * @expression for CHECK calls |
| 44 | * @fatal_signal for failed CHECK:SIGABRT or fatal signal caught in the signal handler |
| 45 | */ |
| 46 | LogCapture::LogCapture(const char *file, const int line, const char *function, const LEVELS &level, |
| 47 | const char *expression, g3::SignalType fatal_signal, const char *dump) |
| 48 | : _file(file), _line(line), _function(function), _level(level), _expression(expression), _fatal_signal(fatal_signal) { |
| 49 | |
| 50 | if (g3::internal::wasFatal(level)) { |
| 51 | _stack_trace = {"\n*******\tSTACKDUMP *******\n"}; |
| 52 | _stack_trace.append(g3::internal::stackdump(dump)); |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | |
| 57 | |
| 58 | /** |
| 59 | * capturef, used for "printf" like API in CHECKF, LOGF, LOGF_IF |
| 60 | * See also for the attribute formatting ref: http://www.codemaestro.com/reviews/18 |
| 61 | */ |
| 62 | void LogCapture::capturef(const char *printf_like_message, ...) { |
| 63 | static const int kMaxMessageSize = 2048; |
| 64 | static const std::string kTruncatedWarningText = "[...truncated...]"; |
| 65 | char finished_message[kMaxMessageSize]; |
| 66 | va_list arglist; |
| 67 | va_start(arglist, printf_like_message); |
| 68 | |
| 69 | #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) && !defined(__GNUC__)) |
| 70 | const int nbrcharacters = vsnprintf_s(finished_message, _countof(finished_message), _TRUNCATE, printf_like_message, arglist); |
| 71 | #else |
| 72 | const int nbrcharacters = vsnprintf(finished_message, sizeof (finished_message), printf_like_message, arglist); |
| 73 | #endif |
| 74 | va_end(arglist); |
| 75 | |
| 76 | if (nbrcharacters <= 0) { |
| 77 | stream() << "\n\tERROR LOG MSG NOTIFICATION: Failure to parse successfully the message"; |
| 78 | stream() << '"' << printf_like_message << '"' << std::endl; |
| 79 | } else if (nbrcharacters > kMaxMessageSize) { |
| 80 | stream() << finished_message << kTruncatedWarningText; |
| 81 | } else { |
| 82 | stream() << finished_message; |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | |