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