blob: 038b5f7a86a4656ba91280dc11a7c08ef281abbd [file] [log] [blame]
Ed Tanous50c50c22017-05-12 16:58:06 -07001/** ==========================================================================
2* 2012 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/logmessage.hpp"
10#include "g3log/crashhandler.hpp"
11#include "g3log/time.hpp"
12#include <mutex>
13
14namespace {
15 std::string splitFileName(const std::string& str) {
16 size_t found;
17 found = str.find_last_of("(/\\");
18 return str.substr(found + 1);
19 }
20} // anonymous
21
22
23
24namespace g3 {
25
26
27 // helper for setting the normal log details in an entry
28 std::string LogDetailsToString(const LogMessage& msg) {
29 std::string out;
30 out.append(msg.timestamp() + "\t"
31 + msg.level() + " [" + msg.file() + "->" + msg.function() + ":" + msg.line() + "]\t");
32 return out;
33 }
34
35
36 // helper for normal
37 std::string normalToString(const LogMessage& msg) {
38 auto out = LogDetailsToString(msg);
39 out.append(msg.message() + '\n');
40 return out;
41 }
42
43 // helper for fatal signal
44 std::string fatalSignalToString(const LogMessage& msg) {
45 std::string out; // clear any previous text and formatting
46 out.append(msg.timestamp()
47 + "\n\n***** FATAL SIGNAL RECEIVED ******* \n"
48 + msg.message() + '\n');
49 return out;
50 }
51
52
53 // helper for fatal exception (windows only)
54 std::string fatalExceptionToString(const LogMessage& msg) {
55 std::string out; // clear any previous text and formatting
56 out.append(msg.timestamp()
57 + "\n\n***** FATAL EXCEPTION RECEIVED ******* \n"
58 + msg.message() + '\n');
59 return out;
60 }
61
62
63 // helper for fatal LOG
64 std::string fatalLogToString(const LogMessage& msg) {
65 auto out = LogDetailsToString(msg);
66 static const std::string fatalExitReason = {"EXIT trigger caused by LOG(FATAL) entry: "};
67 out.append("\n\t*******\t " + fatalExitReason + "\n\t" + '"' + msg.message() + '"');
68 return out;
69 }
70
71 // helper for fatal CHECK
72 std::string fatalCheckToString(const LogMessage& msg) {
73 auto out = LogDetailsToString(msg);
74 static const std::string contractExitReason = {"EXIT trigger caused by broken Contract:"};
75 out.append("\n\t*******\t " + contractExitReason + " CHECK(" + msg.expression() + ")\n\t"
76 + '"' + msg. message() + '"');
77 return out;
78 }
79
80
81 // Format the log message according to it's type
82 std::string LogMessage::toString() const {
83 if (false == wasFatal()) {
84 return normalToString(*this);
85 }
86
87 const auto level_value = _level.value;
88 if (internal::FATAL_SIGNAL.value == _level.value) {
89 return fatalSignalToString(*this);
90 }
91
92 if (internal::FATAL_EXCEPTION.value == _level.value) {
93 return fatalExceptionToString(*this);
94 }
95
96 if (FATAL.value == _level.value) {
97 return fatalLogToString(*this);
98 }
99
100 if (internal::CONTRACT.value == level_value) {
101 return fatalCheckToString(*this);
102 }
103
104 // What? Did we hit a custom made level?
105 auto out = LogDetailsToString(*this);
106 static const std::string errorUnknown = {"UNKNOWN or Custom made Log Message Type"};
107 out.append("\t*******" + errorUnknown + "\n\t" + message() + '\n');
108 return out;
109 }
110
111
112
113 std::string LogMessage::timestamp(const std::string& time_look) const {
114 return g3::localtime_formatted(_timestamp, time_look);
115 }
116
117
118// By copy, not by reference. See this explanation for details:
119// http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom
120 LogMessage& LogMessage::operator=(LogMessage other) {
121 swap(*this, other);
122 return *this;
123 }
124
125
126 LogMessage::LogMessage(const std::string& file, const int line,
127 const std::string& function, const LEVELS& level)
128 : _call_thread_id(std::this_thread::get_id())
129 , _file(splitFileName(file))
130 , _file_path(file)
131 , _line(line)
132 , _function(function)
133 , _level(level)
134 {
135 g3::timespec_get(&_timestamp/*, TIME_UTC*/);
136 // Another possibility could be to Falling back to clock_gettime as TIME_UTC
137 // is not recognized by travis CI.
138 // i.e. clock_gettime(CLOCK_REALTIME, &_timestamp);
139 }
140
141
142 LogMessage::LogMessage(const std::string& fatalOsSignalCrashMessage)
143 : LogMessage( {""}, 0, {""}, internal::FATAL_SIGNAL) {
144 _message.append(fatalOsSignalCrashMessage);
145 }
146
147 LogMessage::LogMessage(const LogMessage& other)
148 : _timestamp(other._timestamp)
149 , _call_thread_id(other._call_thread_id)
150 , _file(other._file)
151 , _file_path(other._file_path)
152 , _line(other._line)
153 , _function(other._function)
154 , _level(other._level)
155 , _expression(other._expression)
156 , _message(other._message) {
157 }
158
159 LogMessage::LogMessage(LogMessage &&other)
160 : _timestamp(other._timestamp)
161 , _call_thread_id(other._call_thread_id)
162 , _file(std::move(other._file))
163 , _file_path(std::move(other._file_path))
164 , _line(other._line)
165 , _function(std::move(other._function))
166 , _level(other._level)
167 , _expression(std::move(other._expression))
168 , _message(std::move(other._message)) {
169 }
170
171
172
173 std::string LogMessage::threadID() const {
174 std::ostringstream oss;
175 oss << _call_thread_id;
176 return oss.str();
177 }
178
179
180
181 FatalMessage::FatalMessage(const LogMessage& details, g3::SignalType signal_id)
182 : LogMessage(details), _signal_id(signal_id) { }
183
184
185
186 FatalMessage::FatalMessage(const FatalMessage& other)
187 : LogMessage(other), _signal_id(other._signal_id) {}
188
189
190 LogMessage FatalMessage::copyToLogMessage() const {
191 return LogMessage(*this);
192 }
193
194 std::string FatalMessage::reason() const {
195 return internal::exitReasonName(_level, _signal_id);
196 }
197
198
199} // g3