3 * Copyright (c) 2005-2008, The Android Open Source Project
4 * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
30 typedef struct FilterInfo_t {
33 struct FilterInfo_t *p_next;
37 log_priority global_pri;
39 log_print_format format;
42 static FilterInfo * filterinfo_new(const char *tag, log_priority pri)
45 p_ret = (FilterInfo *)calloc(1, sizeof(FilterInfo));
46 p_ret->mTag = strdup(tag);
52 static void filterinfo_free(FilterInfo *p_info)
63 * Note: also accepts 0-9 priorities
64 * returns DLOG_UNKNOWN if the character is unrecognized
66 static log_priority filter_char_to_pri (char c)
72 if (c >= '0' && c <= '9') {
73 if (c >= ('0'+DLOG_SILENT)) {
76 pri = (log_priority)(c - '0');
78 } else if (c == 'v') {
80 } else if (c == 'd') {
82 } else if (c == 'i') {
84 } else if (c == 'w') {
86 } else if (c == 'e') {
88 } else if (c == 'f') {
90 } else if (c == 's') {
92 } else if (c == '*') {
101 static char filter_pri_to_char (log_priority pri)
125 static log_priority filter_pri_for_tag(log_format *p_format, const char *tag)
127 FilterInfo *p_curFilter;
129 for (p_curFilter = p_format->filters; p_curFilter != NULL; p_curFilter = p_curFilter->p_next )
131 if (0 == strcmp(tag, p_curFilter->mTag))
133 if (p_curFilter->mPri == DLOG_DEFAULT) {
134 return p_format->global_pri;
136 return p_curFilter->mPri;
140 return p_format->global_pri;
144 void dump_filters(log_format *p_format)
148 for (p_fi = p_format->filters ; p_fi != NULL ; p_fi = p_fi->p_next) {
149 char cPri = filter_pri_to_char(p_fi->mPri);
150 if (p_fi->mPri == DLOG_DEFAULT) {
151 cPri = filter_pri_to_char(p_format->global_pri);
153 fprintf(stderr, "%s:%c\n", p_fi->mTag, cPri);
156 fprintf(stderr, "*:%c\n", filter_pri_to_char(p_format->global_pri));
161 * returns 1 if this log line should be printed based on its priority
162 * and tag, and 0 if it should not
164 int log_should_print_line (log_format *p_format, const char *tag, log_priority pri)
166 return pri >= filter_pri_for_tag(p_format, tag);
169 log_format *log_format_new()
173 p_ret = calloc(1, sizeof(log_format));
175 p_ret->global_pri = DLOG_SILENT;
176 p_ret->format = FORMAT_BRIEF;
181 void log_format_free(log_format *p_format)
183 FilterInfo *p_info, *p_info_old;
185 p_info = p_format->filters;
187 while (p_info != NULL) {
189 p_info = p_info->p_next;
190 filterinfo_free(p_info_old);
196 void log_set_print_format(log_format *p_format,log_print_format format)
198 p_format->format=format;
202 * Returns FORMAT_OFF on invalid string
204 log_print_format log_format_from_string(const char * formatString)
206 static log_print_format format;
208 if (strcmp(formatString, "brief") == 0)
209 format = FORMAT_BRIEF;
210 else if (strcmp(formatString, "process") == 0)
211 format = FORMAT_PROCESS;
212 else if (strcmp(formatString, "tag") == 0)
214 else if (strcmp(formatString, "thread") == 0)
215 format = FORMAT_THREAD;
216 else if (strcmp(formatString, "raw") == 0)
218 else if (strcmp(formatString, "time") == 0)
219 format = FORMAT_TIME;
220 else if (strcmp(formatString, "threadtime") == 0)
221 format = FORMAT_THREADTIME;
222 else if (strcmp(formatString, "long") == 0)
223 format = FORMAT_LONG;
224 else format = FORMAT_OFF;
230 * filterExpression: a single filter expression
233 * returns 0 on success and -1 on invalid expression
235 * Assumes single threaded execution
237 int log_add_filter_rule(log_format *p_format,
238 const char *filterExpression)
240 size_t tagNameLength;
241 log_priority pri = DLOG_DEFAULT;
243 tagNameLength = strcspn(filterExpression, ":");
245 if (tagNameLength == 0) {
249 if(filterExpression[tagNameLength] == ':') {
250 pri = filter_char_to_pri(filterExpression[tagNameLength+1]);
252 if (pri == DLOG_UNKNOWN) {
257 if(0 == strncmp("*", filterExpression, tagNameLength)) {
258 /* This filter expression refers to the global filter
259 * The default level for this is DEBUG if the priority
262 if (pri == DLOG_DEFAULT) {
266 p_format->global_pri = pri;
268 /* for filter expressions that don't refer to the global
269 * filter, the default is verbose if the priority is unspecified
271 if (pri == DLOG_DEFAULT) {
276 tagName = strndup(filterExpression, tagNameLength);
278 FilterInfo *p_fi = filterinfo_new(tagName, pri);
281 p_fi->p_next = p_format->filters;
282 p_format->filters = p_fi;
291 * filterString: a comma/whitespace-separated set of filter expressions
295 * returns 0 on success and -1 on invalid expression
297 * Assumes single threaded execution
300 int log_add_filter_string(log_format *p_format,
301 const char *filterString)
303 char *filterStringCopy = strdup (filterString);
304 char *p_cur = filterStringCopy;
308 while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
309 /* ignore whitespace-only entries */
310 if(p_ret[0] != '\0') {
311 err = log_add_filter_rule(p_format, p_ret);
319 free (filterStringCopy);
322 free (filterStringCopy);
326 static inline char * strip_end(char *str)
328 char *end = str + strlen(str) - 1;
330 while (end >= str && isspace(*end))
336 * Splits a wire-format buffer into an LogEntry
337 * entry allocated by caller. Pointers will point directly into buf
339 * Returns 0 on success and -1 on invalid wire format (entry will be
340 * in unspecified state)
342 int log_process_log_buffer(struct logger_entry *buf,log_entry *entry)
346 entry->tv_sec = buf->sec;
347 entry->tv_nsec = buf->nsec;
348 entry->pid = buf->pid;
349 entry->tid = buf->tid;
351 if (buf->msg[0] < 0 || buf->msg[0] > DLOG_SILENT) { /* char can be signed too */
353 /* There is no tag in this message - which is an error, but it might
354 * happen when sombody redirects stdout/err to /dev/log_*.
356 * Pick ERROR priority as this shouldn't happen.
358 entry->priority = DLOG_ERROR;
359 entry->tag = "[NO TAG]";
360 entry->messageLen = buf->len;
361 entry->message = buf->msg;
363 entry->priority = buf->msg[0];
364 entry->tag = buf->msg + 1;
365 tag_len = strlen(entry->tag);
366 entry->messageLen = buf->len - tag_len - 3;
367 entry->message = entry->tag + tag_len + 1;
374 * Formats a log message into a buffer
376 * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer
377 * If return value != defaultBuffer, caller must call free()
378 * Returns NULL on malloc error
380 char *log_format_log_line (
381 log_format *p_format,
383 size_t defaultBufferSize,
384 const log_entry *entry,
387 #if defined(HAVE_LOCALTIME_R)
392 char prefixBuf[128], suffixBuf[128];
394 int prefixSuffixIsHeaderFooter = 0;
397 priChar = filter_pri_to_char(entry->priority);
400 * Get the current date/time in pretty form
402 * It's often useful when examining a log with "less" to jump to
403 * a specific point in the file by searching for the date/time stamp.
404 * For this reason it's very annoying to have regexp meta characters
405 * in the time stamp. Don't use forward slashes, parenthesis,
406 * brackets, asterisks, or other special chars here.
408 #if defined(HAVE_LOCALTIME_R)
409 ptm = localtime_r(&(entry->tv_sec), &tmBuf);
411 ptm = localtime(&(entry->tv_sec));
413 strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
416 * Construct a buffer containing the log header and log message.
418 size_t prefixLen, suffixLen;
420 switch (p_format->format) {
422 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
423 "%c/%-8s: ", priChar, entry->tag);
424 strcpy(suffixBuf, "\n"); suffixLen = 1;
427 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
428 "%c(%5d) ", priChar, (int)entry->pid);
429 suffixLen = snprintf(suffixBuf, sizeof(suffixBuf),
430 " (%s)\n", entry->tag);
433 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
434 "%c(%5d:%5d) ", priChar, (int)entry->pid, (int)entry->tid);
435 strcpy(suffixBuf, "\n");
441 strcpy(suffixBuf, "\n");
445 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
446 "%s.%03ld %c/%-8s(%5d): ", timeBuf, entry->tv_nsec / 1000000,
447 priChar, entry->tag, (int)entry->pid);
448 strcpy(suffixBuf, "\n");
451 case FORMAT_THREADTIME:
452 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
453 "%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000,
454 (int)entry->pid, (int)entry->tid, priChar, entry->tag);
455 strcpy(suffixBuf, "\n");
459 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
460 "[ %s.%03ld %5d:%5d %c/%-8s ]\n",
461 timeBuf, entry->tv_nsec / 1000000, (int)entry->pid,
462 (int)entry->tid, priChar, entry->tag);
463 strcpy(suffixBuf, "\n\n");
465 prefixSuffixIsHeaderFooter = 1;
469 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
470 "%c/%-8s(%5d): ", priChar, entry->tag, (int)entry->pid);
471 strcpy(suffixBuf, "\n");
475 /* snprintf has a weird return value. It returns what would have been
476 * written given a large enough buffer. In the case that the prefix is
477 * longer then our buffer(128), it messes up the calculations below
478 * possibly causing heap corruption. To avoid this we double check and
479 * set the length at the maximum (size minus null byte)
481 if(prefixLen >= sizeof(prefixBuf))
482 prefixLen = sizeof(prefixBuf) - 1;
483 if(suffixLen >= sizeof(suffixBuf))
484 suffixLen = sizeof(suffixBuf) - 1;
486 /* the following code is tragically unreadable */
493 if (prefixSuffixIsHeaderFooter) {
494 /* we're just wrapping message with a header/footer */
500 /* The line-end finding here must match the line-end finding
501 * in for ( ... numLines...) loop below
503 while (pm < (entry->message + entry->messageLen)) {
504 if (*pm++ == '\n') numLines++;
506 /* plus one line for anything not newline-terminated at the end */
507 if (pm > entry->message && *(pm-1) != '\n') numLines++;
510 /* this is an upper bound--newlines in message may be counted
513 bufferSize = (numLines * (prefixLen + suffixLen)) + entry->messageLen + 1;
515 if (defaultBufferSize >= bufferSize) {
518 ret = (char *)malloc(bufferSize);
525 ret[0] = '\0'; /* to start strcat off */
530 if (prefixSuffixIsHeaderFooter) {
531 strcat(p, prefixBuf);
533 strncat(p, entry->message, entry->messageLen);
534 p += entry->messageLen;
535 strcat(p, suffixBuf);
538 while (pm < (entry->message + entry->messageLen)) {
539 const char *lineStart;
544 /* Find the next end-of-line in message */
545 while (pm < (entry->message + entry->messageLen)
546 && *pm != '\n') pm++;
547 lineLen = pm - lineStart;
549 strcat(p, prefixBuf);
551 strncat(p, lineStart, lineLen);
553 strcat(p, suffixBuf);
561 if (p_outLength != NULL) {
562 *p_outLength = p - ret;
569 * Either print or do not print log line, based on filter
571 * Returns count bytes written
574 int log_print_log_line(
575 log_format *p_format,
577 const log_entry *entry)
580 char defaultBuffer[512];
581 char *outBuffer = NULL;
584 outBuffer = log_format_log_line(p_format,
585 defaultBuffer, sizeof(defaultBuffer), entry, &totalLen);
591 ret = write(fd, outBuffer, totalLen);
592 } while (ret < 0 && errno == EINTR);
595 fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
600 if (((size_t)ret) < totalLen) {
601 fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", ret,
607 if (outBuffer != defaultBuffer) {
616 void logprint_run_tests()
620 log_format *p_format;
622 p_format = log_format_new();
624 fprintf(stderr, "running tests\n");
628 log_add_filter_rule(p_format,"*:i");
630 assert (DLOG_INFO == filter_pri_for_tag(p_format, "random"));
631 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) == 0);
632 log_add_filter_rule(p_format, "*");
633 assert (DLOG_DEBUG == filter_pri_for_tag(p_format, "random"));
634 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) > 0);
635 log_add_filter_rule(p_format, "*:v");
636 assert (DLOG_VERBOSE == filter_pri_for_tag(p_format, "random"));
637 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) > 0);
638 log_add_filter_rule(p_format, "*:i");
639 assert (DLOG_INFO == filter_pri_for_tag(p_format, "random"));
640 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) == 0);
642 log_add_filter_rule(p_format, "random");
643 assert (DLOG_VERBOSE == filter_pri_for_tag(p_format, "random"));
644 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) > 0);
645 log_add_filter_rule(p_format, "random:v");
646 assert (DLOG_VERBOSE == filter_pri_for_tag(p_format, "random"));
647 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) > 0);
648 log_add_filter_rule(p_format, "random:d");
649 assert (DLOG_DEBUG == filter_pri_for_tag(p_format, "random"));
650 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) > 0);
651 log_add_filter_rule(p_format, "random:w");
652 assert (DLOG_WARN == filter_pri_for_tag(p_format, "random"));
653 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) == 0);
655 log_add_filter_rule(p_format, "crap:*");
656 assert (DLOG_VERBOSE== filter_pri_for_tag(p_format, "crap"));
657 assert(log_should_print_line(p_format, "crap", DLOG_VERBOSE) > 0);
659 /* invalid expression */
660 err = log_add_filter_rule(p_format, "random:z");
662 assert (DLOG_WARN == filter_pri_for_tag(p_format, "random"));
663 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) == 0);
666 err = log_add_filter_string(p_format, " ");
668 assert(DLOG_WARN == filter_pri_for_tag(p_format, "random"));
670 /* note trailing space */
671 err = log_add_filter_string(p_format, "*:s random:d ");
673 assert(DLOG_DEBUG == filter_pri_for_tag(p_format, "random"));
675 err = log_add_filter_string(p_format, "*:s random:z");
678 log_format_free(p_format);
680 fprintf(stderr, "tests complete\n");