]> git.proxmox.com Git - mirror_frr.git/blame - lib/log_vty.c
lib: rewrite zlog lock-free & TLS-buffered
[mirror_frr.git] / lib / log_vty.c
CommitLineData
f73126c3
SW
1/*
2 * Logging - VTY code
3 * Copyright (C) 2019 Cumulus Networks, Inc.
4 * Stephen Worley
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <zebra.h>
22
23#include "lib/log_vty.h"
24#include "command.h"
f73126c3 25#include "lib/log.h"
0bdeb5e5
DL
26#include "lib/zlog_targets.h"
27#include "lib/lib_errors.h"
28#include "lib/printfrr.h"
29
f73126c3
SW
30#ifndef VTYSH_EXTRACT_PL
31#include "lib/log_vty_clippy.c"
32#endif
33
0bdeb5e5
DL
34#define ZLOG_MAXLVL(a, b) MAX(a, b)
35
36DEFINE_HOOK(zlog_rotate, (), ())
37
38static const int log_default_lvl = LOG_DEBUG;
39
40static int log_config_stdout_lvl = ZLOG_DISABLED;
41static int log_config_syslog_lvl = ZLOG_DISABLED;
42static int log_cmdline_stdout_lvl = ZLOG_DISABLED;
43static int log_cmdline_syslog_lvl = ZLOG_DISABLED;
44
45static struct zlog_cfg_file zt_file_cmdline = {
46 .prio_min = ZLOG_DISABLED,
47};
48static struct zlog_cfg_file zt_file = {
49 .prio_min = ZLOG_DISABLED,
50};
51static struct zlog_cfg_file zt_stdout = {
52 .prio_min = ZLOG_DISABLED,
53};
54
55static const char *zlog_progname;
56static const char *zlog_protoname;
57
58static const struct facility_map {
59 int facility;
60 const char *name;
61 size_t match;
62} syslog_facilities[] = {
63 {LOG_KERN, "kern", 1},
64 {LOG_USER, "user", 2},
65 {LOG_MAIL, "mail", 1},
66 {LOG_DAEMON, "daemon", 1},
67 {LOG_AUTH, "auth", 1},
68 {LOG_SYSLOG, "syslog", 1},
69 {LOG_LPR, "lpr", 2},
70 {LOG_NEWS, "news", 1},
71 {LOG_UUCP, "uucp", 2},
72 {LOG_CRON, "cron", 1},
73#ifdef LOG_FTP
74 {LOG_FTP, "ftp", 1},
75#endif
76 {LOG_LOCAL0, "local0", 6},
77 {LOG_LOCAL1, "local1", 6},
78 {LOG_LOCAL2, "local2", 6},
79 {LOG_LOCAL3, "local3", 6},
80 {LOG_LOCAL4, "local4", 6},
81 {LOG_LOCAL5, "local5", 6},
82 {LOG_LOCAL6, "local6", 6},
83 {LOG_LOCAL7, "local7", 6},
84 {0, NULL, 0},
85};
86
87static const char * const zlog_priority[] = {
88 "emergencies", "alerts", "critical", "errors", "warnings",
89 "notifications", "informational", "debugging", NULL,
90};
91
92static const char *facility_name(int facility)
93{
94 const struct facility_map *fm;
95
96 for (fm = syslog_facilities; fm->name; fm++)
97 if (fm->facility == facility)
98 return fm->name;
99 return "";
100}
101
102static int facility_match(const char *str)
f73126c3 103{
0bdeb5e5 104 const struct facility_map *fm;
f73126c3 105
0bdeb5e5
DL
106 for (fm = syslog_facilities; fm->name; fm++)
107 if (!strncmp(str, fm->name, fm->match))
108 return fm->facility;
109 return -1;
110}
111
112int log_level_match(const char *s)
113{
114 int level;
115
116 for (level = 0; zlog_priority[level] != NULL; level++)
117 if (!strncmp(s, zlog_priority[level], 2))
118 return level;
119 return ZLOG_DISABLED;
120}
121
122void zlog_rotate(void)
123{
124 zlog_file_rotate(&zt_file);
125 hook_call(zlog_rotate);
126}
127
128
129void log_show_syslog(struct vty *vty)
130{
131 int level = zlog_syslog_get_prio_min();
132
133 vty_out(vty, "Syslog logging: ");
134 if (level == ZLOG_DISABLED)
135 vty_out(vty, "disabled\n");
f73126c3 136 else
0bdeb5e5
DL
137 vty_out(vty, "level %s, facility %s, ident %s\n",
138 zlog_priority[level],
139 facility_name(zlog_syslog_get_facility()),
140 zlog_progname);
141}
f73126c3 142
0bdeb5e5
DL
143DEFUN (show_logging,
144 show_logging_cmd,
145 "show logging",
146 SHOW_STR
147 "Show current logging configuration\n")
148{
149 log_show_syslog(vty);
150
151 vty_out(vty, "Stdout logging: ");
152 if (zt_stdout.prio_min == ZLOG_DISABLED)
153 vty_out(vty, "disabled");
154 else
155 vty_out(vty, "level %s",
156 zlog_priority[zt_stdout.prio_min]);
157 vty_out(vty, "\n");
158
159 vty_out(vty, "File logging: ");
160 if (zt_file.prio_min == ZLOG_DISABLED || !zt_file.filename)
161 vty_out(vty, "disabled");
162 else
163 vty_out(vty, "level %s, filename %s",
164 zlog_priority[zt_file.prio_min], zt_file.filename);
165 vty_out(vty, "\n");
166
167 if (log_cmdline_syslog_lvl != ZLOG_DISABLED)
168 vty_out(vty,
169 "From command line: \"--log syslog --log-level %s\"\n",
170 zlog_priority[log_cmdline_syslog_lvl]);
171 if (log_cmdline_stdout_lvl != ZLOG_DISABLED)
172 vty_out(vty,
173 "From command line: \"--log stdout --log-level %s\"\n",
174 zlog_priority[log_cmdline_stdout_lvl]);
175 if (zt_file_cmdline.prio_min != ZLOG_DISABLED)
176 vty_out(vty,
177 "From command line: \"--log file:%s --log-level %s\"\n",
178 zt_file_cmdline.filename,
179 zlog_priority[zt_file_cmdline.prio_min]);
180
181 vty_out(vty, "Protocol name: %s\n", zlog_protoname);
182 vty_out(vty, "Record priority: %s\n",
183 (zt_file.record_priority ? "enabled" : "disabled"));
184 vty_out(vty, "Timestamp precision: %d\n", zt_file.ts_subsec);
f73126c3
SW
185 return CMD_SUCCESS;
186}
187
0bdeb5e5
DL
188DEFPY (config_log_stdout,
189 config_log_stdout_cmd,
190 "log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
191 "Logging control\n"
192 "Set stdout logging level\n"
193 LOG_LEVEL_DESC)
194{
195 int level;
196
197 if (levelarg) {
198 level = log_level_match(levelarg);
199 if (level == ZLOG_DISABLED)
200 return CMD_ERR_NO_MATCH;
201 } else
202 level = log_default_lvl;
203
204 log_config_stdout_lvl = level;
205 zt_stdout.prio_min = ZLOG_MAXLVL(log_config_stdout_lvl,
206 log_cmdline_stdout_lvl);
207 zlog_file_set_other(&zt_stdout);
208 return CMD_SUCCESS;
209}
210
211DEFUN (no_config_log_stdout,
212 no_config_log_stdout_cmd,
213 "no log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
214 NO_STR
215 "Logging control\n"
216 "Cancel logging to stdout\n"
217 LOG_LEVEL_DESC)
f73126c3 218{
0bdeb5e5
DL
219 log_config_stdout_lvl = ZLOG_DISABLED;
220 zt_stdout.prio_min = ZLOG_MAXLVL(log_config_stdout_lvl,
221 log_cmdline_stdout_lvl);
222 zlog_file_set_other(&zt_stdout);
f73126c3
SW
223 return CMD_SUCCESS;
224}
225
0bdeb5e5
DL
226DEFUN_HIDDEN (config_log_monitor,
227 config_log_monitor_cmd,
228 "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
229 "Logging control\n"
230 "Set terminal line (monitor) logging level\n"
231 LOG_LEVEL_DESC)
232{
233 vty_out(vty, "%% \"log monitor\" is deprecated and does nothing.\n");
234 return CMD_SUCCESS;
235}
236
237DEFUN_HIDDEN (no_config_log_monitor,
238 no_config_log_monitor_cmd,
239 "no log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
240 NO_STR
241 "Logging control\n"
242 "Disable terminal line (monitor) logging\n"
243 LOG_LEVEL_DESC)
244{
245 return CMD_SUCCESS;
246}
247
248static int set_log_file(struct zlog_cfg_file *target, struct vty *vty,
249 const char *fname, int loglevel)
250{
251 char *p = NULL;
252 const char *fullpath;
253 bool ok;
254
255 /* Path detection. */
256 if (!IS_DIRECTORY_SEP(*fname)) {
257 char cwd[MAXPATHLEN + 1];
258
259 cwd[MAXPATHLEN] = '\0';
260
261 if (getcwd(cwd, MAXPATHLEN) == NULL) {
262 flog_err_sys(EC_LIB_SYSTEM_CALL,
263 "config_log_file: Unable to alloc mem!");
264 return CMD_WARNING_CONFIG_FAILED;
265 }
266
267 p = XMALLOC(MTYPE_TMP, strlen(cwd) + strlen(fname) + 2);
268 sprintf(p, "%s/%s", cwd, fname);
269 fullpath = p;
270 } else
271 fullpath = fname;
272
273 target->prio_min = loglevel;
274 ok = zlog_file_set_filename(target, fullpath);
275
276 XFREE(MTYPE_TMP, p);
277
278 if (!ok) {
279 if (vty)
280 vty_out(vty, "can't open logfile %s\n", fname);
281 return CMD_WARNING_CONFIG_FAILED;
282 }
283 return CMD_SUCCESS;
284}
285
286void command_setup_early_logging(const char *dest, const char *level)
287{
288 int nlevel;
289 char *sep;
290 int len;
291 char type[8];
292
293 if (level) {
294 nlevel = log_level_match(level);
295
296 if (nlevel == ZLOG_DISABLED) {
297 fprintf(stderr, "invalid log level \"%s\"\n", level);
298 exit(1);
299 }
300 } else
301 nlevel = log_default_lvl;
302
303 if (!dest)
304 return;
305
306 sep = strchr(dest, ':');
307 len = sep ? (int)(sep - dest) : (int)strlen(dest);
308
309 snprintfrr(type, sizeof(type), "%.*s", len, dest);
310
311 if (strcmp(type, "stdout") == 0) {
312 log_cmdline_stdout_lvl = nlevel;
313 zt_stdout.prio_min = ZLOG_MAXLVL(log_config_stdout_lvl,
314 log_cmdline_stdout_lvl);
315 zlog_file_set_other(&zt_stdout);
316 return;
317 }
318 if (strcmp(type, "syslog") == 0) {
319 log_cmdline_syslog_lvl = nlevel;
320 zlog_syslog_set_prio_min(ZLOG_MAXLVL(log_config_syslog_lvl,
321 log_cmdline_syslog_lvl));
322 return;
323 }
324 if (strcmp(type, "file") == 0 && sep) {
325 sep++;
326 set_log_file(&zt_file_cmdline, NULL, sep, nlevel);
327 return;
328 }
329
330 fprintf(stderr, "invalid log target \"%s\" (\"%s\")\n", type, dest);
331 exit(1);
332}
333
334DEFUN (clear_log_cmdline,
335 clear_log_cmdline_cmd,
336 "clear log cmdline-targets",
337 CLEAR_STR
338 "Logging control\n"
339 "Disable log targets specified at startup by --log option\n")
f73126c3 340{
0bdeb5e5
DL
341 zt_file_cmdline.prio_min = ZLOG_DISABLED;
342 zlog_file_set_other(&zt_file_cmdline);
343
344 log_cmdline_syslog_lvl = ZLOG_DISABLED;
345 zlog_syslog_set_prio_min(ZLOG_MAXLVL(log_config_syslog_lvl,
346 log_cmdline_syslog_lvl));
347
348 log_cmdline_stdout_lvl = ZLOG_DISABLED;
349 zt_stdout.prio_min = ZLOG_MAXLVL(log_config_stdout_lvl,
350 log_cmdline_stdout_lvl);
351 zlog_file_set_other(&zt_stdout);
f73126c3 352
0bdeb5e5
DL
353 return CMD_SUCCESS;
354}
f73126c3 355
0bdeb5e5
DL
356DEFPY (config_log_file,
357 config_log_file_cmd,
358 "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
359 "Logging control\n"
360 "Logging to file\n"
361 "Logging filename\n"
362 LOG_LEVEL_DESC)
363{
364 int level = log_default_lvl;
365
366 if (levelarg) {
367 level = log_level_match(levelarg);
368 if (level == ZLOG_DISABLED)
369 return CMD_ERR_NO_MATCH;
f73126c3 370 }
0bdeb5e5
DL
371 return set_log_file(&zt_file, vty, filename, level);
372}
373
374DEFUN (no_config_log_file,
375 no_config_log_file_cmd,
376 "no log file [FILENAME [LEVEL]]",
377 NO_STR
378 "Logging control\n"
379 "Cancel logging to file\n"
380 "Logging file name\n"
381 "Logging level\n")
382{
383 zt_file.prio_min = ZLOG_DISABLED;
384 zlog_file_set_other(&zt_file);
385 return CMD_SUCCESS;
386}
387
388DEFPY (config_log_syslog,
389 config_log_syslog_cmd,
390 "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
391 "Logging control\n"
392 "Set syslog logging level\n"
393 LOG_LEVEL_DESC)
394{
395 int level;
396
397 if (levelarg) {
398 level = log_level_match(levelarg);
399
400 if (level == ZLOG_DISABLED)
401 return CMD_ERR_NO_MATCH;
402 } else
403 level = log_default_lvl;
404
405 log_config_syslog_lvl = level;
406 zlog_syslog_set_prio_min(ZLOG_MAXLVL(log_config_syslog_lvl,
407 log_cmdline_syslog_lvl));
408 return CMD_SUCCESS;
409}
410
411DEFUN (no_config_log_syslog,
412 no_config_log_syslog_cmd,
413 "no log syslog [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>] [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
414 NO_STR
415 "Logging control\n"
416 "Cancel logging to syslog\n"
417 LOG_FACILITY_DESC
418 LOG_LEVEL_DESC)
419{
420 log_config_syslog_lvl = ZLOG_DISABLED;
421 zlog_syslog_set_prio_min(ZLOG_MAXLVL(log_config_syslog_lvl,
422 log_cmdline_syslog_lvl));
423 return CMD_SUCCESS;
424}
425
426DEFPY (config_log_facility,
427 config_log_facility_cmd,
428 "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>$facilityarg",
429 "Logging control\n"
430 "Facility parameter for syslog messages\n"
431 LOG_FACILITY_DESC)
432{
433 int facility = facility_match(facilityarg);
434
435 zlog_syslog_set_facility(facility);
436 return CMD_SUCCESS;
437}
438
439DEFUN (no_config_log_facility,
440 no_config_log_facility_cmd,
441 "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
442 NO_STR
443 "Logging control\n"
444 "Reset syslog facility to default (daemon)\n"
445 LOG_FACILITY_DESC)
446{
447 zlog_syslog_set_facility(LOG_DAEMON);
448 return CMD_SUCCESS;
449}
450
451DEFUN (config_log_record_priority,
452 config_log_record_priority_cmd,
453 "log record-priority",
454 "Logging control\n"
455 "Log the priority of the message within the message\n")
456{
457 zt_file.record_priority = true;
458 zlog_file_set_other(&zt_file);
459 zt_stdout.record_priority = true;
460 zlog_file_set_other(&zt_stdout);
461 return CMD_SUCCESS;
462}
463
464DEFUN (no_config_log_record_priority,
465 no_config_log_record_priority_cmd,
466 "no log record-priority",
467 NO_STR
468 "Logging control\n"
469 "Do not log the priority of the message within the message\n")
470{
471 zt_file.record_priority = false;
472 zlog_file_set_other(&zt_file);
473 zt_stdout.record_priority = false;
474 zlog_file_set_other(&zt_stdout);
475 return CMD_SUCCESS;
476}
f73126c3 477
0bdeb5e5
DL
478DEFPY (config_log_timestamp_precision,
479 config_log_timestamp_precision_cmd,
480 "log timestamp precision (0-6)",
481 "Logging control\n"
482 "Timestamp configuration\n"
483 "Set the timestamp precision\n"
484 "Number of subsecond digits\n")
485{
486 zt_file.ts_subsec = precision;
487 zlog_file_set_other(&zt_file);
488 zt_stdout.ts_subsec = precision;
489 zlog_file_set_other(&zt_stdout);
490 return CMD_SUCCESS;
491}
f73126c3 492
0bdeb5e5
DL
493DEFUN (no_config_log_timestamp_precision,
494 no_config_log_timestamp_precision_cmd,
495 "no log timestamp precision [(0-6)]",
496 NO_STR
497 "Logging control\n"
498 "Timestamp configuration\n"
499 "Reset the timestamp precision to the default value of 0\n"
500 "Number of subsecond digits\n")
501{
502 zt_file.ts_subsec = 0;
503 zlog_file_set_other(&zt_file);
504 zt_stdout.ts_subsec = 0;
505 zlog_file_set_other(&zt_stdout);
f73126c3
SW
506 return CMD_SUCCESS;
507}
508
0bdeb5e5 509void log_config_write(struct vty *vty)
f73126c3 510{
0bdeb5e5
DL
511 bool show_cmdline_hint = false;
512
513 if (zt_file.prio_min != ZLOG_DISABLED && zt_file.filename) {
514 vty_out(vty, "log file %s", zt_file.filename);
515
516 if (zt_file.prio_min != log_default_lvl)
517 vty_out(vty, " %s", zlog_priority[zt_file.prio_min]);
518 vty_out(vty, "\n");
519 }
520
521 if (log_config_stdout_lvl != ZLOG_DISABLED) {
522 vty_out(vty, "log stdout");
523
524 if (log_config_stdout_lvl != log_default_lvl)
525 vty_out(vty, " %s",
526 zlog_priority[log_config_stdout_lvl]);
527 vty_out(vty, "\n");
528 }
529
530 if (log_config_syslog_lvl != ZLOG_DISABLED) {
531 vty_out(vty, "log syslog");
532
533 if (log_config_syslog_lvl != log_default_lvl)
534 vty_out(vty, " %s",
535 zlog_priority[log_config_syslog_lvl]);
536 vty_out(vty, "\n");
537 }
538
539 if (log_cmdline_syslog_lvl != ZLOG_DISABLED) {
540 vty_out(vty,
541 "! \"log syslog %s\" enabled by \"--log\" startup option\n",
542 zlog_priority[log_cmdline_syslog_lvl]);
543 show_cmdline_hint = true;
544 }
545 if (log_cmdline_stdout_lvl != ZLOG_DISABLED) {
546 vty_out(vty,
547 "! \"log stdout %s\" enabled by \"--log\" startup option\n",
548 zlog_priority[log_cmdline_stdout_lvl]);
549 show_cmdline_hint = true;
550 }
551 if (zt_file_cmdline.prio_min != ZLOG_DISABLED) {
552 vty_out(vty,
553 "! \"log file %s %s\" enabled by \"--log\" startup option\n",
554 zt_file_cmdline.filename,
555 zlog_priority[zt_file_cmdline.prio_min]);
556 show_cmdline_hint = true;
557 }
558 if (show_cmdline_hint)
559 vty_out(vty,
560 "! use \"clear log cmdline-targets\" to remove this target\n");
561
562 if (zlog_syslog_get_facility() != LOG_DAEMON)
563 vty_out(vty, "log facility %s\n",
564 facility_name(zlog_syslog_get_facility()));
565
566 if (zt_file.record_priority == 1)
567 vty_out(vty, "log record-priority\n");
568
569 if (zt_file.ts_subsec > 0)
570 vty_out(vty, "log timestamp precision %d\n",
571 zt_file.ts_subsec);
572}
573
574static int log_vty_init(const char *progname, const char *protoname,
575 unsigned short instance, uid_t uid, gid_t gid)
576{
577 zlog_progname = progname;
578 zlog_protoname = protoname;
579
580 zlog_file_set_fd(&zt_stdout, STDOUT_FILENO);
581 return 0;
582}
583
584__attribute__((_CONSTRUCTOR(475))) static void log_vty_preinit(void)
585{
586 hook_register(zlog_init, log_vty_init);
587}
588
589void log_cmd_init(void)
590{
591 install_element(VIEW_NODE, &show_logging_cmd);
592 install_element(ENABLE_NODE, &clear_log_cmdline_cmd);
593
594 install_element(CONFIG_NODE, &config_log_stdout_cmd);
595 install_element(CONFIG_NODE, &no_config_log_stdout_cmd);
596 install_element(CONFIG_NODE, &config_log_monitor_cmd);
597 install_element(CONFIG_NODE, &no_config_log_monitor_cmd);
598 install_element(CONFIG_NODE, &config_log_file_cmd);
599 install_element(CONFIG_NODE, &no_config_log_file_cmd);
600 install_element(CONFIG_NODE, &config_log_syslog_cmd);
601 install_element(CONFIG_NODE, &no_config_log_syslog_cmd);
602 install_element(CONFIG_NODE, &config_log_facility_cmd);
603 install_element(CONFIG_NODE, &no_config_log_facility_cmd);
604 install_element(CONFIG_NODE, &config_log_record_priority_cmd);
605 install_element(CONFIG_NODE, &no_config_log_record_priority_cmd);
606 install_element(CONFIG_NODE, &config_log_timestamp_precision_cmd);
607 install_element(CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
f73126c3 608}