bslsink.c (9570B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * Broadcom System Log Sinks 8 */ 9 10 #include <sal/core/libc.h> 11 #include <sal/core/time.h> 12 #include <sal/core/thread.h> 13 #include <sal/appl/io.h> 14 #include <shared/bsl.h> 15 #include <shared/bslnames.h> 16 #include <appl/diag/bslenable.h> 17 #include <appl/diag/bslsink.h> 18 19 /* List of output sinks */ 20 static bslsink_sink_t *bslsink_sinks = NULL; 21 22 /* System start time */ 23 static sal_time_t init_time; 24 25 /* Append string value to prefix */ 26 static int 27 add_string(char *buf, int max, const char *str) 28 { 29 return sal_snprintf(buf, max, "%s", str); 30 } 31 32 /* Append decimal integer to prefix */ 33 static int 34 add_dval(char *buf, int max, int dval) 35 { 36 return sal_snprintf(buf, max, "%d", dval); 37 } 38 39 /* Append unsigned decimal integer to prefix */ 40 static int 41 add_uval(char *buf, int max, uint32 uval) 42 { 43 return sal_snprintf(buf, max, "%u", uval); 44 } 45 46 /* Append minutes/seconds to prefix */ 47 static int 48 add_msval(char *buf, int max, int msval) 49 { 50 return sal_snprintf(buf, max, ":%02d", msval); 51 } 52 53 /* Append time stamp to prefix */ 54 static int 55 add_timetamp(char *buf, int max) 56 { 57 int len = 0; 58 sal_time_t now = sal_time() - init_time; 59 unsigned long hrs, mins, secs; 60 61 secs = now % 60; 62 now = now / 60; 63 mins = now % 60; 64 hrs = now / 60; 65 66 len += add_dval(&buf[len], max-len, hrs); 67 len += add_msval(&buf[len], max-len, mins); 68 len += add_msval(&buf[len], max-len, secs); 69 70 return len; 71 } 72 73 /* Append micro second timestamp to prefix */ 74 static int 75 add_hi_res_timestamp(char *buf, int max) 76 { 77 int len = 0; 78 unsigned long time = (unsigned long)(sal_time_usecs()); 79 80 len += add_uval(buf, max, time); 81 82 return len; 83 } 84 85 /* Append thread name to prefix */ 86 static int 87 add_thread_name(char *buf, int max, const char *str) 88 { 89 char tname[SAL_THREAD_NAME_MAX_LEN], *name; 90 91 name = sal_thread_name(sal_thread_self(), tname, SAL_THREAD_NAME_MAX_LEN); 92 93 if (name == NULL) { 94 name = "unknown thread"; 95 } 96 97 return add_string(buf, max, name); 98 } 99 100 /* 101 * Prefix formatting function 102 * 103 * Formats log prefix string based on meta data contents and 104 * configuration string. 105 * 106 * The configuration string is similar to a printf format string, 107 * except that is uses a different set of format specifiers. 108 * 109 * %F - function name 110 * %f - file name 111 * %l - line number 112 * %u - unit number 113 * %p - port number 114 * %x - xtra parameter 115 * %L - layer of this log message source 116 * %S - source of this log message 117 * %s - severity level (string value) of this log message 118 * %t - time stamp (based seconds since system start) 119 * %T - high resolution timestamp (micro seconds) 120 * %P - process or thread name 121 */ 122 static int 123 format_prefix(char *buf, int max, const char *prefix_format, 124 bsl_meta_t *meta, int path_offset) 125 { 126 int len = 0; 127 const char *str = NULL; 128 const char *cp = prefix_format; 129 130 while (len < max) { 131 if (*cp != '%') { 132 buf[len++] = *cp; 133 if (*cp == 0) { 134 return len; 135 } 136 cp++; 137 continue; 138 } 139 cp++; 140 switch (*cp) { 141 case 'F': 142 str = meta->func; 143 if (str == NULL) { 144 str = "<nofunc>"; 145 } 146 len += add_string(&buf[len], max-len, str); 147 cp++; 148 break; 149 case 'f': 150 str = "<nofile>"; 151 if (meta->file != NULL) { 152 str = &meta->file[path_offset]; 153 } 154 len += add_string(&buf[len], max-len, str); 155 cp++; 156 break; 157 case 'l': 158 len += add_dval(&buf[len], max-len, meta->line); 159 cp++; 160 break; 161 case 'u': 162 if (meta->unit < 0) { 163 len += add_string(&buf[len], max-len, "<nounit>"); 164 } else { 165 len += add_dval(&buf[len], max-len, meta->unit); 166 } 167 cp++; 168 break; 169 case 'p': 170 len += add_dval(&buf[len], max-len, meta->port); 171 cp++; 172 break; 173 case 'x': 174 len += add_dval(&buf[len], max-len, meta->xtra); 175 cp++; 176 break; 177 case 'L': 178 str = bsl_layer2str(meta->layer); 179 len += add_string(&buf[len], max-len, str); 180 cp++; 181 break; 182 case 'S': 183 str = bsl_source2str(meta->source); 184 len += add_string(&buf[len], max-len, str); 185 cp++; 186 break; 187 case 's': 188 str = bsl_severity2str(meta->severity); 189 len += add_string(&buf[len], max-len, str); 190 cp++; 191 break; 192 case 't': 193 len += add_timetamp(&buf[len], max-len); 194 cp++; 195 break; 196 case 'T': 197 len += add_hi_res_timestamp(&buf[len], max-len); 198 cp++; 199 break; 200 case 'P': 201 len += add_thread_name(&buf[len], max-len, str); 202 cp++; 203 break; 204 default: 205 /* Bad format */ 206 return len; 207 } 208 } 209 return len; 210 } 211 212 /* 213 * Check that severity is within a specific range 214 */ 215 static int 216 severity_in_range(bslsink_severity_range_t *range, bsl_severity_t val) 217 { 218 if (range == NULL) { 219 return 0; 220 } 221 return (val >= range->min && val <= range->max); 222 } 223 224 /* 225 * Convenience function for printing prefix string 226 */ 227 static int 228 sink_printf(bslsink_sink_t *sink, const char *format, ...) 229 { 230 int rv; 231 va_list args; 232 233 va_start(args, format); 234 rv = sink->vfprintf(sink->file, format, args); 235 va_end(args); 236 237 return rv; 238 } 239 240 /* 241 * Additional filtering based on meta data 242 */ 243 int 244 bslsink_out(bslsink_sink_t *sink, bsl_meta_t *meta, 245 const char *format, va_list args) 246 { 247 int unit; 248 bsl_severity_t sev = meta->severity; 249 char buf[BSLSINK_PREFIX_MAX]; 250 251 if (sink->check && sink->check(meta) == 0) { 252 return 0; 253 } 254 if (!severity_in_range(&sink->enable_range, sev)) { 255 return 0; 256 } 257 if (meta->source == bslSourceEcho && 258 (sink->options & BSLSINK_OPT_NO_ECHO)) { 259 return 0; 260 } 261 unit = meta->unit; 262 if (unit == BSL_UNIT_UNKNOWN) { 263 /* Map to pseudo-unit to allow proper filtering */ 264 unit = BSLSINK_UNIT_UNKNOWN; 265 } 266 if (unit >= 0 && unit < BSLSINK_MAX_NUM_UNITS) { 267 if (SHR_BITGET(sink->units, unit) == 0) { 268 return 0; 269 } 270 } 271 if (meta->port >= 0 && meta->port < BSLSINK_MAX_NUM_PORTS) { 272 if (SHR_BITGET(sink->ports, meta->port) == 0) { 273 return 0; 274 } 275 } 276 if (meta->xtra >= 0 && sink->xtra >= 0) { 277 if (meta->xtra != sink->xtra) { 278 return 0; 279 } 280 } 281 if ((meta->source == bslSourceShell || meta->source == bslSourceEcho) && 282 (sink->options & BSLSINK_OPT_SHELL_PREFIX) == 0) { 283 /* Skip prefix for shell output */ 284 } else if (severity_in_range(&sink->prefix_range, sev)) { 285 if (meta->options & BSL_META_OPT_START) { 286 format_prefix(buf, sizeof(buf)-1, sink->prefix_format, 287 meta, sink->path_offset); 288 buf[sizeof(buf)-1] = 0; 289 sink_printf(sink, buf); 290 if (meta->options & BSL_META_OPT_PFX_NL) { 291 sink_printf(sink, "\n"); 292 } 293 } 294 } 295 return sink->vfprintf(sink->file, format, args); 296 } 297 298 void 299 bslsink_sink_t_init(bslsink_sink_t *sink) 300 { 301 sal_memset(sink, 0, sizeof(*sink)); 302 SHR_BITSET_RANGE(sink->units, 0, BSLSINK_MAX_NUM_UNITS); 303 SHR_BITSET_RANGE(sink->ports, 0, BSLSINK_MAX_NUM_PORTS); 304 sink->xtra = -1; 305 #ifndef BSLSINK_FULL_FILE_PATH 306 { 307 char *ptr, *file = BSL_FILE; 308 309 /* Calculate position of SDK root in BSL_FILE (__FILE__) */ 310 ptr = sal_strstr(file, "src/appl/diag/bslsink.c"); 311 if (ptr != NULL) { 312 sink->path_offset = PTR_TO_UINTPTR(ptr) - PTR_TO_UINTPTR(file); 313 } 314 } 315 #endif 316 } 317 318 int 319 bslsink_sink_cleanup(bslsink_sink_t *sink) 320 { 321 if (sink->cleanup) { 322 sink->cleanup(sink); 323 } 324 return 0; 325 } 326 327 int 328 bslsink_sink_add(bslsink_sink_t *new_sink) 329 { 330 bslsink_sink_t *sink; 331 int sink_id = 0; 332 333 if (bslsink_sinks == NULL) { 334 /* First sink */ 335 bslsink_sinks = new_sink; 336 new_sink->sink_id = sink_id; 337 return sink_id; 338 } 339 sink = bslsink_sinks; 340 sink_id++; 341 while (sink->next != NULL) { 342 sink = sink->next; 343 sink_id++; 344 } 345 sink->next = new_sink; 346 new_sink->sink_id = sink_id; 347 return sink_id; 348 } 349 350 bslsink_sink_t * 351 bslsink_sink_find(const char *name) 352 { 353 bslsink_sink_t *sink = bslsink_sinks; 354 355 if (name == NULL) { 356 return NULL; 357 } 358 359 while (sink != NULL) { 360 if (sal_strcmp(name, sink->name) == 0) { 361 return sink; 362 } 363 sink = sink->next; 364 } 365 return NULL; 366 } 367 368 bslsink_sink_t * 369 bslsink_sink_find_by_id(int sink_id) 370 { 371 bslsink_sink_t *sink = bslsink_sinks; 372 373 while (sink != NULL) { 374 if (sink->sink_id == sink_id) { 375 return sink; 376 } 377 sink = sink->next; 378 } 379 return NULL; 380 } 381 382 int 383 bslsink_cleanup(void) 384 { 385 bslsink_sink_t *sink = bslsink_sinks; 386 387 while (sink != NULL) { 388 bslsink_sink_cleanup(sink); 389 sink = sink->next; 390 } 391 return 0; 392 } 393 394 int 395 bslsink_init(void) 396 { 397 bslsink_sinks = NULL; 398 init_time = sal_time(); 399 400 return 0; 401 }