blob: c5dc4331a4baf4aa1fbc3cb3cb31cb32164698b6 [file] [log] [blame]
Ed Tanous50c50c22017-05-12 16:58:06 -07001/** ==========================================================================
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*/
29LogCapture::~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)
37LogCapture::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 */
46LogCapture::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*/
62void 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