Line data Source code
1 : // Copyright (c) 2013-2022 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/snaplogger
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 : #pragma once
20 :
21 : /** \file
22 : * \brief Handle the message generator.
23 : *
24 : * This file declares the base message class which is derived from an
25 : * std::stringstram. This allows you to use our logger with `<<`
26 : * to send anything that the `<<` operator understands to the logs.
27 : */
28 :
29 :
30 : // self
31 : //
32 : #include "snaplogger/component.h"
33 : #include "snaplogger/environment.h"
34 : #include "snaplogger/severity.h"
35 :
36 :
37 : // libexcept
38 : //
39 : #include <libexcept/exception.h>
40 :
41 :
42 : // snapdev
43 : //
44 : #include <snapdev/join_strings.h>
45 :
46 :
47 : // C++
48 : //
49 : #include <sstream>
50 : #include <streambuf>
51 :
52 :
53 : // C
54 : //
55 : #include <sys/time.h>
56 :
57 :
58 :
59 : namespace snaplogger
60 : {
61 :
62 :
63 : class logger;
64 :
65 :
66 :
67 152757 : class null_buffer
68 : : public std::streambuf
69 : {
70 : public:
71 : typedef std::unique_ptr<null_buffer> pointer_t;
72 :
73 : virtual int overflow(int c) override;
74 : };
75 :
76 :
77 : enum class system_field_t
78 : {
79 : SYSTEM_FIELD_UNDEFINED = -1, // used for still undefined system fields
80 :
81 : SYSTEM_FIELD_MESSAGE,
82 : SYSTEM_FIELD_TIMESTAMP,
83 : SYSTEM_FIELD_SEVERITY,
84 : SYSTEM_FIELD_FILENAME,
85 : SYSTEM_FIELD_FUNCTION_NAME,
86 : SYSTEM_FIELD_LINE,
87 :
88 : SYSTEM_FIELD_max
89 : };
90 :
91 :
92 : typedef std::map<std::string, std::string> field_map_t;
93 :
94 :
95 : // the message class is final because the destructor does tricks which
96 : // would not work right if derived further
97 : //
98 : // also we do not offer a shared pointer because we expect the message
99 : // object to be created and immediately destroyed from the stack
100 : //
101 : class message final
102 : : public std::basic_stringstream<char>
103 : {
104 : public:
105 : typedef std::shared_ptr<message> pointer_t;
106 :
107 : message(
108 : severity_t sev = default_severity()
109 : , char const * file = nullptr
110 : , char const * func = nullptr
111 : , int line = -1);
112 : message(std::basic_stringstream<char> const & m, message const & msg);
113 : message(message const & rhs) = delete;
114 : virtual ~message();
115 :
116 : message & operator = (message const & rhs) = delete;
117 :
118 : static severity_t default_severity();
119 :
120 : void set_severity(severity_t severity);
121 : void set_filename(std::string const & filename);
122 : void set_function(std::string const & funcname);
123 : void set_line(int line);
124 : void set_recursive_message(bool state) const;
125 : void set_precise_time();
126 : void set_timestamp(timespec const & timestamp);
127 : bool can_add_component(component::pointer_t c) const;
128 : void add_component(component::pointer_t c);
129 : void add_field(std::string const & name, std::string const & value);
130 :
131 : std::shared_ptr<logger> get_logger() const;
132 : severity_t get_severity() const;
133 : timespec const & get_timestamp() const;
134 : std::string const & get_filename() const;
135 : std::string const & get_function() const;
136 : int get_line() const;
137 : bool get_recursive_message() const;
138 : bool has_component(component::pointer_t c) const;
139 : component::set_t const & get_components() const;
140 : environment::pointer_t get_environment() const;
141 : std::string get_message() const;
142 : static char const * get_system_field_name(system_field_t field);
143 : static system_field_t get_system_field_from_name(std::string const & name);
144 : std::string get_field(std::string const & name) const;
145 : field_map_t get_fields() const;
146 :
147 : private:
148 : std::shared_ptr<logger> f_logger = std::shared_ptr<logger>(); // make sure it does not go away under our feet
149 : timespec f_timestamp = timespec();
150 : severity_t f_severity = severity_t::SEVERITY_INFORMATION;
151 : std::string f_filename = std::string();
152 : std::string f_funcname = std::string();
153 : int f_line = 0;
154 : mutable bool f_recursive_message = false;
155 : environment::pointer_t f_environment = environment::pointer_t();
156 : component::set_t f_components = component::set_t();
157 : field_map_t f_fields = field_map_t();
158 : null_buffer::pointer_t f_null = null_buffer::pointer_t();
159 : std::streambuf * f_saved_buffer = nullptr;
160 : bool f_copy = false;
161 : };
162 :
163 :
164 : template<typename CharT, typename Traits>
165 : inline std::basic_ostream<CharT, Traits> &
166 14 : operator << (std::basic_ostream<CharT, Traits> & os, section_ptr sec)
167 : {
168 14 : message * m(dynamic_cast<message *>(&os));
169 14 : if(m == nullptr)
170 : {
171 7 : os << "(section:"
172 7 : << sec.f_component->get_name()
173 14 : << ")";
174 : }
175 : else
176 : {
177 7 : m->add_component(sec.f_component);
178 : }
179 14 : return os;
180 : }
181 :
182 :
183 : template<typename CharT, typename Traits>
184 : inline std::basic_ostream<CharT, Traits> &
185 5 : secure(std::basic_ostream<CharT, Traits> & os)
186 : {
187 5 : message * m(dynamic_cast<message *>(&os));
188 5 : if(m == nullptr)
189 : {
190 1 : os << "(section:secure)";
191 : }
192 : else
193 : {
194 4 : m->add_component(g_secure_component);
195 : }
196 5 : return os;
197 : }
198 :
199 :
200 : template<typename CharT, typename Traits>
201 : inline std::basic_ostream<CharT, Traits> &
202 1 : precise_time(std::basic_ostream<CharT, Traits> & os)
203 : {
204 1 : message * m(dynamic_cast<message *>(&os));
205 1 : if(m != nullptr)
206 : {
207 1 : m->set_precise_time();
208 : }
209 1 : return os;
210 : }
211 :
212 :
213 :
214 3 : struct field_t
215 : {
216 : std::string f_name;
217 : std::string f_value;
218 : };
219 :
220 3 : inline field_t field(std::string const & name, std::string const & value)
221 : {
222 3 : return { name, value };
223 : }
224 :
225 : template<typename CharT, typename Traits>
226 : inline std::basic_ostream<CharT, Traits> &
227 3 : operator << (std::basic_ostream<CharT, Traits> & os, field_t const & f)
228 : {
229 3 : message * m(dynamic_cast<message *>(&os));
230 3 : if(m != nullptr)
231 : {
232 3 : m->add_field(f.f_name, f.f_value);
233 : }
234 3 : return os;
235 : }
236 :
237 :
238 :
239 :
240 :
241 : message::pointer_t create_message(
242 : severity_t sev = ::snaplogger::message::default_severity()
243 : , char const * file = nullptr
244 : , char const * func = nullptr
245 : , int line = -1);
246 :
247 : void send_message(std::basic_ostream<char> & msg);
248 :
249 : void send_stack_trace(libexcept::exception_base_t const & e);
250 :
251 :
252 : // TODO: with C++20, change the __FILE__, __LINE__, __func__ with
253 : // std::location::current()
254 : //
255 : #define SNAP_LOG_FATAL ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_FATAL, __FILE__, __func__, __LINE__))
256 : #define SNAP_LOG_EMERG ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_EMERGENCY, __FILE__, __func__, __LINE__))
257 : #define SNAP_LOG_EMERGENCY ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_EMERGENCY, __FILE__, __func__, __LINE__))
258 : #define SNAP_LOG_ALERT ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_ALERT, __FILE__, __func__, __LINE__))
259 : #define SNAP_LOG_CRIT ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_CRITICAL, __FILE__, __func__, __LINE__))
260 : #define SNAP_LOG_CRITICAL ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_CRITICAL, __FILE__, __func__, __LINE__))
261 : #define SNAP_LOG_EXCEPTION ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_EXCEPTION, __FILE__, __func__, __LINE__))
262 : #define SNAP_LOG_SEVERE ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_SEVERE, __FILE__, __func__, __LINE__))
263 : #define SNAP_LOG_ERR ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_ERROR, __FILE__, __func__, __LINE__))
264 : #define SNAP_LOG_ERROR ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_ERROR, __FILE__, __func__, __LINE__))
265 : #define SNAP_LOG_RECOVERABLE_ERROR ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_RECOVERABLE_ERROR, __FILE__, __func__, __LINE__))
266 : #define SNAP_LOG_MAJOR ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_MAJOR, __FILE__, __func__, __LINE__))
267 : #define SNAP_LOG_WARN ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_WARNING, __FILE__, __func__, __LINE__))
268 : #define SNAP_LOG_WARNING ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_WARNING, __FILE__, __func__, __LINE__))
269 : #define SNAP_LOG_DEPRECATED ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_DEPRECATED, __FILE__, __func__, __LINE__))
270 : #define SNAP_LOG_TODO ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_TODO, __FILE__, __func__, __LINE__))
271 : #define SNAP_LOG_MINOR ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_MINOR, __FILE__, __func__, __LINE__))
272 : #define SNAP_LOG_IMPORTANT ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_IMPORTANT, __FILE__, __func__, __LINE__))
273 : #define SNAP_LOG_INFO ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_INFORMATION, __FILE__, __func__, __LINE__))
274 : #define SNAP_LOG_INFORMATION ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_INFORMATION, __FILE__, __func__, __LINE__))
275 : #define SNAP_LOG_CONFIGURATION ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_CONFIGURATION, __FILE__, __func__, __LINE__))
276 : #define SNAP_LOG_CONFIG ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_CONFIGURATION, __FILE__, __func__, __LINE__))
277 : #define SNAP_LOG_VERBOSE ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_VERBOSE, __FILE__, __func__, __LINE__))
278 : #define SNAP_LOG_UNIMPORTANT ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_UNIMPORTANT, __FILE__, __func__, __LINE__))
279 : #define SNAP_LOG_NOTICE ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_NOTICE, __FILE__, __func__, __LINE__))
280 : #define SNAP_LOG_DEBUG ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_DEBUG, __FILE__, __func__, __LINE__))
281 : #define SNAP_LOG_NOISY ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_NOISY, __FILE__, __func__, __LINE__))
282 : #define SNAP_LOG_TRACE ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::severity_t::SEVERITY_TRACE, __FILE__, __func__, __LINE__))
283 :
284 : #define SNAP_LOG_DEFAULT ::snaplogger::send_message(((*::snaplogger::create_message(::snaplogger::message::default_severity(), __FILE__, __func__, __LINE__))
285 :
286 : #define SNAP_LOG_FIELD(name, value) ::snaplogger::field((name), (value))
287 :
288 : // The (( are in the opening macros
289 : //
290 : #define SNAP_LOG_SEND ""))
291 : #define SNAP_LOG_SEND_SECURELY ::snaplogger::secure))
292 : #define SNAP_LOG_SEND_WITH_STACK_TRACE(e) \
293 : "")); ::snaplogger::send_stack_trace(e)
294 :
295 :
296 :
297 : } // snaplogger namespace
298 :
299 :
300 :
301 : template<typename CharT, typename Traits>
302 : inline std::basic_ostream<CharT, Traits> &
303 1 : operator << (std::basic_ostream<CharT, Traits> & os, std::stringstream const & ss)
304 : {
305 1 : return os << ss.str();
306 : }
307 :
308 :
309 :
310 : template<typename CharT, typename Traits>
311 : inline std::basic_ostream<CharT, Traits> &
312 1 : operator << (std::basic_ostream<CharT, Traits> & os, std::exception const & e)
313 : {
314 1 : snaplogger::message * m(dynamic_cast<snaplogger::message *>(&os));
315 1 : if(m != nullptr)
316 : {
317 1 : m->add_field("exception_message", e.what());
318 :
319 1 : libexcept::exception_base_t const * b(dynamic_cast<libexcept::exception_base_t const *>(&e));
320 1 : if(b != nullptr)
321 : {
322 1 : m->add_field("exception_stacktrace", snapdev::join_strings(b->get_stack_trace(), "\n") + "\n");
323 :
324 1 : libexcept::parameter_t const & params(b->get_parameters());
325 2 : for(auto const & p : params)
326 : {
327 1 : m->add_field("exception_" + p.first, p.second);
328 : }
329 : }
330 : }
331 :
332 1 : return os << e.what();
333 : }
334 :
335 :
336 : // vim: ts=4 sw=4 et
|