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)
49 p_ret = (FilterInfo *)calloc(1, sizeof(FilterInfo));
53 p_ret->mTag = strdup(tag);
59 static void filterinfo_free(FilterInfo *p_info)
70 * Note: also accepts 0-9 priorities
71 * returns DLOG_UNKNOWN if the character is unrecognized
73 static log_priority filter_char_to_pri (char c)
79 if (c >= '0' && c <= '9') {
80 if (c >= ('0'+DLOG_SILENT)) {
83 pri = (log_priority)(c - '0');
85 } else if (c == 'v') {
87 } else if (c == 'd') {
89 } else if (c == 'i') {
91 } else if (c == 'w') {
93 } else if (c == 'e') {
95 } else if (c == 'f') {
97 } else if (c == 's') {
99 } else if (c == '*') {
108 static char filter_pri_to_char (log_priority pri)
132 static log_priority filter_pri_for_tag(log_format *p_format, const char *tag)
134 FilterInfo *p_curFilter;
136 for (p_curFilter = p_format->filters; p_curFilter != NULL; p_curFilter = p_curFilter->p_next )
138 if (0 == strcmp(tag, p_curFilter->mTag))
140 if (p_curFilter->mPri == DLOG_DEFAULT) {
141 return p_format->global_pri;
143 return p_curFilter->mPri;
147 return p_format->global_pri;
151 void dump_filters(log_format *p_format)
155 for (p_fi = p_format->filters ; p_fi != NULL ; p_fi = p_fi->p_next) {
156 char cPri = filter_pri_to_char(p_fi->mPri);
157 if (p_fi->mPri == DLOG_DEFAULT) {
158 cPri = filter_pri_to_char(p_format->global_pri);
160 fprintf(stderr, "%s:%c\n", p_fi->mTag, cPri);
163 fprintf(stderr, "*:%c\n", filter_pri_to_char(p_format->global_pri));
168 * returns 1 if this log line should be printed based on its priority
169 * and tag, and 0 if it should not
171 int log_should_print_line (log_format *p_format, const char *tag, log_priority pri)
173 return pri >= filter_pri_for_tag(p_format, tag);
176 log_format *log_format_new()
180 p_ret = calloc(1, sizeof(log_format));
184 p_ret->global_pri = DLOG_SILENT;
185 p_ret->format = FORMAT_BRIEF;
190 void log_format_free(log_format *p_format)
192 FilterInfo *p_info, *p_info_old;
194 p_info = p_format->filters;
196 while (p_info != NULL) {
198 p_info = p_info->p_next;
199 filterinfo_free(p_info_old);
205 void log_set_print_format(log_format *p_format,log_print_format format)
207 p_format->format=format;
211 * Returns FORMAT_OFF on invalid string
213 log_print_format log_format_from_string(const char * formatString)
215 static log_print_format format;
217 if (strcmp(formatString, "brief") == 0)
218 format = FORMAT_BRIEF;
219 else if (strcmp(formatString, "process") == 0)
220 format = FORMAT_PROCESS;
221 else if (strcmp(formatString, "tag") == 0)
223 else if (strcmp(formatString, "thread") == 0)
224 format = FORMAT_THREAD;
225 else if (strcmp(formatString, "raw") == 0)
227 else if (strcmp(formatString, "time") == 0)
228 format = FORMAT_TIME;
229 else if (strcmp(formatString, "threadtime") == 0)
230 format = FORMAT_THREADTIME;
231 else if (strcmp(formatString, "dump") == 0)
232 format = FORMAT_DUMP;
233 else if (strcmp(formatString, "long") == 0)
234 format = FORMAT_LONG;
235 else format = FORMAT_OFF;
241 * filterExpression: a single filter expression
244 * returns 0 on success and -1 on invalid expression
246 * Assumes single threaded execution
248 int log_add_filter_rule(log_format *p_format,
249 const char *filterExpression)
251 size_t tagNameLength;
252 log_priority pri = DLOG_DEFAULT;
254 tagNameLength = strcspn(filterExpression, ":");
260 if (tagNameLength == 0) {
264 if(filterExpression[tagNameLength] == ':') {
265 pri = filter_char_to_pri(filterExpression[tagNameLength+1]);
267 if (pri == DLOG_UNKNOWN) {
272 if(0 == strncmp("*", filterExpression, tagNameLength)) {
273 /* This filter expression refers to the global filter
274 * The default level for this is DEBUG if the priority
277 if (pri == DLOG_DEFAULT) {
281 p_format->global_pri = pri;
283 /* for filter expressions that don't refer to the global
284 * filter, the default is verbose if the priority is unspecified
286 if (pri == DLOG_DEFAULT) {
291 tagName = strndup(filterExpression, tagNameLength);
293 FilterInfo *p_fi = filterinfo_new(tagName, pri);
298 p_fi->p_next = p_format->filters;
299 p_format->filters = p_fi;
308 * filterString: a comma/whitespace-separated set of filter expressions
312 * returns 0 on success and -1 on invalid expression
314 * Assumes single threaded execution
317 int log_add_filter_string(log_format *p_format,
318 const char *filterString)
320 char *filterStringCopy = strdup (filterString);
321 char *p_cur = filterStringCopy;
325 while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
326 /* ignore whitespace-only entries */
327 if(p_ret[0] != '\0') {
328 err = log_add_filter_rule(p_format, p_ret);
336 free (filterStringCopy);
339 free (filterStringCopy);
343 static inline char * strip_end(char *str)
345 char *end = str + strlen(str) - 1;
347 while (end >= str && isspace(*end))
353 * Splits a wire-format buffer into an LogEntry
354 * entry allocated by caller. Pointers will point directly into buf
356 * Returns 0 on success and -1 on invalid wire format (entry will be
357 * in unspecified state)
359 int log_process_log_buffer(struct logger_entry *buf, log_entry *entry)
361 int i, start = -1, end = -1;
364 fprintf(stderr, "Entry too small\n");
368 entry->tv_sec = buf->sec;
369 entry->tv_nsec = buf->nsec;
370 entry->pid = buf->pid;
371 entry->tid = buf->tid;
373 entry->priority = buf->msg[0];
374 if (entry->priority < 0 || entry->priority > DLOG_SILENT) {
375 fprintf(stderr, "Wrong priority message\n");
379 entry->tag = buf->msg + 1;
380 if (!strlen(entry->tag)) {
381 fprintf(stderr, "No tag message\n");
385 for (i = 0; i < buf->len; i++) {
386 if (buf->msg[i] == '\0') {
396 fprintf(stderr, "Malformed log message\n");
401 buf->msg[end] = '\0';
404 entry->message = buf->msg + start;
405 entry->messageLen = end - start;
411 * Formats a log message into a buffer
413 * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer
414 * If return value != defaultBuffer, caller must call free()
415 * Returns NULL on malloc error
417 char *log_format_log_line (
418 log_format *p_format,
420 size_t defaultBufferSize,
421 const log_entry *entry,
424 #if defined(HAVE_LOCALTIME_R)
428 char timeBuf[32], tzBuf[16];
429 char prefixBuf[128], suffixBuf[128];
431 int prefixSuffixIsHeaderFooter = 0;
434 priChar = filter_pri_to_char(entry->priority);
437 * Get the current date/time in pretty form
439 * It's often useful when examining a log with "less" to jump to
440 * a specific point in the file by searching for the date/time stamp.
441 * For this reason it's very annoying to have regexp meta characters
442 * in the time stamp. Don't use forward slashes, parenthesis,
443 * brackets, asterisks, or other special chars here.
445 #if defined(HAVE_LOCALTIME_R)
446 ptm = localtime_r(&(entry->tv_sec), &tmBuf);
448 ptm = localtime(&(entry->tv_sec));
453 strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
454 strftime(tzBuf, sizeof(tzBuf), "%z", ptm);
457 * Construct a buffer containing the log header and log message.
459 size_t prefixLen, suffixLen;
461 switch (p_format->format) {
463 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
464 "%c/%-8s: ", priChar, entry->tag);
465 strcpy(suffixBuf, "\n"); suffixLen = 1;
468 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
469 "%c(%5d) ", priChar, (int)entry->pid);
470 suffixLen = snprintf(suffixBuf, sizeof(suffixBuf),
471 " (%s)\n", entry->tag);
474 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
475 "%c(%5d:%5d) ", priChar, (int)entry->pid, (int)entry->tid);
476 strcpy(suffixBuf, "\n");
482 strcpy(suffixBuf, "\n");
486 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
487 "%s.%03ld%s %c/%-8s(%5d): ", timeBuf, entry->tv_nsec / 1000000,
488 tzBuf, priChar, entry->tag, (int)entry->pid);
489 strcpy(suffixBuf, "\n");
492 case FORMAT_THREADTIME:
493 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
494 "%s.%03ld%s %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000,
495 tzBuf, (int)entry->pid, (int)entry->tid, priChar, entry->tag);
496 strcpy(suffixBuf, "\n");
500 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
501 "%s.%03ld%s %5d %5d %c %-8s: ", timeBuf,
502 entry->tv_nsec / 1000000, tzBuf, (int)entry->pid,
503 (int)entry->tid, priChar, entry->tag);
504 strcpy(suffixBuf, "\n");
508 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
509 "[ %s.%03ld %5d:%5d %c/%-8s ]\n",
510 timeBuf, entry->tv_nsec / 1000000, (int)entry->pid,
511 (int)entry->tid, priChar, entry->tag);
512 strcpy(suffixBuf, "\n\n");
514 prefixSuffixIsHeaderFooter = 1;
518 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
519 "%c/%-8s(%5d): ", priChar, entry->tag, (int)entry->pid);
520 strcpy(suffixBuf, "\n");
524 /* snprintf has a weird return value. It returns what would have been
525 * written given a large enough buffer. In the case that the prefix is
526 * longer then our buffer(128), it messes up the calculations below
527 * possibly causing heap corruption. To avoid this we double check and
528 * set the length at the maximum (size minus null byte)
530 if(prefixLen >= sizeof(prefixBuf))
531 prefixLen = sizeof(prefixBuf) - 1;
532 if(suffixLen >= sizeof(suffixBuf))
533 suffixLen = sizeof(suffixBuf) - 1;
535 /* the following code is tragically unreadable */
542 if (prefixSuffixIsHeaderFooter) {
543 /* we're just wrapping message with a header/footer */
549 /* The line-end finding here must match the line-end finding
550 * in for ( ... numLines...) loop below
552 while (pm < (entry->message + entry->messageLen)) {
553 if (*pm++ == '\n') numLines++;
555 /* plus one line for anything not newline-terminated at the end */
556 if (pm > entry->message && *(pm-1) != '\n') numLines++;
559 /* this is an upper bound--newlines in message may be counted
562 bufferSize = (numLines * (prefixLen + suffixLen)) + entry->messageLen + 1;
564 if (defaultBufferSize >= bufferSize) {
567 ret = (char *)malloc(bufferSize);
574 ret[0] = '\0'; /* to start strcat off */
579 if (prefixSuffixIsHeaderFooter) {
580 strcat(p, prefixBuf);
582 strncat(p, entry->message, entry->messageLen);
583 p += entry->messageLen;
584 strcat(p, suffixBuf);
587 while (pm < (entry->message + entry->messageLen)) {
588 const char *lineStart;
593 /* Find the next end-of-line in message */
594 while (pm < (entry->message + entry->messageLen)
595 && *pm != '\n') pm++;
596 lineLen = pm - lineStart;
598 strcat(p, prefixBuf);
600 strncat(p, lineStart, lineLen);
602 strcat(p, suffixBuf);
610 if (p_outLength != NULL) {
611 *p_outLength = p - ret;
618 * Either print or do not print log line, based on filter
620 * Returns count bytes written
623 int log_print_log_line(
624 log_format *p_format,
626 const log_entry *entry)
629 char defaultBuffer[512];
630 char *outBuffer = NULL;
633 outBuffer = log_format_log_line(p_format,
634 defaultBuffer, sizeof(defaultBuffer), entry, &totalLen);
640 ret = write(fd, outBuffer, totalLen);
641 } while (ret < 0 && errno == EINTR);
644 fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
649 if (((size_t)ret) < totalLen) {
650 fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", ret,
656 if (outBuffer != defaultBuffer) {
665 void logprint_run_tests()
669 log_format *p_format;
671 p_format = log_format_new();
673 fprintf(stderr, "create log_foramt failed\n");
677 fprintf(stderr, "running tests\n");
681 log_add_filter_rule(p_format,"*:i");
683 assert (DLOG_INFO == filter_pri_for_tag(p_format, "random"));
684 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) == 0);
685 log_add_filter_rule(p_format, "*");
686 assert (DLOG_DEBUG == filter_pri_for_tag(p_format, "random"));
687 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) > 0);
688 log_add_filter_rule(p_format, "*:v");
689 assert (DLOG_VERBOSE == filter_pri_for_tag(p_format, "random"));
690 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) > 0);
691 log_add_filter_rule(p_format, "*:i");
692 assert (DLOG_INFO == filter_pri_for_tag(p_format, "random"));
693 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) == 0);
695 log_add_filter_rule(p_format, "random");
696 assert (DLOG_VERBOSE == filter_pri_for_tag(p_format, "random"));
697 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) > 0);
698 log_add_filter_rule(p_format, "random:v");
699 assert (DLOG_VERBOSE == filter_pri_for_tag(p_format, "random"));
700 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) > 0);
701 log_add_filter_rule(p_format, "random:d");
702 assert (DLOG_DEBUG == filter_pri_for_tag(p_format, "random"));
703 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) > 0);
704 log_add_filter_rule(p_format, "random:w");
705 assert (DLOG_WARN == filter_pri_for_tag(p_format, "random"));
706 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) == 0);
708 log_add_filter_rule(p_format, "crap:*");
709 assert (DLOG_VERBOSE== filter_pri_for_tag(p_format, "crap"));
710 assert(log_should_print_line(p_format, "crap", DLOG_VERBOSE) > 0);
712 /* invalid expression */
713 err = log_add_filter_rule(p_format, "random:z");
715 assert (DLOG_WARN == filter_pri_for_tag(p_format, "random"));
716 assert(log_should_print_line(p_format, tag, DLOG_DEBUG) == 0);
719 err = log_add_filter_string(p_format, " ");
721 assert(DLOG_WARN == filter_pri_for_tag(p_format, "random"));
723 /* note trailing space */
724 err = log_add_filter_string(p_format, "*:s random:d ");
726 assert(DLOG_DEBUG == filter_pri_for_tag(p_format, "random"));
728 err = log_add_filter_string(p_format, "*:s random:z");
731 log_format_free(p_format);
733 fprintf(stderr, "tests complete\n");