Line data Source code
1 : /*
2 : * Copyright (c) 2018 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 :
16 : #include <stdbool.h>
17 : #include <vlib/vlib.h>
18 : #include <vlib/log.h>
19 : #include <vlib/unix/unix.h>
20 : #include <syslog.h>
21 : #include <vppinfra/elog.h>
22 :
23 : vlib_log_main_t log_main = {
24 : .default_log_level = VLIB_LOG_LEVEL_NOTICE,
25 : .default_syslog_log_level = VLIB_LOG_LEVEL_WARNING,
26 : .unthrottle_time = 3,
27 : .size = 512,
28 : .add_to_elog = 0,
29 : .default_rate_limit = 50,
30 : };
31 :
32 : /* *INDENT-OFF* */
33 559 : VLIB_REGISTER_LOG_CLASS (log_log, static) = {
34 : .class_name = "log",
35 : };
36 : /* *INDENT-ON* */
37 :
38 : static const int colors[] = {
39 : [VLIB_LOG_LEVEL_EMERG] = 1, /* red */
40 : [VLIB_LOG_LEVEL_ALERT] = 1, /* red */
41 : [VLIB_LOG_LEVEL_CRIT] = 1, /* red */
42 : [VLIB_LOG_LEVEL_ERR] = 1, /* red */
43 : [VLIB_LOG_LEVEL_WARNING] = 3, /* yellow */
44 : [VLIB_LOG_LEVEL_NOTICE] = 2, /* green */
45 : [VLIB_LOG_LEVEL_INFO] = 4, /* blue */
46 : [VLIB_LOG_LEVEL_DEBUG] = 6, /* cyan */
47 : };
48 :
49 : static const int log_level_to_syslog_priority[] = {
50 : [VLIB_LOG_LEVEL_EMERG] = LOG_EMERG,
51 : [VLIB_LOG_LEVEL_ALERT] = LOG_ALERT,
52 : [VLIB_LOG_LEVEL_CRIT] = LOG_CRIT,
53 : [VLIB_LOG_LEVEL_ERR] = LOG_ERR,
54 : [VLIB_LOG_LEVEL_WARNING] = LOG_WARNING,
55 : [VLIB_LOG_LEVEL_NOTICE] = LOG_NOTICE,
56 : [VLIB_LOG_LEVEL_INFO] = LOG_INFO,
57 : [VLIB_LOG_LEVEL_DEBUG] = LOG_DEBUG,
58 : [VLIB_LOG_LEVEL_DISABLED] = LOG_DEBUG,
59 : };
60 :
61 : int
62 1637 : last_log_entry ()
63 : {
64 1637 : vlib_log_main_t *lm = &log_main;
65 : int i;
66 :
67 1637 : i = lm->next - lm->count;
68 :
69 1637 : if (i < 0)
70 19 : i += lm->size;
71 1637 : return i;
72 : }
73 : u8 *
74 276470 : format_vlib_log_class (u8 * s, va_list * args)
75 : {
76 276470 : vlib_log_class_t ci = va_arg (*args, vlib_log_class_t);
77 276470 : vlib_log_class_data_t *c = vnet_log_get_class_data (ci);
78 276470 : vlib_log_subclass_data_t *sc = vlib_log_get_subclass_data (ci);
79 :
80 276470 : if (sc->name)
81 253714 : return format (s, "%v/%v", c->name, sc->name);
82 : else
83 22756 : return format (s, "%v", c->name, 0);
84 : }
85 :
86 : u8 *
87 0 : format_indent (u8 * s, va_list * args)
88 : {
89 0 : u8 *v = va_arg (*args, u8 *);
90 0 : u32 indent = va_arg (*args, u32);
91 : u8 *c;
92 :
93 : /* *INDENT-OFF* */
94 0 : vec_foreach (c, v)
95 : {
96 0 : vec_add (s, c, 1);
97 0 : if (c[0] == '\n')
98 0 : for (u32 i = 0; i < indent; i++)
99 0 : vec_add1 (s, (u8) ' ');
100 : }
101 : /* *INDENT-ON* */
102 0 : return s;
103 : }
104 :
105 : static int
106 3586060 : log_level_is_enabled (vlib_log_level_t level, vlib_log_level_t configured)
107 : {
108 3586060 : if (configured == VLIB_LOG_LEVEL_DISABLED)
109 0 : return 0;
110 3586060 : if (level > configured)
111 3483160 : return 0;
112 102893 : return 1;
113 : }
114 :
115 : void
116 1793030 : vlib_log (vlib_log_level_t level, vlib_log_class_t class, char *fmt, ...)
117 : {
118 1793030 : vlib_main_t *vm = vlib_get_main ();
119 1793030 : vlib_log_main_t *lm = &log_main;
120 : vlib_log_entry_t *e;
121 1793030 : vlib_log_subclass_data_t *sc = vlib_log_get_subclass_data (class);
122 : va_list va;
123 1793030 : f64 t = vlib_time_now (vm);
124 1793030 : f64 delta = t - sc->last_event_timestamp;
125 1793030 : int log_enabled = log_level_is_enabled (level, sc->level);
126 1793030 : int syslog_enabled = log_level_is_enabled (level, sc->syslog_level);
127 1793030 : u8 *s = 0;
128 :
129 : /* make sure we are running on the main thread to avoid use in dataplane
130 : code, for dataplane logging consider use of event-logger */
131 1793030 : ASSERT (vlib_get_thread_index () == 0);
132 :
133 1793030 : if ((log_enabled || syslog_enabled) == 0)
134 1700300 : return;
135 :
136 96455 : vec_validate (lm->entries, lm->size);
137 :
138 96455 : if ((delta > lm->unthrottle_time) ||
139 95502 : (sc->is_throttling == 0 && (delta > 1)))
140 : {
141 2912 : sc->last_event_timestamp = t;
142 2912 : sc->last_sec_count = 0;
143 2912 : sc->is_throttling = 0;
144 : }
145 : else
146 : {
147 93543 : sc->last_sec_count++;
148 93543 : if (sc->last_sec_count > sc->rate_limit)
149 3726 : return;
150 89817 : else if (sc->last_sec_count == sc->rate_limit)
151 : {
152 21 : vec_reset_length (s);
153 21 : s = format (s, "--- message(s) throttled ---");
154 21 : sc->is_throttling = 1;
155 : }
156 : }
157 :
158 92729 : if (s == 0)
159 : {
160 92708 : va_start (va, fmt);
161 92708 : s = va_format (s, fmt, &va);
162 92708 : va_end (va);
163 : }
164 :
165 92729 : if (syslog_enabled)
166 : {
167 6351 : u8 *l = 0;
168 6351 : if (unix_main.flags & (UNIX_FLAG_INTERACTIVE | UNIX_FLAG_NOSYSLOG))
169 : {
170 0 : int indent = 0;
171 0 : int with_colors = (unix_main.flags & UNIX_FLAG_NOCOLOR) == 0;
172 : u8 *fmt;
173 0 : if (with_colors)
174 : {
175 0 : l = format (l, "\x1b[%um", 90 + colors[level]);
176 0 : indent = vec_len (l);
177 : }
178 0 : fmt = format (0, "%%-%uU [%%-6U]: ", lm->max_class_name_length);
179 0 : vec_terminate_c_string (fmt);
180 0 : l = format (l, (char *) fmt, format_vlib_log_class, class,
181 : format_vlib_log_level, level);
182 0 : vec_free (fmt);
183 0 : indent = vec_len (l) - indent;
184 0 : if (with_colors)
185 0 : l = format (l, "\x1b[0m");
186 0 : l = format (l, "%U", format_indent, s, indent);
187 0 : fformat (stderr, "%v\n", l);
188 0 : fflush (stderr);
189 : }
190 : else
191 : {
192 6351 : l = format (l, "%U", format_vlib_log_class, class);
193 6351 : int prio = log_level_to_syslog_priority[level];
194 6351 : int is_term = vec_c_string_is_terminated (l) ? 1 : 0;
195 :
196 6351 : syslog (prio, "%.*s: %.*s", (int) vec_len (l), l,
197 6351 : (int) vec_len (s) - is_term, s);
198 : }
199 6351 : vec_free (l);
200 : }
201 :
202 92729 : if (log_enabled)
203 : {
204 92729 : e = vec_elt_at_index (lm->entries, lm->next);
205 92729 : vec_free (e->string);
206 92729 : e->level = level;
207 92729 : e->class = class;
208 92729 : e->string = s;
209 92729 : e->timestamp = t;
210 92729 : s = 0;
211 :
212 92729 : if (lm->add_to_elog)
213 : {
214 : ELOG_TYPE_DECLARE(ee) =
215 : {
216 : .format = "log-%s: %s",
217 : .format_args = "t4T4",
218 : .n_enum_strings = VLIB_LOG_N_LEVELS,
219 : .enum_strings = {
220 : "unknown",
221 : "emerg",
222 : "alert",
223 : "crit",
224 : "err",
225 : "warn",
226 : "notice",
227 : "info",
228 : "debug",
229 : "disabled",
230 : },
231 : };
232 : struct
233 : {
234 : u32 log_level;
235 : u32 string_index;
236 : } * ed;
237 0 : ed = ELOG_DATA (&vlib_global_main.elog_main, ee);
238 0 : ed->log_level = level;
239 0 : ed->string_index =
240 0 : elog_string (&vlib_global_main.elog_main, "%v%c", e->string, 0);
241 : }
242 :
243 92729 : lm->next = (lm->next + 1) % lm->size;
244 92729 : if (lm->size > lm->count)
245 91568 : lm->count++;
246 : }
247 :
248 92729 : vec_free (s);
249 : }
250 :
251 : static vlib_log_class_t
252 30202 : vlib_log_register_class_internal (char *class, char *subclass, u32 limit)
253 : {
254 30202 : vlib_log_main_t *lm = &log_main;
255 30202 : vlib_log_class_data_t *c = NULL;
256 : vlib_log_subclass_data_t *s;
257 : vlib_log_class_data_t *tmp;
258 30202 : vlib_log_class_config_t *cc = 0, *scc = 0;
259 : uword *p;
260 : u8 *str;
261 30202 : u32 length = 0;
262 :
263 30202 : if ((p = hash_get_mem (lm->config_index_by_name, class)))
264 0 : cc = vec_elt_at_index (lm->configs, p[0]);
265 :
266 30202 : str = format (0, "%s/%s%c", class, subclass, 0);
267 60404 : if ((p = hash_get_mem (lm->config_index_by_name, (char *) str)))
268 0 : scc = vec_elt_at_index (lm->configs, p[0]);
269 30202 : vec_free (str);
270 :
271 551480 : vec_foreach (tmp, lm->classes)
272 : {
273 529118 : if (vec_len (tmp->name) != strlen (class))
274 427809 : continue;
275 101309 : if (!memcmp (class, tmp->name, vec_len (tmp->name)))
276 : {
277 7840 : c = tmp;
278 7840 : break;
279 : }
280 : }
281 30202 : if (!c)
282 : {
283 22362 : vec_add2 (lm->classes, c, 1);
284 22362 : c->index = c - lm->classes;
285 22362 : c->name = format (0, "%s", class);
286 : }
287 30202 : length = vec_len (c->name);
288 :
289 30202 : vec_add2 (c->subclasses, s, 1);
290 30202 : s->index = s - c->subclasses;
291 30202 : s->name = subclass ? format (0, "%s", subclass) : 0;
292 :
293 30202 : if (scc && scc->rate_limit != ~0)
294 0 : s->rate_limit = scc->rate_limit;
295 30202 : else if (cc && cc->rate_limit != ~0)
296 0 : s->rate_limit = cc->rate_limit;
297 30202 : else if (limit)
298 1677 : s->rate_limit = limit;
299 : else
300 28525 : s->rate_limit = lm->default_rate_limit;
301 :
302 30202 : if (scc && scc->level != ~0)
303 0 : s->level = scc->level;
304 30202 : else if (cc && cc->level != ~0)
305 0 : s->level = cc->level;
306 : else
307 30202 : s->level = lm->default_log_level;
308 :
309 30202 : if (scc && scc->syslog_level != ~0)
310 0 : s->syslog_level = scc->syslog_level;
311 30202 : else if (cc && cc->syslog_level != ~0)
312 0 : s->syslog_level = cc->syslog_level;
313 : else
314 30202 : s->syslog_level = lm->default_syslog_log_level;
315 :
316 30202 : if (subclass)
317 15109 : length += 1 + vec_len (s->name);
318 30202 : if (length > lm->max_class_name_length)
319 1118 : lm->max_class_name_length = length;
320 30202 : return (c->index << 16) | (s->index);
321 : }
322 :
323 : vlib_log_class_t
324 28525 : vlib_log_register_class (char *class, char *subclass)
325 : {
326 28525 : return vlib_log_register_class_internal (class, subclass,
327 : 0 /* default rate limit */ );
328 : }
329 :
330 : vlib_log_class_t
331 1677 : vlib_log_register_class_rate_limit (char *class, char *subclass, u32 limit)
332 : {
333 1677 : return vlib_log_register_class_internal (class, subclass, limit);
334 : }
335 :
336 :
337 : u8 *
338 269852 : format_vlib_log_level (u8 * s, va_list * args)
339 : {
340 269852 : vlib_log_level_t i = va_arg (*args, vlib_log_level_t);
341 269852 : char *t = 0;
342 :
343 269852 : switch (i)
344 : {
345 : #define _(uc,lc) case VLIB_LOG_LEVEL_##uc: t = #lc; break;
346 269852 : foreach_vlib_log_level
347 : #undef _
348 0 : default:
349 0 : return format (s, "unknown");
350 : }
351 269852 : return format (s, "%s", t);
352 : }
353 :
354 : clib_error_t *
355 559 : vlib_log_init (vlib_main_t *vm)
356 : {
357 559 : vlib_log_main_t *lm = &log_main;
358 559 : vlib_log_class_registration_t *r = lm->registrations;
359 :
360 559 : gettimeofday (&lm->time_zero_timeval, 0);
361 559 : lm->time_zero = vlib_time_now (vm);
362 :
363 559 : vec_validate (lm->entries, lm->size);
364 :
365 9503 : while (r)
366 : {
367 8944 : r->class = vlib_log_register_class (r->class_name, r->subclass_name);
368 8944 : if (r->default_level)
369 0 : vlib_log_get_subclass_data (r->class)->level = r->default_level;
370 8944 : if (r->default_syslog_level)
371 0 : vlib_log_get_subclass_data (r->class)->syslog_level =
372 0 : r->default_syslog_level;
373 8944 : r = r->next;
374 : }
375 :
376 559 : r = lm->registrations;
377 9503 : while (r)
378 : {
379 8944 : vlib_log_debug (r->class, "initialized");
380 8944 : r = r->next;
381 : }
382 559 : return 0;
383 : }
384 :
385 : static clib_error_t *
386 1577 : show_log (vlib_main_t * vm,
387 : unformat_input_t * input, vlib_cli_command_t * cmd)
388 : {
389 1577 : clib_error_t *error = 0;
390 1577 : vlib_log_main_t *lm = &log_main;
391 : vlib_log_entry_t *e;
392 1577 : int i = last_log_entry ();
393 1577 : int count = lm->count;
394 : f64 time_offset;
395 :
396 1577 : time_offset = (f64) lm->time_zero_timeval.tv_sec
397 1577 : + (((f64) lm->time_zero_timeval.tv_usec) * 1e-6) - lm->time_zero;
398 :
399 271429 : while (count--)
400 : {
401 269852 : e = vec_elt_at_index (lm->entries, i);
402 269852 : vlib_cli_output (vm, "%U %-10U %-14U %v", format_time_float, NULL,
403 269852 : e->timestamp + time_offset, format_vlib_log_level,
404 269852 : e->level, format_vlib_log_class, e->class, e->string);
405 269852 : i = (i + 1) % lm->size;
406 : }
407 :
408 1577 : return error;
409 : }
410 :
411 : /* *INDENT-OFF* */
412 272887 : VLIB_CLI_COMMAND (cli_show_log, static) = {
413 : .path = "show logging",
414 : .short_help = "show logging",
415 : .function = show_log,
416 : };
417 : /* *INDENT-ON* */
418 :
419 : static clib_error_t *
420 0 : show_log_config (vlib_main_t * vm,
421 : unformat_input_t * input, vlib_cli_command_t * cmd)
422 : {
423 0 : clib_error_t *error = 0;
424 0 : vlib_log_main_t *lm = &log_main;
425 : vlib_log_class_data_t *c;
426 : vlib_log_subclass_data_t *sc;
427 :
428 0 : vlib_cli_output (vm, "%-20s %u entries", "Buffer Size:", lm->size);
429 0 : vlib_cli_output (vm, "Defaults:\n");
430 0 : vlib_cli_output (vm, "%-20s %U", " Log Level:",
431 : format_vlib_log_level, lm->default_log_level);
432 0 : vlib_cli_output (vm, "%-20s %U", " Syslog Log Level:",
433 : format_vlib_log_level, lm->default_syslog_log_level);
434 0 : vlib_cli_output (vm, "%-20s %u msgs/sec", " Rate Limit:",
435 : lm->default_rate_limit);
436 0 : vlib_cli_output (vm, "\n");
437 0 : vlib_cli_output (vm, "%-22s %-14s %-14s %s",
438 : "Class/Subclass", "Level", "Syslog Level", "Rate Limit");
439 :
440 :
441 0 : u8 *defstr = format (0, "default");
442 0 : vec_foreach (c, lm->classes)
443 : {
444 0 : vlib_cli_output (vm, "%v", c->name);
445 0 : vec_foreach (sc, c->subclasses)
446 : {
447 0 : vlib_cli_output (vm, " %-20v %-14U %-14U %d",
448 0 : sc->name ? sc->name : defstr,
449 0 : format_vlib_log_level, sc->level,
450 0 : format_vlib_log_level, sc->syslog_level,
451 : sc->rate_limit);
452 : }
453 : }
454 0 : vec_free (defstr);
455 :
456 0 : return error;
457 : }
458 :
459 : /* *INDENT-OFF* */
460 272887 : VLIB_CLI_COMMAND (cli_show_log_config, static) = {
461 : .path = "show logging configuration",
462 : .short_help = "show logging configuration",
463 : .function = show_log_config,
464 : };
465 : /* *INDENT-ON* */
466 :
467 : static clib_error_t *
468 57 : clear_log (vlib_main_t * vm,
469 : unformat_input_t * input, vlib_cli_command_t * cmd)
470 : {
471 57 : clib_error_t *error = 0;
472 57 : vlib_log_main_t *lm = &log_main;
473 : vlib_log_entry_t *e;
474 57 : int i = last_log_entry ();
475 57 : int count = lm->count;
476 :
477 363 : while (count--)
478 : {
479 306 : e = vec_elt_at_index (lm->entries, i);
480 306 : vec_free (e->string);
481 306 : i = (i + 1) % lm->size;
482 : }
483 :
484 57 : lm->count = 0;
485 57 : lm->next = 0;
486 57 : vlib_log_info (log_log.class, "log cleared");
487 57 : return error;
488 : }
489 :
490 : /* *INDENT-OFF* */
491 272887 : VLIB_CLI_COMMAND (cli_clear_log, static) = {
492 : .path = "clear logging",
493 : .short_help = "clear logging",
494 : .function = clear_log,
495 : };
496 : /* *INDENT-ON* */
497 :
498 : static uword
499 18 : unformat_vlib_log_level (unformat_input_t * input, va_list * args)
500 : {
501 18 : vlib_log_level_t *level = va_arg (*args, vlib_log_level_t *);
502 18 : u8 *level_str = NULL;
503 18 : uword rv = 1;
504 18 : if (unformat (input, "%s", &level_str))
505 : {
506 : #define _(uc, lc) \
507 : const char __##uc[] = #lc; \
508 : if (!strcmp ((const char *) level_str, __##uc)) \
509 : { \
510 : *level = VLIB_LOG_LEVEL_##uc; \
511 : rv = 1; \
512 : goto done; \
513 : }
514 18 : foreach_vlib_log_level;
515 0 : rv = 0;
516 : #undef _
517 : }
518 0 : done:
519 18 : vec_free (level_str);
520 18 : return rv;
521 : }
522 :
523 : static uword
524 18 : unformat_vlib_log_class (unformat_input_t * input, va_list * args)
525 : {
526 18 : vlib_log_class_data_t **class = va_arg (*args, vlib_log_class_data_t **);
527 18 : uword rv = 0;
528 18 : u8 *class_str = NULL;
529 18 : vlib_log_main_t *lm = &log_main;
530 18 : if (unformat (input, "%v", &class_str))
531 : {
532 : vlib_log_class_data_t *cdata;
533 429 : vec_foreach (cdata, lm->classes)
534 : {
535 429 : if (vec_is_equal (cdata->name, class_str))
536 : {
537 18 : *class = cdata;
538 18 : rv = 1;
539 18 : break;
540 : }
541 : }
542 : }
543 18 : vec_free (class_str);
544 18 : return rv;
545 : }
546 :
547 : static clib_error_t *
548 15 : set_log_class (vlib_main_t * vm,
549 : unformat_input_t * input, vlib_cli_command_t * cmd)
550 : {
551 15 : unformat_input_t _line_input, *line_input = &_line_input;
552 15 : clib_error_t *rv = NULL;
553 : int rate_limit;
554 15 : bool set_rate_limit = false;
555 15 : bool set_level = false;
556 15 : bool set_syslog_level = false;
557 : vlib_log_level_t level;
558 : vlib_log_level_t syslog_level;
559 :
560 : /* Get a line of input. */
561 15 : if (!unformat_user (input, unformat_line_input, line_input))
562 0 : return 0;
563 :
564 15 : vlib_log_class_data_t *class = NULL;
565 15 : if (!unformat (line_input, "%U", unformat_vlib_log_class, &class))
566 : {
567 0 : return clib_error_return (0, "unknown log class `%U'",
568 : format_unformat_error, line_input);
569 : }
570 30 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
571 : {
572 15 : if (unformat (line_input, "rate-limit %d", &rate_limit))
573 : {
574 0 : set_rate_limit = true;
575 : }
576 : else
577 15 : if (unformat
578 : (line_input, "level %U", unformat_vlib_log_level, &level))
579 : {
580 15 : set_level = true;
581 : }
582 : else
583 0 : if (unformat
584 : (line_input, "syslog-level %U", unformat_vlib_log_level,
585 : &syslog_level))
586 : {
587 0 : set_syslog_level = true;
588 : }
589 : else
590 : {
591 0 : return clib_error_return (0, "unknown input `%U'",
592 : format_unformat_error, line_input);
593 : }
594 : }
595 :
596 15 : if (set_level)
597 : {
598 : vlib_log_subclass_data_t *subclass;
599 39 : vec_foreach (subclass, class->subclasses)
600 : {
601 24 : subclass->level = level;
602 : }
603 : }
604 15 : if (set_syslog_level)
605 : {
606 : vlib_log_subclass_data_t *subclass;
607 0 : vec_foreach (subclass, class->subclasses)
608 : {
609 0 : subclass->syslog_level = syslog_level;
610 : }
611 : }
612 15 : if (set_rate_limit)
613 : {
614 : vlib_log_subclass_data_t *subclass;
615 0 : vec_foreach (subclass, class->subclasses)
616 : {
617 0 : subclass->rate_limit = rate_limit;
618 : }
619 : }
620 :
621 15 : return rv;
622 : }
623 :
624 : /* *INDENT-OFF* */
625 272887 : VLIB_CLI_COMMAND (cli_set_log, static) = {
626 : .path = "set logging class",
627 : .short_help = "set logging class <class> [rate-limit <int>] "
628 : "[level <level>] [syslog-level <level>]",
629 : .function = set_log_class,
630 : };
631 : /* *INDENT-ON* */
632 :
633 : static clib_error_t *
634 1 : set_log_unth_time (vlib_main_t * vm,
635 : unformat_input_t * input, vlib_cli_command_t * cmd)
636 : {
637 1 : unformat_input_t _line_input, *line_input = &_line_input;
638 1 : clib_error_t *rv = NULL;
639 : int unthrottle_time;
640 1 : vlib_log_main_t *lm = &log_main;
641 :
642 : /* Get a line of input. */
643 1 : if (!unformat_user (input, unformat_line_input, line_input))
644 0 : return 0;
645 :
646 2 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
647 : {
648 1 : if (unformat (line_input, "%d", &unthrottle_time))
649 1 : lm->unthrottle_time = unthrottle_time;
650 : else
651 0 : return clib_error_return (0, "unknown input `%U'",
652 : format_unformat_error, line_input);
653 : }
654 :
655 1 : return rv;
656 : }
657 :
658 : /* *INDENT-OFF* */
659 272887 : VLIB_CLI_COMMAND (cli_set_log_params, static) = {
660 : .path = "set logging unthrottle-time",
661 : .short_help = "set logging unthrottle-time <int>",
662 : .function = set_log_unth_time,
663 : };
664 : /* *INDENT-ON* */
665 :
666 : static clib_error_t *
667 1 : set_log_size (vlib_main_t * vm,
668 : unformat_input_t * input, vlib_cli_command_t * cmd)
669 : {
670 1 : unformat_input_t _line_input, *line_input = &_line_input;
671 1 : clib_error_t *rv = NULL;
672 : int size;
673 1 : vlib_log_main_t *lm = &log_main;
674 :
675 : /* Get a line of input. */
676 1 : if (!unformat_user (input, unformat_line_input, line_input))
677 0 : return 0;
678 :
679 2 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
680 : {
681 1 : if (unformat (line_input, "%d", &size))
682 : {
683 1 : lm->size = size;
684 1 : vec_validate (lm->entries, lm->size);
685 : }
686 : else
687 0 : return clib_error_return (0, "unknown input `%U'",
688 : format_unformat_error, line_input);
689 : }
690 :
691 1 : return rv;
692 : }
693 :
694 : /* *INDENT-OFF* */
695 272887 : VLIB_CLI_COMMAND (cli_set_log_size, static) = {
696 : .path = "set logging size",
697 : .short_help = "set logging size <int>",
698 : .function = set_log_size,
699 : };
700 : /* *INDENT-ON* */
701 :
702 : static uword
703 3 : unformat_vlib_log_subclass (unformat_input_t * input, va_list * args)
704 : {
705 3 : vlib_log_class_data_t *class = va_arg (*args, vlib_log_class_data_t *);
706 3 : vlib_log_subclass_data_t **subclass =
707 : va_arg (*args, vlib_log_subclass_data_t **);
708 3 : uword rv = 0;
709 3 : u8 *subclass_str = NULL;
710 3 : if (unformat (input, "%v", &subclass_str))
711 : {
712 : vlib_log_subclass_data_t *scdata;
713 3 : vec_foreach (scdata, class->subclasses)
714 : {
715 3 : if (vec_is_equal (scdata->name, subclass_str))
716 : {
717 3 : rv = 1;
718 3 : *subclass = scdata;
719 3 : break;
720 : }
721 : }
722 : }
723 3 : vec_free (subclass_str);
724 3 : return rv;
725 : }
726 :
727 : static clib_error_t *
728 3 : test_log_class_subclass (vlib_main_t * vm,
729 : unformat_input_t * input, vlib_cli_command_t * cmd)
730 : {
731 3 : unformat_input_t _line_input, *line_input = &_line_input;
732 : /* Get a line of input. */
733 3 : if (!unformat_user (input, unformat_line_input, line_input))
734 0 : return 0;
735 :
736 3 : vlib_log_class_data_t *class = NULL;
737 3 : vlib_log_subclass_data_t *subclass = NULL;
738 : vlib_log_level_t level;
739 3 : if (unformat (line_input, "%U", unformat_vlib_log_level, &level))
740 : {
741 3 : if (unformat (line_input, "%U", unformat_vlib_log_class, &class))
742 : {
743 3 : if (unformat
744 : (line_input, "%U", unformat_vlib_log_subclass, class,
745 : &subclass))
746 : {
747 3 : vlib_log (level,
748 3 : (class->index << 16) | (subclass->index), "%U",
749 : format_unformat_input, line_input);
750 : }
751 : else
752 : {
753 0 : return clib_error_return (0,
754 : "unknown log subclass near beginning of `%U'",
755 : format_unformat_error, line_input);
756 : }
757 : }
758 : else
759 : {
760 0 : return clib_error_return (0,
761 : "unknown log class near beginning of `%U'",
762 : format_unformat_error, line_input);
763 : }
764 : }
765 : else
766 : {
767 0 : return clib_error_return (0, "unknown log level near beginning of `%U'",
768 : format_unformat_error, line_input);
769 : }
770 3 : return 0;
771 : }
772 :
773 : /* *INDENT-OFF* */
774 272887 : VLIB_CLI_COMMAND (cli_test_log, static) = {
775 : .path = "test log",
776 : .short_help = "test log <level> <class> <subclass> <message>",
777 : .function = test_log_class_subclass,
778 : };
779 : /* *INDENT-ON* */
780 :
781 : static clib_error_t *
782 0 : log_config_class (vlib_main_t * vm, char *name, unformat_input_t * input)
783 : {
784 0 : vlib_log_main_t *lm = &log_main;
785 : vlib_log_class_config_t *cc, tmp;
786 : uword *p;
787 :
788 0 : if (lm->config_index_by_name == 0)
789 0 : lm->config_index_by_name = hash_create_string (0, sizeof (uword));
790 :
791 0 : p = hash_get_mem (lm->config_index_by_name, name);
792 :
793 0 : if (p)
794 0 : return clib_error_return (0, "logging class '%s' already configured",
795 : name);
796 :
797 0 : clib_memset_u8 (&tmp, 0xff, sizeof (vlib_log_class_config_t));
798 :
799 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
800 : {
801 0 : if (unformat (input, "level %U", unformat_vlib_log_level, &tmp.level))
802 : ;
803 0 : else if (unformat (input, "syslog-level %U", unformat_vlib_log_level,
804 : &tmp.syslog_level))
805 : ;
806 0 : else if (unformat (input, "rate-limit %u", &tmp.rate_limit))
807 : ;
808 : else
809 0 : return clib_error_return (0, "unknown input '%U'",
810 : format_unformat_error, input);
811 : }
812 :
813 0 : vec_add2 (lm->configs, cc, 1);
814 0 : clib_memcpy_fast (cc, &tmp, sizeof (vlib_log_class_config_t));
815 0 : cc->name = name;
816 0 : hash_set_mem (lm->config_index_by_name, name, cc - lm->configs);
817 0 : return 0;
818 : }
819 :
820 : static clib_error_t *
821 559 : log_config (vlib_main_t * vm, unformat_input_t * input)
822 : {
823 559 : vlib_log_main_t *lm = &log_main;
824 : unformat_input_t sub_input;
825 559 : u8 *class = 0;
826 :
827 559 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
828 : {
829 0 : if (unformat (input, "size %d", &lm->size))
830 0 : vec_validate (lm->entries, lm->size);
831 0 : else if (unformat (input, "unthrottle-time %d", &lm->unthrottle_time))
832 : ;
833 0 : else if (unformat (input, "default-log-level %U",
834 : unformat_vlib_log_level, &lm->default_log_level))
835 : ;
836 0 : else if (unformat (input, "default-syslog-log-level %U",
837 : unformat_vlib_log_level,
838 : &lm->default_syslog_log_level))
839 : ;
840 0 : else if (unformat (input, "add-to-elog"))
841 0 : lm->add_to_elog = 1;
842 0 : else if (unformat (input, "class %s %U", &class,
843 : unformat_vlib_cli_sub_input, &sub_input))
844 : {
845 : clib_error_t *err;
846 0 : err = log_config_class (vm, (char *) class, &sub_input);
847 0 : class = 0;
848 0 : unformat_free (&sub_input);
849 0 : if (err)
850 0 : return err;
851 : }
852 : else
853 : {
854 0 : return unformat_parse_error (input);
855 : }
856 : }
857 :
858 559 : return 0;
859 : }
860 :
861 7306 : VLIB_EARLY_CONFIG_FUNCTION (log_config, "logging");
862 :
863 : /*
864 : * fd.io coding-style-patch-verification: ON
865 : *
866 : * Local Variables:
867 : * eval: (c-set-style "gnu")
868 : * End:
869 : */
|