Line data Source code
1 : // Copyright (c) 2006-2025 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 3 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
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 :
19 : // self
20 : //
21 : #include "catch_main.h"
22 :
23 :
24 : // snaplogger
25 : //
26 : #include <snaplogger/buffer_appender.h>
27 : #include <snaplogger/exception.h>
28 : #include <snaplogger/format.h>
29 : #include <snaplogger/logger.h>
30 : #include <snaplogger/map_diagnostic.h>
31 : #include <snaplogger/message.h>
32 : #include <snaplogger/severity.h>
33 : #include <snaplogger/version.h>
34 :
35 :
36 : // C
37 : //
38 : #include <unistd.h>
39 : #include <netdb.h>
40 : #include <sys/param.h>
41 :
42 :
43 :
44 :
45 :
46 1 : CATCH_TEST_CASE("variable_param", "[variable][param][error]")
47 : {
48 1 : CATCH_START_SECTION("variable: Param Name is Mandatory")
49 : {
50 6 : CATCH_REQUIRE_THROWS_MATCHES(
51 : new snaplogger::param(std::string())
52 : , snaplogger::invalid_parameter
53 : , Catch::Matchers::ExceptionMessage(
54 : "logger_error: a parameter must have a non-empty name."));
55 : }
56 1 : CATCH_END_SECTION()
57 1 : }
58 :
59 :
60 :
61 9 : CATCH_TEST_CASE("system_variable", "[variable][param]")
62 : {
63 9 : CATCH_START_SECTION("variable: get_type() to use padding as integer or string (hostname)")
64 : {
65 5 : snaplogger::set_diagnostic(snaplogger::DIAG_KEY_PROGNAME, "message-logging");
66 :
67 1 : snaplogger::logger::pointer_t l(snaplogger::logger::get_instance());
68 1 : snaplogger::buffer_appender::pointer_t buffer(std::make_shared<snaplogger::buffer_appender>("test-buffer"));
69 :
70 1 : char const * cargv[] =
71 : {
72 : "/usr/bin/daemon",
73 : nullptr
74 : };
75 1 : int const argc(sizeof(cargv) / sizeof(cargv[0]) - 1);
76 1 : char ** argv = const_cast<char **>(cargv);
77 :
78 1 : advgetopt::options_environment environment_options;
79 1 : environment_options.f_project_name = "test-logger";
80 1 : environment_options.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
81 1 : advgetopt::getopt opts(environment_options);
82 1 : opts.parse_program_name(argv);
83 1 : opts.parse_arguments(argc, argv, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
84 :
85 1 : buffer->set_config(opts);
86 :
87 1 : snaplogger::format::pointer_t f(std::make_shared<snaplogger::format>("${hostname:padding=3:align=right:min_width=30} ${message}"));
88 1 : buffer->set_format(f);
89 :
90 1 : l->add_appender(buffer);
91 :
92 1 : char host[HOST_NAME_MAX + 2 + 30];
93 1 : CATCH_REQUIRE(gethostname(host, HOST_NAME_MAX + 1) == 0);
94 1 : host[HOST_NAME_MAX + 1] = '\0';
95 3 : std::string aligned(host);
96 24 : while(aligned.length() < 30)
97 : {
98 23 : aligned = "3" + aligned;
99 : }
100 :
101 2 : SNAP_LOG_ERROR << "Check the param::get_type()" << SNAP_LOG_SEND;
102 1 : CATCH_REQUIRE(buffer->str() == aligned + " Check the param::get_type()\n");
103 :
104 1 : buffer->clear();
105 :
106 1 : f = std::make_shared<snaplogger::format>("${hostname:padding=\"t\":align=center:min_width=30} ${message}");
107 1 : buffer->set_format(f);
108 :
109 1 : aligned = host;
110 1 : std::string::size_type const low((30 - aligned.length()) / 2 + aligned.length());
111 12 : while(aligned.length() < low)
112 : {
113 11 : aligned = "t" + aligned;
114 : }
115 13 : while(aligned.length() < 30)
116 : {
117 12 : aligned = aligned + "t";
118 : }
119 :
120 2 : SNAP_LOG_ERROR << "Try again with a string" << SNAP_LOG_SEND;
121 1 : CATCH_REQUIRE(buffer->str() == aligned + " Try again with a string\n");
122 :
123 1 : buffer->clear();
124 :
125 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"t\":align=center:max_width=30}");
126 1 : buffer->set_format(f);
127 :
128 2 : SNAP_LOG_ERROR << "This message will have a maximum width of 30 chars" << SNAP_LOG_SEND;
129 3 : CATCH_REQUIRE(buffer->str() == std::string(host) + " ge will have a maximum width o\n");
130 :
131 1 : buffer->clear();
132 :
133 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"t\":align=right:max_width=25}");
134 1 : buffer->set_format(f);
135 :
136 2 : SNAP_LOG_ERROR << "This message will have a maximum width of 25 chars" << SNAP_LOG_SEND;
137 3 : CATCH_REQUIRE(buffer->str() == std::string(host) + " maximum width of 25 chars\n");
138 :
139 1 : buffer->clear();
140 :
141 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"t\":align=center:min_width=25}");
142 1 : buffer->set_format(f);
143 :
144 2 : SNAP_LOG_ERROR << "minimum width 25" << SNAP_LOG_SEND;
145 3 : CATCH_REQUIRE(buffer->str() == std::string(host) + " ttttminimum width 25ttttt\n");
146 :
147 1 : buffer->clear();
148 :
149 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"t\":align=left:min_width=25}");
150 1 : buffer->set_format(f);
151 :
152 2 : SNAP_LOG_ERROR << "minimum width 25" << SNAP_LOG_SEND;
153 3 : CATCH_REQUIRE(buffer->str() == std::string(host) + " minimum width 25ttttttttt\n");
154 :
155 1 : buffer->clear();
156 :
157 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"t\":align=left:exact_width=25}");
158 1 : buffer->set_format(f);
159 :
160 2 : SNAP_LOG_ERROR << "First we get this message cut to the specified width." << SNAP_LOG_SEND;
161 3 : CATCH_REQUIRE(buffer->str() == std::string(host) + " First we get this message\n");
162 :
163 1 : buffer->clear();
164 :
165 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"t\":align=center:exact_width=25}");
166 1 : buffer->set_format(f);
167 :
168 2 : SNAP_LOG_ERROR << "First we get this message cut to the specified width." << SNAP_LOG_SEND;
169 3 : CATCH_REQUIRE(buffer->str() == std::string(host) + " his message cut to the sp\n");
170 :
171 1 : buffer->clear();
172 :
173 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"t\":align=right:exact_width=25}");
174 1 : buffer->set_format(f);
175 :
176 2 : SNAP_LOG_ERROR << "First we get this message cut to the specified width." << SNAP_LOG_SEND;
177 3 : CATCH_REQUIRE(buffer->str() == std::string(host) + " t to the specified width.\n");
178 :
179 1 : buffer->clear();
180 :
181 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"x\":align=left:exact_width=25}");
182 1 : buffer->set_format(f);
183 :
184 2 : SNAP_LOG_ERROR << "Small Message" << SNAP_LOG_SEND;
185 3 : CATCH_REQUIRE(buffer->str() == std::string(host) + " Small Messagexxxxxxxxxxxx\n");
186 :
187 1 : buffer->clear();
188 :
189 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"x\":align=center:exact_width=25}");
190 1 : buffer->set_format(f);
191 :
192 2 : SNAP_LOG_ERROR << "Small Message" << SNAP_LOG_SEND;
193 3 : CATCH_REQUIRE(buffer->str() == std::string(host) + " xxxxxxSmall Messagexxxxxx\n");
194 :
195 1 : buffer->clear();
196 :
197 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"x\":align=center:exact_width=25}");
198 1 : buffer->set_format(f);
199 :
200 2 : SNAP_LOG_ERROR << "Small Message (even)" << SNAP_LOG_SEND;
201 3 : CATCH_REQUIRE(buffer->str() == std::string(host) + " xxSmall Message (even)xxx\n");
202 :
203 1 : buffer->clear();
204 :
205 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"x\":align=right:exact_width=25}");
206 1 : buffer->set_format(f);
207 :
208 2 : SNAP_LOG_ERROR << "Small Message" << SNAP_LOG_SEND;
209 3 : CATCH_REQUIRE(buffer->str() == std::string(host) + " xxxxxxxxxxxxSmall Message\n");
210 :
211 1 : buffer->clear();
212 :
213 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:prepend=\"(P) \":padding=\"z\":align=right:exact_width=25}");
214 1 : buffer->set_format(f);
215 :
216 2 : SNAP_LOG_ERROR << "Small Message" << SNAP_LOG_SEND;
217 3 : CATCH_REQUIRE(buffer->str() == std::string(host) + " zzzzzzzz(P) Small Message\n");
218 :
219 1 : buffer->clear();
220 :
221 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:append=\" (A)\":padding=\"z\":align=right:exact_width=25}");
222 1 : buffer->set_format(f);
223 :
224 2 : SNAP_LOG_ERROR << "Small Message" << SNAP_LOG_SEND;
225 3 : CATCH_REQUIRE(buffer->str() == std::string(host) + " zzzzzzzzSmall Message (A)\n");
226 :
227 1 : buffer->clear();
228 :
229 1 : f = std::make_shared<snaplogger::format>("${hostname:padding=\"q\":align=101:min_width=30} ${message}");
230 1 : buffer->set_format(f);
231 :
232 1 : snaplogger::message::pointer_t msg(std::make_shared<snaplogger::message>
233 1 : (::snaplogger::severity_t::SEVERITY_ERROR));
234 1 : *msg << "The align=101 parameter is the wrong type";
235 3 : CATCH_REQUIRE_THROWS_MATCHES(
236 : l->log_message(*msg)
237 : , snaplogger::invalid_parameter
238 : , Catch::Matchers::ExceptionMessage(
239 : "logger_error: the ${...:align=<value>} parameter must be a valid string (not an integer)."));
240 :
241 : // this is important here because we want to make sure that the
242 : // `message` destructor works as expected (i.e. it does not call
243 : // std::terminate() because of the throw as the align=101 is
244 : // invalid)
245 : //
246 1 : msg.reset();
247 :
248 1 : buffer->clear();
249 :
250 1 : f = std::make_shared<snaplogger::format>("${hostname:padding=\"t\":align=justify:min_width=30} ${message}");
251 1 : buffer->set_format(f);
252 :
253 1 : msg = std::make_shared<snaplogger::message>
254 1 : (::snaplogger::severity_t::SEVERITY_ERROR);
255 1 : *msg << "Try align=\"justify\" which has to fail.";
256 3 : CATCH_REQUIRE_THROWS_MATCHES(
257 : l->log_message(*msg)
258 : , snaplogger::invalid_parameter
259 : , Catch::Matchers::ExceptionMessage(
260 : "logger_error: the ${...:align=left|center|right} was expected, got \"justify\"."));
261 :
262 1 : buffer->clear();
263 :
264 1 : f = std::make_shared<snaplogger::format>("${hostname:padding=\"q\":align=left:min_width=wide} ${message}");
265 1 : buffer->set_format(f);
266 :
267 1 : msg = std::make_shared<snaplogger::message>
268 1 : (::snaplogger::severity_t::SEVERITY_ERROR);
269 1 : *msg << "The min_width=wide parameter is the wrong type";
270 3 : CATCH_REQUIRE_THROWS_MATCHES(
271 : l->log_message(*msg)
272 : , snaplogger::invalid_parameter
273 : , Catch::Matchers::ExceptionMessage(
274 : "logger_error: the ${...:min_width=<value>} parameter must be a valid integer."));
275 :
276 : // this is important here because we want to make sure that the
277 : // `message` destructor works as expected (i.e. it does not call
278 : // std::terminate() because of the throw as the align=101 is
279 : // invalid)
280 : //
281 1 : msg.reset();
282 :
283 1 : buffer->clear();
284 :
285 1 : f = std::make_shared<snaplogger::format>("${hostname:padding=99:align=left:min_width=wide} ${message}");
286 1 : buffer->set_format(f);
287 :
288 1 : msg = std::make_shared<snaplogger::message>
289 1 : (::snaplogger::severity_t::SEVERITY_ERROR);
290 1 : *msg << "The padding=... accepts a number between 0 and 9 inclusive";
291 3 : CATCH_REQUIRE_THROWS_MATCHES(
292 : l->log_message(*msg)
293 : , snaplogger::invalid_parameter
294 : , Catch::Matchers::ExceptionMessage(
295 : "logger_error: the ${...:padding=<value>} when set to a number must be one digit ('0' to '9'), not \"99\"."));
296 :
297 : // this is important here because we want to make sure that the
298 : // `message` destructor works as expected (i.e. it does not call
299 : // std::terminate() because of the throw as the align=101 is
300 : // invalid)
301 : //
302 1 : msg.reset();
303 :
304 1 : buffer->clear();
305 :
306 1 : f = std::make_shared<snaplogger::format>("${hostname:padding='abc':align=left:min_width=wide} ${message}");
307 1 : buffer->set_format(f);
308 :
309 1 : msg = std::make_shared<snaplogger::message>
310 1 : (::snaplogger::severity_t::SEVERITY_ERROR);
311 1 : *msg << "The padding=... accepts one character";
312 3 : CATCH_REQUIRE_THROWS_MATCHES(
313 : l->log_message(*msg)
314 : , snaplogger::invalid_parameter
315 : , Catch::Matchers::ExceptionMessage(
316 : "logger_error: the ${...:padding=' '} must be exactly one character, not \"abc\"."));
317 :
318 : // this is important here because we want to make sure that the
319 : // `message` destructor works as expected (i.e. it does not call
320 : // std::terminate() because of the throw as the align=101 is
321 : // invalid)
322 : //
323 1 : msg.reset();
324 :
325 1 : l->reset();
326 1 : }
327 9 : CATCH_END_SECTION()
328 :
329 9 : CATCH_START_SECTION("variable: escape")
330 : {
331 5 : snaplogger::set_diagnostic(snaplogger::DIAG_KEY_PROGNAME, "escape");
332 :
333 1 : snaplogger::logger::pointer_t l(snaplogger::logger::get_instance());
334 1 : snaplogger::buffer_appender::pointer_t buffer(std::make_shared<snaplogger::buffer_appender>("test-buffer"));
335 :
336 1 : char const * cargv[] =
337 : {
338 : "/usr/bin/daemon",
339 : nullptr
340 : };
341 1 : int const argc(sizeof(cargv) / sizeof(cargv[0]) - 1);
342 1 : char ** argv = const_cast<char **>(cargv);
343 :
344 1 : advgetopt::options_environment environment_options;
345 1 : environment_options.f_project_name = "test-logger";
346 1 : environment_options.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
347 1 : advgetopt::getopt opts(environment_options);
348 1 : opts.parse_program_name(argv);
349 1 : opts.parse_arguments(argc, argv, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
350 :
351 1 : buffer->set_config(opts);
352 :
353 1 : snaplogger::format::pointer_t f(std::make_shared<snaplogger::format>("${hostname} ${message:escape}"));
354 1 : buffer->set_format(f);
355 :
356 1 : l->add_appender(buffer);
357 :
358 1 : char host[HOST_NAME_MAX + 2 + 30];
359 1 : CATCH_REQUIRE(gethostname(host, HOST_NAME_MAX + 1) == 0);
360 1 : host[HOST_NAME_MAX + 1] = '\0';
361 :
362 2 : SNAP_LOG_ERROR << "Default escape for newline (\n), carriage return (\r), and tab (\t)" << SNAP_LOG_SEND;
363 3 : CATCH_REQUIRE(buffer->str() == std::string(host) + " Default escape for newline (\\n), carriage return (\\r), and tab (\\t)\n");
364 :
365 1 : buffer->clear();
366 :
367 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:escape=\"[]\"}");
368 1 : buffer->set_format(f);
369 :
370 2 : SNAP_LOG_ERROR << "Try again [with a string]" << SNAP_LOG_SEND;
371 3 : CATCH_REQUIRE(buffer->str() == std::string(host) + " Try again \\[with a string\\]\n");
372 :
373 1 : buffer->clear();
374 :
375 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:escape=\"\a\b\f\n\r\t\v\x1f\xC2\x88\xC2\x97\"}");
376 1 : buffer->set_format(f);
377 :
378 2 : SNAP_LOG_ERROR << "Escape all \a\b\f\n\r\t\v\x1f\xC2\x88\xC2\x97 types" << SNAP_LOG_SEND;
379 3 : CATCH_REQUIRE(buffer->str() == std::string(host) + " Escape all \\a\\b\\f\\n\\r\\t\\v^_@H@W types\n");
380 :
381 1 : l->reset();
382 1 : }
383 9 : CATCH_END_SECTION()
384 :
385 9 : CATCH_START_SECTION("variable: caps")
386 : {
387 5 : snaplogger::set_diagnostic(snaplogger::DIAG_KEY_PROGNAME, "caps");
388 :
389 1 : snaplogger::logger::pointer_t l(snaplogger::logger::get_instance());
390 1 : snaplogger::buffer_appender::pointer_t buffer(std::make_shared<snaplogger::buffer_appender>("test-buffer"));
391 :
392 1 : char const * cargv[] =
393 : {
394 : "/usr/bin/daemon",
395 : nullptr
396 : };
397 1 : int const argc(sizeof(cargv) / sizeof(cargv[0]) - 1);
398 1 : char ** argv = const_cast<char **>(cargv);
399 :
400 1 : advgetopt::options_environment environment_options;
401 1 : environment_options.f_project_name = "test-logger";
402 1 : environment_options.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
403 1 : advgetopt::getopt opts(environment_options);
404 1 : opts.parse_program_name(argv);
405 1 : opts.parse_arguments(argc, argv, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
406 :
407 1 : buffer->set_config(opts);
408 :
409 1 : snaplogger::format::pointer_t f(std::make_shared<snaplogger::format>("${message:caps}"));
410 1 : buffer->set_format(f);
411 :
412 1 : l->add_appender(buffer);
413 :
414 2 : SNAP_LOG_ERROR << "this message words will get their FIRST-LETTER capitalized." << SNAP_LOG_SEND;
415 1 : CATCH_REQUIRE(buffer->str() == "This Message Words Will Get Their First-Letter Capitalized.\n");
416 :
417 1 : l->reset();
418 1 : }
419 9 : CATCH_END_SECTION()
420 :
421 9 : CATCH_START_SECTION("variable: lower/upper")
422 : {
423 5 : snaplogger::set_diagnostic(snaplogger::DIAG_KEY_PROGNAME, "case");
424 :
425 1 : snaplogger::logger::pointer_t l(snaplogger::logger::get_instance());
426 1 : snaplogger::buffer_appender::pointer_t buffer(std::make_shared<snaplogger::buffer_appender>("test-buffer"));
427 :
428 1 : char const * cargv[] =
429 : {
430 : "/usr/bin/daemon",
431 : nullptr
432 : };
433 1 : int const argc(sizeof(cargv) / sizeof(cargv[0]) - 1);
434 1 : char ** argv = const_cast<char **>(cargv);
435 :
436 1 : advgetopt::options_environment environment_options;
437 1 : environment_options.f_project_name = "test-logger";
438 1 : environment_options.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
439 1 : advgetopt::getopt opts(environment_options);
440 1 : opts.parse_program_name(argv);
441 1 : opts.parse_arguments(argc, argv, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
442 :
443 1 : buffer->set_config(opts);
444 :
445 1 : snaplogger::format::pointer_t f(std::make_shared<snaplogger::format>("${message:lower}"));
446 1 : buffer->set_format(f);
447 :
448 1 : l->add_appender(buffer);
449 :
450 2 : SNAP_LOG_ERROR << "This message words will get their FIRST-LETTER capitalized." << SNAP_LOG_SEND;
451 1 : CATCH_REQUIRE(buffer->str() == "this message words will get their first-letter capitalized.\n");
452 :
453 1 : buffer->clear();
454 :
455 1 : f = std::make_shared<snaplogger::format>("${message:upper}");
456 1 : buffer->set_format(f);
457 :
458 2 : SNAP_LOG_ERROR << "This message words will get their FIRST-LETTER capitalized." << SNAP_LOG_SEND;
459 1 : CATCH_REQUIRE(buffer->str() == "THIS MESSAGE WORDS WILL GET THEIR FIRST-LETTER CAPITALIZED.\n");
460 :
461 1 : l->reset();
462 1 : }
463 9 : CATCH_END_SECTION()
464 :
465 9 : CATCH_START_SECTION("variable: default align value")
466 : {
467 5 : snaplogger::set_diagnostic(snaplogger::DIAG_KEY_PROGNAME, "message-variable-default-param");
468 :
469 1 : snaplogger::logger::pointer_t l(snaplogger::logger::get_instance());
470 1 : snaplogger::buffer_appender::pointer_t buffer(std::make_shared<snaplogger::buffer_appender>("test-buffer"));
471 :
472 1 : char const * cargv[] =
473 : {
474 : "/usr/bin/daemon",
475 : nullptr
476 : };
477 1 : int const argc(sizeof(cargv) / sizeof(cargv[0]) - 1);
478 1 : char ** argv = const_cast<char **>(cargv);
479 :
480 1 : advgetopt::options_environment environment_options;
481 1 : environment_options.f_project_name = "test-logger";
482 1 : environment_options.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
483 1 : advgetopt::getopt opts(environment_options);
484 1 : opts.parse_program_name(argv);
485 1 : opts.parse_arguments(argc, argv, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
486 :
487 1 : buffer->set_config(opts);
488 :
489 1 : snaplogger::format::pointer_t f(std::make_shared<snaplogger::format>("${hostname:max_width=3} ${message}"));
490 1 : buffer->set_format(f);
491 :
492 1 : l->add_appender(buffer);
493 :
494 1 : char host[HOST_NAME_MAX + 2 + 30];
495 1 : CATCH_REQUIRE(gethostname(host, HOST_NAME_MAX + 1) == 0);
496 1 : host[HOST_NAME_MAX + 1] = '\0';
497 3 : std::string aligned(host);
498 1 : aligned = aligned.substr(0, 3);
499 1 : while(aligned.length() < 3)
500 : {
501 0 : aligned = " " + aligned;
502 : }
503 :
504 2 : SNAP_LOG_ERROR << "<- first three letters of hostname" << SNAP_LOG_SEND;
505 1 : CATCH_REQUIRE(buffer->str() == aligned + " <- first three letters of hostname\n");
506 :
507 1 : l->reset();
508 1 : }
509 9 : CATCH_END_SECTION()
510 :
511 9 : CATCH_START_SECTION("variable: systemd severity")
512 : {
513 5 : snaplogger::set_diagnostic(snaplogger::DIAG_KEY_PROGNAME, "message-variable-systemd-severity");
514 :
515 1 : snaplogger::logger::pointer_t l(snaplogger::logger::get_instance());
516 1 : snaplogger::buffer_appender::pointer_t buffer(std::make_shared<snaplogger::buffer_appender>("test-buffer"));
517 :
518 1 : char const * cargv[] =
519 : {
520 : "/usr/bin/daemon",
521 : nullptr
522 : };
523 1 : int const argc(sizeof(cargv) / sizeof(cargv[0]) - 1);
524 1 : char ** argv = const_cast<char **>(cargv);
525 :
526 1 : advgetopt::options_environment environment_options;
527 1 : environment_options.f_project_name = "test-logger";
528 1 : environment_options.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
529 1 : advgetopt::getopt opts(environment_options);
530 1 : opts.parse_program_name(argv);
531 1 : opts.parse_arguments(argc, argv, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
532 :
533 1 : buffer->set_config(opts);
534 :
535 1 : snaplogger::format::pointer_t f(std::make_shared<snaplogger::format>("${severity:format=systemd} ${message} (${severity:format=alpha})"));
536 1 : buffer->set_format(f);
537 :
538 1 : l->add_appender(buffer);
539 :
540 2 : SNAP_LOG_EMERGENCY << "<- severity tag for systemd/syslog" << SNAP_LOG_SEND;
541 2 : SNAP_LOG_ALERT << "<- severity tag for systemd/syslog" << SNAP_LOG_SEND;
542 2 : SNAP_LOG_CRIT << "<- severity tag for systemd/syslog" << SNAP_LOG_SEND;
543 2 : SNAP_LOG_ERROR << "<- severity tag for systemd/syslog" << SNAP_LOG_SEND;
544 2 : SNAP_LOG_WARNING << "<- severity tag for systemd/syslog" << SNAP_LOG_SEND;
545 2 : SNAP_LOG_MINOR << "<- severity tag for systemd/syslog" << SNAP_LOG_SEND; // a.k.a. a NOTICE for syslog
546 2 : SNAP_LOG_INFO << "<- severity tag for systemd/syslog" << SNAP_LOG_SEND;
547 2 : SNAP_LOG_DEBUG << "<- severity tag for systemd/syslog" << SNAP_LOG_SEND;
548 :
549 1 : CATCH_REQUIRE(buffer->str() == "<0> <- severity tag for systemd/syslog (emergency)\n"
550 : "<1> <- severity tag for systemd/syslog (alert)\n"
551 : "<2> <- severity tag for systemd/syslog (critical)\n"
552 : "<3> <- severity tag for systemd/syslog (error)\n"
553 : "<4> <- severity tag for systemd/syslog (warning)\n"
554 : "<5> <- severity tag for systemd/syslog (minor)\n"
555 : "<6> <- severity tag for systemd/syslog (information)\n");
556 :
557 1 : l->set_severity(::snaplogger::severity_t::SEVERITY_ALL);
558 2 : SNAP_LOG_DEBUG << "<- severity tag for systemd/syslog" << SNAP_LOG_SEND;
559 :
560 1 : CATCH_REQUIRE(buffer->str() == "<0> <- severity tag for systemd/syslog (emergency)\n"
561 : "<1> <- severity tag for systemd/syslog (alert)\n"
562 : "<2> <- severity tag for systemd/syslog (critical)\n"
563 : "<3> <- severity tag for systemd/syslog (error)\n"
564 : "<4> <- severity tag for systemd/syslog (warning)\n"
565 : "<5> <- severity tag for systemd/syslog (minor)\n"
566 : "<6> <- severity tag for systemd/syslog (information)\n"
567 : "<7> <- severity tag for systemd/syslog (debug)\n");
568 :
569 1 : l->reset();
570 1 : }
571 9 : CATCH_END_SECTION()
572 :
573 9 : CATCH_START_SECTION("variable: systemd severity with an invalid format")
574 : {
575 5 : snaplogger::set_diagnostic(snaplogger::DIAG_KEY_PROGNAME, "message-variable-systemd-severity-invalid-format");
576 :
577 1 : snaplogger::logger::pointer_t l(snaplogger::logger::get_instance());
578 1 : snaplogger::buffer_appender::pointer_t buffer(std::make_shared<snaplogger::buffer_appender>("test-buffer"));
579 :
580 1 : char const * cargv[] =
581 : {
582 : "/usr/bin/daemon",
583 : nullptr
584 : };
585 1 : int const argc(sizeof(cargv) / sizeof(cargv[0]) - 1);
586 1 : char ** argv = const_cast<char **>(cargv);
587 :
588 1 : advgetopt::options_environment environment_options;
589 1 : environment_options.f_project_name = "test-logger";
590 1 : environment_options.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
591 1 : advgetopt::getopt opts(environment_options);
592 1 : opts.parse_program_name(argv);
593 1 : opts.parse_arguments(argc, argv, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
594 :
595 1 : buffer->set_config(opts);
596 :
597 1 : snaplogger::format::pointer_t f(std::make_shared<snaplogger::format>("${severity:format=invalid} ${message} (${severity:format=alpha})"));
598 1 : buffer->set_format(f);
599 :
600 1 : l->add_appender(buffer);
601 :
602 5 : CATCH_REQUIRE_THROWS_MATCHES(
603 : SNAP_LOG_MAJOR << "<- severity tag for systemd/syslog" << SNAP_LOG_SEND
604 : , snaplogger::invalid_variable
605 : , Catch::Matchers::ExceptionMessage(
606 : "logger_error: the ${severity:format=alpha|number|systemd}"
607 : " variable cannot be set to \"invalid\"."));
608 :
609 1 : CATCH_REQUIRE(buffer->str() == "");
610 :
611 1 : l->reset();
612 1 : }
613 9 : CATCH_END_SECTION()
614 :
615 9 : CATCH_START_SECTION("variable: bad UTF-8 in message")
616 : {
617 5 : snaplogger::set_diagnostic(snaplogger::DIAG_KEY_PROGNAME, "case");
618 :
619 1 : snaplogger::logger::pointer_t l(snaplogger::logger::get_instance());
620 1 : snaplogger::buffer_appender::pointer_t buffer(std::make_shared<snaplogger::buffer_appender>("test-buffer"));
621 :
622 1 : char const * cargv[] =
623 : {
624 : "/usr/bin/daemon",
625 : nullptr
626 : };
627 1 : int const argc(sizeof(cargv) / sizeof(cargv[0]) - 1);
628 1 : char ** argv = const_cast<char **>(cargv);
629 :
630 1 : advgetopt::options_environment environment_options;
631 1 : environment_options.f_project_name = "test-logger";
632 1 : environment_options.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
633 1 : advgetopt::getopt opts(environment_options);
634 1 : opts.parse_program_name(argv);
635 1 : opts.parse_arguments(argc, argv, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
636 :
637 1 : buffer->set_config(opts);
638 :
639 1 : snaplogger::format::pointer_t f(std::make_shared<snaplogger::format>("${message:caps}"));
640 1 : buffer->set_format(f);
641 :
642 1 : l->add_appender(buffer);
643 :
644 2 : SNAP_LOG_ERROR << "Byte 0xFF is not UTF-8 \xFF so the string does not even compile?" << SNAP_LOG_SEND;
645 1 : CATCH_REQUIRE(buffer->str() == "Byte 0xFF is not UTF-8 \xFF so the string does not even compile?"
646 : " {WARNING: your value has invalid UTF-8 characters; do you"
647 : " use an std::int8_t or std::uint8_t variable as a parameter"
648 : " to the log message? Those are often inserted as characters"
649 : " instead of numbers; exception message:"
650 : " \"libutf8_exception: to_u32string(): a UTF-8 character"
651 : " could not be extracted.\"} \n");
652 :
653 1 : l->reset();
654 1 : }
655 9 : CATCH_END_SECTION()
656 :
657 9 : CATCH_START_SECTION("variable: time:process_ms")
658 : {
659 5 : snaplogger::set_diagnostic(snaplogger::DIAG_KEY_PROGNAME, "on_repeat");
660 :
661 1 : snaplogger::logger::pointer_t l(snaplogger::logger::get_instance());
662 1 : snaplogger::buffer_appender::pointer_t buffer(std::make_shared<snaplogger::buffer_appender>("test-buffer"));
663 :
664 1 : char const * cargv[] =
665 : {
666 : "/usr/bin/daemon",
667 : "--no-repeat",
668 : "20",
669 : nullptr
670 : };
671 1 : int const argc(std::size(cargv) - 1);
672 1 : char ** argv = const_cast<char **>(cargv);
673 :
674 1 : advgetopt::option const options[] =
675 : {
676 : advgetopt::define_option(
677 : advgetopt::Name("no-repeat")
678 : , advgetopt::Flags(advgetopt::all_flags<
679 : advgetopt::GETOPT_FLAG_REQUIRED
680 : , advgetopt::GETOPT_FLAG_GROUP_OPTIONS>())
681 : , advgetopt::Help("Number of lines to not repeat.")
682 : , advgetopt::DefaultValue("0")
683 : ),
684 : advgetopt::end_options()
685 : };
686 1 : advgetopt::options_environment environment_options;
687 1 : environment_options.f_project_name = "test-logger";
688 1 : environment_options.f_options = options;
689 1 : environment_options.f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_SYSTEM_PARAMETERS;
690 1 : advgetopt::getopt opts(environment_options);
691 1 : opts.parse_program_name(argv);
692 1 : opts.parse_arguments(argc, argv, advgetopt::option_source_t::SOURCE_COMMAND_LINE);
693 :
694 1 : buffer->set_config(opts);
695 :
696 1 : snaplogger::format::pointer_t f(std::make_shared<snaplogger::format>("process:${time:process_ms}: ${message}"));
697 1 : buffer->set_format(f);
698 :
699 1 : l->add_appender(buffer);
700 :
701 2 : SNAP_LOG_FATAL << "We need a first message." << SNAP_LOG_SEND;
702 2 : SNAP_LOG_ERROR << "This calls the on_repeat function." << SNAP_LOG_SEND;
703 : // the time changes between runs so it's impossible to verify as is
704 : //CATCH_REQUIRE(buffer->str() == "process:00:00:00.0: This calls the on_repeat function.\n");
705 1 : std::string const result(buffer->str());
706 1 : CATCH_REQUIRE(result.starts_with("process:"));
707 1 : CATCH_REQUIRE(result.ends_with(": This calls the on_repeat function.\n"));
708 :
709 1 : buffer->clear();
710 :
711 1 : f = std::make_shared<snaplogger::format>("${message:upper}");
712 1 : buffer->set_format(f);
713 :
714 2 : SNAP_LOG_ERROR << "This message words will get their FIRST-LETTER capitalized." << SNAP_LOG_SEND;
715 1 : CATCH_REQUIRE(buffer->str() == "THIS MESSAGE WORDS WILL GET THEIR FIRST-LETTER CAPITALIZED.\n");
716 :
717 1 : l->reset();
718 1 : }
719 9 : CATCH_END_SECTION()
720 9 : }
721 :
722 :
723 :
724 3 : CATCH_TEST_CASE("duplicate_factory", "[variable][factory]")
725 : {
726 3 : CATCH_START_SECTION("variable: attempt dynamically creating a factory which already exists")
727 : {
728 : class fake_variable_factory final
729 : : public snaplogger::variable_factory
730 : {
731 : public:
732 1 : fake_variable_factory()
733 3 : : variable_factory("version")
734 : {
735 1 : }
736 :
737 0 : virtual snaplogger::variable::pointer_t create_variable() override final
738 : {
739 : // we can't even register this one so returning an empty
740 : // pointer is perfectly safe here
741 : //
742 0 : return snaplogger::variable::pointer_t();
743 : }
744 : };
745 :
746 7 : CATCH_REQUIRE_THROWS_MATCHES(
747 : snaplogger::register_variable_factory(std::make_shared<fake_variable_factory>())
748 : , snaplogger::duplicate_error
749 : , Catch::Matchers::ExceptionMessage("logger_error: trying to add two variable factories of type \"version\"."));
750 : }
751 3 : CATCH_END_SECTION()
752 :
753 3 : CATCH_START_SECTION("variable: attempt creating a variable with a non-existant type")
754 : {
755 3 : CATCH_REQUIRE(snaplogger::get_variable("fake") == nullptr);
756 : }
757 3 : CATCH_END_SECTION()
758 :
759 3 : CATCH_START_SECTION("variable: attempt creating a function factory with an existing name")
760 : {
761 : class fake_function final
762 : : public snaplogger::function
763 : {
764 : public:
765 1 : fake_function()
766 3 : : function("padding")
767 : {
768 1 : }
769 :
770 0 : virtual void apply(
771 : ::snaplogger::message const & msg
772 : , ::snaplogger::function_data & d
773 : , ::snaplogger::param::pointer_t const & p) override
774 : {
775 0 : snapdev::NOT_USED(msg, d, p);
776 0 : }
777 : };
778 :
779 7 : CATCH_REQUIRE_THROWS_MATCHES(
780 : snaplogger::register_function(std::make_shared<fake_function>())
781 : , snaplogger::duplicate_error
782 : , Catch::Matchers::ExceptionMessage("logger_error: trying to add two functions named \"padding\"."));
783 : }
784 3 : CATCH_END_SECTION()
785 3 : }
786 :
787 :
788 : // vim: ts=4 sw=4 et
|