blob: 6fac84b464b17fc07db72dd2feaaf009defcfcae [file] [log] [blame]
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07001/* //device/libs/cutils/logprint.c
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#define _GNU_SOURCE /* for asprintf */
19
20#include <ctype.h>
21#include <stdio.h>
22#include <errno.h>
23#include <stdlib.h>
24#include <stdint.h>
25#include <string.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070026#include <assert.h>
27#include <arpa/inet.h>
28
29#include <cutils/logd.h>
30#include <cutils/logprint.h>
31
32typedef struct FilterInfo_t {
33 char *mTag;
34 android_LogPriority mPri;
35 struct FilterInfo_t *p_next;
36} FilterInfo;
37
38struct AndroidLogFormat_t {
39 android_LogPriority global_pri;
40 FilterInfo *filters;
41 AndroidLogPrintFormat format;
42};
43
44static FilterInfo * filterinfo_new(const char * tag, android_LogPriority pri)
45{
46 FilterInfo *p_ret;
47
48 p_ret = (FilterInfo *)calloc(1, sizeof(FilterInfo));
49 p_ret->mTag = strdup(tag);
50 p_ret->mPri = pri;
51
52 return p_ret;
53}
54
55static void filterinfo_free(FilterInfo *p_info)
56{
57 if (p_info == NULL) {
58 return;
59 }
60
61 free(p_info->mTag);
62 p_info->mTag = NULL;
63}
64
65/*
66 * Note: also accepts 0-9 priorities
67 * returns ANDROID_LOG_UNKNOWN if the character is unrecognized
68 */
69static android_LogPriority filterCharToPri (char c)
70{
71 android_LogPriority pri;
72
73 c = tolower(c);
74
75 if (c >= '0' && c <= '9') {
76 if (c >= ('0'+ANDROID_LOG_SILENT)) {
77 pri = ANDROID_LOG_VERBOSE;
78 } else {
79 pri = (android_LogPriority)(c - '0');
80 }
81 } else if (c == 'v') {
82 pri = ANDROID_LOG_VERBOSE;
83 } else if (c == 'd') {
84 pri = ANDROID_LOG_DEBUG;
85 } else if (c == 'i') {
86 pri = ANDROID_LOG_INFO;
87 } else if (c == 'w') {
88 pri = ANDROID_LOG_WARN;
89 } else if (c == 'e') {
90 pri = ANDROID_LOG_ERROR;
91 } else if (c == 'f') {
92 pri = ANDROID_LOG_FATAL;
93 } else if (c == 's') {
94 pri = ANDROID_LOG_SILENT;
95 } else if (c == '*') {
96 pri = ANDROID_LOG_DEFAULT;
97 } else {
98 pri = ANDROID_LOG_UNKNOWN;
99 }
100
101 return pri;
102}
103
104static char filterPriToChar (android_LogPriority pri)
105{
106 switch (pri) {
107 case ANDROID_LOG_VERBOSE: return 'V';
108 case ANDROID_LOG_DEBUG: return 'D';
109 case ANDROID_LOG_INFO: return 'I';
110 case ANDROID_LOG_WARN: return 'W';
111 case ANDROID_LOG_ERROR: return 'E';
112 case ANDROID_LOG_FATAL: return 'F';
113 case ANDROID_LOG_SILENT: return 'S';
114
115 case ANDROID_LOG_DEFAULT:
116 case ANDROID_LOG_UNKNOWN:
117 default: return '?';
118 }
119}
120
121static android_LogPriority filterPriForTag(
122 AndroidLogFormat *p_format, const char *tag)
123{
124 FilterInfo *p_curFilter;
125
126 for (p_curFilter = p_format->filters
127 ; p_curFilter != NULL
128 ; p_curFilter = p_curFilter->p_next
129 ) {
130 if (0 == strcmp(tag, p_curFilter->mTag)) {
131 if (p_curFilter->mPri == ANDROID_LOG_DEFAULT) {
132 return p_format->global_pri;
133 } else {
134 return p_curFilter->mPri;
135 }
136 }
137 }
138
139 return p_format->global_pri;
140}
141
142/** for debugging */
143static void dumpFilters(AndroidLogFormat *p_format)
144{
145 FilterInfo *p_fi;
146
147 for (p_fi = p_format->filters ; p_fi != NULL ; p_fi = p_fi->p_next) {
148 char cPri = filterPriToChar(p_fi->mPri);
149 if (p_fi->mPri == ANDROID_LOG_DEFAULT) {
150 cPri = filterPriToChar(p_format->global_pri);
151 }
152 fprintf(stderr,"%s:%c\n", p_fi->mTag, cPri);
153 }
154
155 fprintf(stderr,"*:%c\n", filterPriToChar(p_format->global_pri));
156
157}
158
159/**
160 * returns 1 if this log line should be printed based on its priority
161 * and tag, and 0 if it should not
162 */
163int android_log_shouldPrintLine (
164 AndroidLogFormat *p_format, const char *tag, android_LogPriority pri)
165{
166 return pri >= filterPriForTag(p_format, tag);
167}
168
169AndroidLogFormat *android_log_format_new()
170{
171 AndroidLogFormat *p_ret;
172
173 p_ret = calloc(1, sizeof(AndroidLogFormat));
174
175 p_ret->global_pri = ANDROID_LOG_VERBOSE;
176 p_ret->format = FORMAT_BRIEF;
177
178 return p_ret;
179}
180
181void android_log_format_free(AndroidLogFormat *p_format)
182{
183 FilterInfo *p_info, *p_info_old;
184
185 p_info = p_format->filters;
186
187 while (p_info != NULL) {
188 p_info_old = p_info;
189 p_info = p_info->p_next;
190
191 free(p_info_old);
192 }
193
194 free(p_format);
195}
196
197
198
199void android_log_setPrintFormat(AndroidLogFormat *p_format,
200 AndroidLogPrintFormat format)
201{
202 p_format->format=format;
203}
204
205/**
206 * Returns FORMAT_OFF on invalid string
207 */
208AndroidLogPrintFormat android_log_formatFromString(const char * formatString)
209{
210 static AndroidLogPrintFormat format;
211
212 if (strcmp(formatString, "brief") == 0) format = FORMAT_BRIEF;
213 else if (strcmp(formatString, "process") == 0) format = FORMAT_PROCESS;
214 else if (strcmp(formatString, "tag") == 0) format = FORMAT_TAG;
215 else if (strcmp(formatString, "thread") == 0) format = FORMAT_THREAD;
216 else if (strcmp(formatString, "raw") == 0) format = FORMAT_RAW;
217 else if (strcmp(formatString, "time") == 0) format = FORMAT_TIME;
218 else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
219 else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
220 else format = FORMAT_OFF;
221
222 return format;
223}
224
225/**
226 * filterExpression: a single filter expression
227 * eg "AT:d"
228 *
229 * returns 0 on success and -1 on invalid expression
230 *
231 * Assumes single threaded execution
232 */
233
234int android_log_addFilterRule(AndroidLogFormat *p_format,
235 const char *filterExpression)
236{
237 size_t i=0;
238 size_t tagNameLength;
239 android_LogPriority pri = ANDROID_LOG_DEFAULT;
240
241 tagNameLength = strcspn(filterExpression, ":");
242
243 if (tagNameLength == 0) {
244 goto error;
245 }
246
247 if(filterExpression[tagNameLength] == ':') {
248 pri = filterCharToPri(filterExpression[tagNameLength+1]);
249
250 if (pri == ANDROID_LOG_UNKNOWN) {
251 goto error;
252 }
253 }
254
255 if(0 == strncmp("*", filterExpression, tagNameLength)) {
256 // This filter expression refers to the global filter
257 // The default level for this is DEBUG if the priority
258 // is unspecified
259 if (pri == ANDROID_LOG_DEFAULT) {
260 pri = ANDROID_LOG_DEBUG;
261 }
262
263 p_format->global_pri = pri;
264 } else {
265 // for filter expressions that don't refer to the global
266 // filter, the default is verbose if the priority is unspecified
267 if (pri == ANDROID_LOG_DEFAULT) {
268 pri = ANDROID_LOG_VERBOSE;
269 }
270
271 char *tagName;
272
273// Presently HAVE_STRNDUP is never defined, so the second case is always taken
274// Darwin doesn't have strnup, everything else does
275#ifdef HAVE_STRNDUP
276 tagName = strndup(filterExpression, tagNameLength);
277#else
278 //a few extra bytes copied...
279 tagName = strdup(filterExpression);
280 tagName[tagNameLength] = '\0';
281#endif /*HAVE_STRNDUP*/
282
283 FilterInfo *p_fi = filterinfo_new(tagName, pri);
284 free(tagName);
285
286 p_fi->p_next = p_format->filters;
287 p_format->filters = p_fi;
288 }
289
290 return 0;
291error:
292 return -1;
293}
294
295
296/**
297 * filterString: a comma/whitespace-separated set of filter expressions
298 *
299 * eg "AT:d *:i"
300 *
301 * returns 0 on success and -1 on invalid expression
302 *
303 * Assumes single threaded execution
304 *
305 */
306
307int android_log_addFilterString(AndroidLogFormat *p_format,
308 const char *filterString)
309{
310 char *filterStringCopy = strdup (filterString);
311 char *p_cur = filterStringCopy;
312 char *p_ret;
313 int err;
314
315 // Yes, I'm using strsep
316 while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
317 // ignore whitespace-only entries
318 if(p_ret[0] != '\0') {
319 err = android_log_addFilterRule(p_format, p_ret);
320
321 if (err < 0) {
322 goto error;
323 }
324 }
325 }
326
327 free (filterStringCopy);
328 return 0;
329error:
330 free (filterStringCopy);
331 return -1;
332}
333
334static inline char * strip_end(char *str)
335{
336 char *end = str + strlen(str) - 1;
337
338 while (end >= str && isspace(*end))
339 *end-- = '\0';
340 return str;
341}
342
343/**
344 * Splits a wire-format buffer into an AndroidLogEntry
345 * entry allocated by caller. Pointers will point directly into buf
346 *
347 * Returns 0 on success and -1 on invalid wire format (entry will be
348 * in unspecified state)
349 */
350int android_log_processLogBuffer(struct logger_entry *buf,
351 AndroidLogEntry *entry)
352{
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700353 entry->tv_sec = buf->sec;
354 entry->tv_nsec = buf->nsec;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700355 entry->pid = buf->pid;
356 entry->tid = buf->tid;
Kenny Root4bf3c022011-09-30 17:10:14 -0700357
358 /*
359 * format: <priority:1><tag:N>\0<message:N>\0
360 *
361 * tag str
Nick Kraleviche1ede152011-10-18 15:23:33 -0700362 * starts at buf->msg+1
Kenny Root4bf3c022011-09-30 17:10:14 -0700363 * msg
Nick Kraleviche1ede152011-10-18 15:23:33 -0700364 * starts at buf->msg+1+len(tag)+1
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700365 *
366 * The message may have been truncated by the kernel log driver.
367 * When that happens, we must null-terminate the message ourselves.
Kenny Root4bf3c022011-09-30 17:10:14 -0700368 */
Nick Kraleviche1ede152011-10-18 15:23:33 -0700369 if (buf->len < 3) {
370 // An well-formed entry must consist of at least a priority
371 // and two null characters
372 fprintf(stderr, "+++ LOG: entry too small\n");
Kenny Root4bf3c022011-09-30 17:10:14 -0700373 return -1;
374 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700375
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700376 int msgStart = -1;
377 int msgEnd = -1;
378
Nick Kraleviche1ede152011-10-18 15:23:33 -0700379 int i;
380 for (i = 1; i < buf->len; i++) {
381 if (buf->msg[i] == '\0') {
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700382 if (msgStart == -1) {
383 msgStart = i + 1;
384 } else {
385 msgEnd = i;
386 break;
387 }
Nick Kraleviche1ede152011-10-18 15:23:33 -0700388 }
389 }
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700390
391 if (msgStart == -1) {
392 fprintf(stderr, "+++ LOG: malformed log message\n");
Nick Kralevich63f4a842011-10-17 10:45:03 -0700393 return -1;
394 }
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700395 if (msgEnd == -1) {
396 // incoming message not null-terminated; force it
397 msgEnd = buf->len - 1;
398 buf->msg[msgEnd] = '\0';
399 }
400
Nick Kraleviche1ede152011-10-18 15:23:33 -0700401 entry->priority = buf->msg[0];
402 entry->tag = buf->msg + 1;
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700403 entry->message = buf->msg + msgStart;
404 entry->messageLen = msgEnd - msgStart;
Nick Kralevich63f4a842011-10-17 10:45:03 -0700405
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700406 return 0;
407}
408
409/*
410 * Extract a 4-byte value from a byte stream.
411 */
412static inline uint32_t get4LE(const uint8_t* src)
413{
414 return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
415}
416
417/*
418 * Extract an 8-byte value from a byte stream.
419 */
420static inline uint64_t get8LE(const uint8_t* src)
421{
422 uint32_t low, high;
423
424 low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
425 high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
426 return ((long long) high << 32) | (long long) low;
427}
428
429
430/*
431 * Recursively convert binary log data to printable form.
432 *
433 * This needs to be recursive because you can have lists of lists.
434 *
435 * If we run out of room, we stop processing immediately. It's important
436 * for us to check for space on every output element to avoid producing
437 * garbled output.
438 *
439 * Returns 0 on success, 1 on buffer full, -1 on failure.
440 */
441static int android_log_printBinaryEvent(const unsigned char** pEventData,
442 size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen)
443{
444 const unsigned char* eventData = *pEventData;
445 size_t eventDataLen = *pEventDataLen;
446 char* outBuf = *pOutBuf;
447 size_t outBufLen = *pOutBufLen;
448 unsigned char type;
449 size_t outCount;
450 int result = 0;
451
452 if (eventDataLen < 1)
453 return -1;
454 type = *eventData++;
455 eventDataLen--;
456
457 //fprintf(stderr, "--- type=%d (rem len=%d)\n", type, eventDataLen);
458
459 switch (type) {
460 case EVENT_TYPE_INT:
461 /* 32-bit signed int */
462 {
463 int ival;
464
465 if (eventDataLen < 4)
466 return -1;
467 ival = get4LE(eventData);
468 eventData += 4;
469 eventDataLen -= 4;
470
471 outCount = snprintf(outBuf, outBufLen, "%d", ival);
472 if (outCount < outBufLen) {
473 outBuf += outCount;
474 outBufLen -= outCount;
475 } else {
476 /* halt output */
477 goto no_room;
478 }
479 }
480 break;
481 case EVENT_TYPE_LONG:
482 /* 64-bit signed long */
483 {
484 long long lval;
485
486 if (eventDataLen < 8)
487 return -1;
488 lval = get8LE(eventData);
489 eventData += 8;
490 eventDataLen -= 8;
491
492 outCount = snprintf(outBuf, outBufLen, "%lld", lval);
493 if (outCount < outBufLen) {
494 outBuf += outCount;
495 outBufLen -= outCount;
496 } else {
497 /* halt output */
498 goto no_room;
499 }
500 }
501 break;
502 case EVENT_TYPE_STRING:
503 /* UTF-8 chars, not NULL-terminated */
504 {
505 unsigned int strLen;
506
507 if (eventDataLen < 4)
508 return -1;
509 strLen = get4LE(eventData);
510 eventData += 4;
511 eventDataLen -= 4;
512
513 if (eventDataLen < strLen)
514 return -1;
515
516 if (strLen < outBufLen) {
517 memcpy(outBuf, eventData, strLen);
518 outBuf += strLen;
519 outBufLen -= strLen;
520 } else if (outBufLen > 0) {
521 /* copy what we can */
522 memcpy(outBuf, eventData, outBufLen);
523 outBuf += outBufLen;
524 outBufLen -= outBufLen;
525 goto no_room;
526 }
527 eventData += strLen;
528 eventDataLen -= strLen;
529 break;
530 }
531 case EVENT_TYPE_LIST:
532 /* N items, all different types */
533 {
534 unsigned char count;
535 int i;
536
537 if (eventDataLen < 1)
538 return -1;
539
540 count = *eventData++;
541 eventDataLen--;
542
543 if (outBufLen > 0) {
544 *outBuf++ = '[';
545 outBufLen--;
546 } else {
547 goto no_room;
548 }
549
550 for (i = 0; i < count; i++) {
551 result = android_log_printBinaryEvent(&eventData, &eventDataLen,
552 &outBuf, &outBufLen);
553 if (result != 0)
554 goto bail;
555
556 if (i < count-1) {
557 if (outBufLen > 0) {
558 *outBuf++ = ',';
559 outBufLen--;
560 } else {
561 goto no_room;
562 }
563 }
564 }
565
566 if (outBufLen > 0) {
567 *outBuf++ = ']';
568 outBufLen--;
569 } else {
570 goto no_room;
571 }
572 }
573 break;
574 default:
575 fprintf(stderr, "Unknown binary event type %d\n", type);
576 return -1;
577 }
578
579bail:
580 *pEventData = eventData;
581 *pEventDataLen = eventDataLen;
582 *pOutBuf = outBuf;
583 *pOutBufLen = outBufLen;
584 return result;
585
586no_room:
587 result = 1;
588 goto bail;
589}
590
591/**
592 * Convert a binary log entry to ASCII form.
593 *
594 * For convenience we mimic the processLogBuffer API. There is no
595 * pre-defined output length for the binary data, since we're free to format
596 * it however we choose, which means we can't really use a fixed-size buffer
597 * here.
598 */
599int android_log_processBinaryLogBuffer(struct logger_entry *buf,
600 AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf,
601 int messageBufLen)
602{
603 size_t inCount;
604 unsigned int tagIndex;
605 const unsigned char* eventData;
606
607 entry->tv_sec = buf->sec;
608 entry->tv_nsec = buf->nsec;
609 entry->priority = ANDROID_LOG_INFO;
610 entry->pid = buf->pid;
611 entry->tid = buf->tid;
612
613 /*
614 * Pull the tag out.
615 */
616 eventData = (const unsigned char*) buf->msg;
617 inCount = buf->len;
618 if (inCount < 4)
619 return -1;
620 tagIndex = get4LE(eventData);
621 eventData += 4;
622 inCount -= 4;
623
624 if (map != NULL) {
625 entry->tag = android_lookupEventTag(map, tagIndex);
626 } else {
627 entry->tag = NULL;
628 }
629
630 /*
631 * If we don't have a map, or didn't find the tag number in the map,
632 * stuff a generated tag value into the start of the output buffer and
633 * shift the buffer pointers down.
634 */
635 if (entry->tag == NULL) {
636 int tagLen;
637
638 tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex);
639 entry->tag = messageBuf;
640 messageBuf += tagLen+1;
641 messageBufLen -= tagLen+1;
642 }
643
644 /*
645 * Format the event log data into the buffer.
646 */
647 char* outBuf = messageBuf;
648 size_t outRemaining = messageBufLen-1; /* leave one for nul byte */
649 int result;
650 result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
651 &outRemaining);
652 if (result < 0) {
653 fprintf(stderr, "Binary log entry conversion failed\n");
654 return -1;
655 } else if (result == 1) {
656 if (outBuf > messageBuf) {
657 /* leave an indicator */
658 *(outBuf-1) = '!';
659 } else {
660 /* no room to output anything at all */
661 *outBuf++ = '!';
662 outRemaining--;
663 }
664 /* pretend we ate all the data */
665 inCount = 0;
666 }
667
668 /* eat the silly terminating '\n' */
669 if (inCount == 1 && *eventData == '\n') {
670 eventData++;
671 inCount--;
672 }
673
674 if (inCount != 0) {
675 fprintf(stderr,
Andrew Hsiehd2c8f522012-02-27 16:48:18 -0800676 "Warning: leftover binary log data (%zu bytes)\n", inCount);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700677 }
678
679 /*
680 * Terminate the buffer. The NUL byte does not count as part of
681 * entry->messageLen.
682 */
683 *outBuf = '\0';
684 entry->messageLen = outBuf - messageBuf;
685 assert(entry->messageLen == (messageBufLen-1) - outRemaining);
686
687 entry->message = messageBuf;
688
689 return 0;
690}
691
692/**
693 * Formats a log message into a buffer
694 *
695 * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer
696 * If return value != defaultBuffer, caller must call free()
697 * Returns NULL on malloc error
698 */
699
700char *android_log_formatLogLine (
701 AndroidLogFormat *p_format,
702 char *defaultBuffer,
703 size_t defaultBufferSize,
704 const AndroidLogEntry *entry,
705 size_t *p_outLength)
706{
707#if defined(HAVE_LOCALTIME_R)
708 struct tm tmBuf;
709#endif
710 struct tm* ptm;
711 char timeBuf[32];
712 char headerBuf[128];
713 char prefixBuf[128], suffixBuf[128];
714 char priChar;
715 int prefixSuffixIsHeaderFooter = 0;
716 char * ret = NULL;
717
718 priChar = filterPriToChar(entry->priority);
719
720 /*
721 * Get the current date/time in pretty form
722 *
723 * It's often useful when examining a log with "less" to jump to
724 * a specific point in the file by searching for the date/time stamp.
725 * For this reason it's very annoying to have regexp meta characters
726 * in the time stamp. Don't use forward slashes, parenthesis,
727 * brackets, asterisks, or other special chars here.
728 */
729#if defined(HAVE_LOCALTIME_R)
730 ptm = localtime_r(&(entry->tv_sec), &tmBuf);
731#else
732 ptm = localtime(&(entry->tv_sec));
733#endif
734 //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
735 strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
736
737 /*
738 * Construct a buffer containing the log header and log message.
739 */
740 size_t prefixLen, suffixLen;
741
742 switch (p_format->format) {
743 case FORMAT_TAG:
744 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
745 "%c/%-8s: ", priChar, entry->tag);
746 strcpy(suffixBuf, "\n"); suffixLen = 1;
747 break;
748 case FORMAT_PROCESS:
749 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
750 "%c(%5d) ", priChar, entry->pid);
751 suffixLen = snprintf(suffixBuf, sizeof(suffixBuf),
752 " (%s)\n", entry->tag);
753 break;
754 case FORMAT_THREAD:
755 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
Andrew Hsiehd2c8f522012-02-27 16:48:18 -0800756 "%c(%5d:%5d) ", priChar, entry->pid, entry->tid);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700757 strcpy(suffixBuf, "\n");
758 suffixLen = 1;
759 break;
760 case FORMAT_RAW:
761 prefixBuf[0] = 0;
762 prefixLen = 0;
763 strcpy(suffixBuf, "\n");
764 suffixLen = 1;
765 break;
766 case FORMAT_TIME:
767 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
768 "%s.%03ld %c/%-8s(%5d): ", timeBuf, entry->tv_nsec / 1000000,
769 priChar, entry->tag, entry->pid);
770 strcpy(suffixBuf, "\n");
771 suffixLen = 1;
772 break;
773 case FORMAT_THREADTIME:
774 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
775 "%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000,
Andrew Hsiehd2c8f522012-02-27 16:48:18 -0800776 entry->pid, entry->tid, priChar, entry->tag);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700777 strcpy(suffixBuf, "\n");
778 suffixLen = 1;
779 break;
780 case FORMAT_LONG:
781 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
Andrew Hsiehd2c8f522012-02-27 16:48:18 -0800782 "[ %s.%03ld %5d:%5d %c/%-8s ]\n",
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700783 timeBuf, entry->tv_nsec / 1000000, entry->pid,
Andrew Hsiehd2c8f522012-02-27 16:48:18 -0800784 entry->tid, priChar, entry->tag);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700785 strcpy(suffixBuf, "\n\n");
786 suffixLen = 2;
787 prefixSuffixIsHeaderFooter = 1;
788 break;
789 case FORMAT_BRIEF:
790 default:
791 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
792 "%c/%-8s(%5d): ", priChar, entry->tag, entry->pid);
793 strcpy(suffixBuf, "\n");
794 suffixLen = 1;
795 break;
796 }
Keith Prestonb45b5c92010-02-11 15:12:53 -0600797 /* snprintf has a weird return value. It returns what would have been
798 * written given a large enough buffer. In the case that the prefix is
799 * longer then our buffer(128), it messes up the calculations below
800 * possibly causing heap corruption. To avoid this we double check and
801 * set the length at the maximum (size minus null byte)
802 */
803 if(prefixLen >= sizeof(prefixBuf))
804 prefixLen = sizeof(prefixBuf) - 1;
805 if(suffixLen >= sizeof(suffixBuf))
806 suffixLen = sizeof(suffixBuf) - 1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700807
808 /* the following code is tragically unreadable */
809
810 size_t numLines;
811 size_t i;
812 char *p;
813 size_t bufferSize;
814 const char *pm;
815
816 if (prefixSuffixIsHeaderFooter) {
817 // we're just wrapping message with a header/footer
818 numLines = 1;
819 } else {
820 pm = entry->message;
821 numLines = 0;
822
823 // The line-end finding here must match the line-end finding
824 // in for ( ... numLines...) loop below
825 while (pm < (entry->message + entry->messageLen)) {
826 if (*pm++ == '\n') numLines++;
827 }
828 // plus one line for anything not newline-terminated at the end
829 if (pm > entry->message && *(pm-1) != '\n') numLines++;
830 }
831
832 // this is an upper bound--newlines in message may be counted
833 // extraneously
834 bufferSize = (numLines * (prefixLen + suffixLen)) + entry->messageLen + 1;
835
836 if (defaultBufferSize >= bufferSize) {
837 ret = defaultBuffer;
838 } else {
839 ret = (char *)malloc(bufferSize);
840
841 if (ret == NULL) {
842 return ret;
843 }
844 }
845
846 ret[0] = '\0'; /* to start strcat off */
847
848 p = ret;
849 pm = entry->message;
850
851 if (prefixSuffixIsHeaderFooter) {
852 strcat(p, prefixBuf);
853 p += prefixLen;
854 strncat(p, entry->message, entry->messageLen);
855 p += entry->messageLen;
856 strcat(p, suffixBuf);
857 p += suffixLen;
858 } else {
859 while(pm < (entry->message + entry->messageLen)) {
860 const char *lineStart;
861 size_t lineLen;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700862 lineStart = pm;
863
864 // Find the next end-of-line in message
865 while (pm < (entry->message + entry->messageLen)
866 && *pm != '\n') pm++;
867 lineLen = pm - lineStart;
868
869 strcat(p, prefixBuf);
870 p += prefixLen;
871 strncat(p, lineStart, lineLen);
872 p += lineLen;
873 strcat(p, suffixBuf);
874 p += suffixLen;
875
876 if (*pm == '\n') pm++;
877 }
878 }
879
880 if (p_outLength != NULL) {
881 *p_outLength = p - ret;
882 }
883
884 return ret;
885}
886
887/**
888 * Either print or do not print log line, based on filter
889 *
890 * Returns count bytes written
891 */
892
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800893int android_log_printLogLine(
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700894 AndroidLogFormat *p_format,
895 int fd,
896 const AndroidLogEntry *entry)
897{
898 int ret;
899 char defaultBuffer[512];
900 char *outBuffer = NULL;
901 size_t totalLen;
902
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700903 outBuffer = android_log_formatLogLine(p_format, defaultBuffer,
904 sizeof(defaultBuffer), entry, &totalLen);
905
906 if (!outBuffer)
907 return -1;
908
909 do {
910 ret = write(fd, outBuffer, totalLen);
911 } while (ret < 0 && errno == EINTR);
912
913 if (ret < 0) {
914 fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
915 ret = 0;
916 goto done;
917 }
918
919 if (((size_t)ret) < totalLen) {
920 fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", ret,
921 (int)totalLen);
922 goto done;
923 }
924
925done:
926 if (outBuffer != defaultBuffer) {
927 free(outBuffer);
928 }
929
930 return ret;
931}
932
933
934
935void logprint_run_tests()
936{
937#if 0
938
939 fprintf(stderr, "tests disabled\n");
940
941#else
942
943 int err;
944 const char *tag;
945 AndroidLogFormat *p_format;
946
947 p_format = android_log_format_new();
948
949 fprintf(stderr, "running tests\n");
950
951 tag = "random";
952
953 android_log_addFilterRule(p_format,"*:i");
954
955 assert (ANDROID_LOG_INFO == filterPriForTag(p_format, "random"));
956 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
957 android_log_addFilterRule(p_format, "*");
958 assert (ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
959 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
960 android_log_addFilterRule(p_format, "*:v");
961 assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
962 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
963 android_log_addFilterRule(p_format, "*:i");
964 assert (ANDROID_LOG_INFO == filterPriForTag(p_format, "random"));
965 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
966
967 android_log_addFilterRule(p_format, "random");
968 assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
969 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
970 android_log_addFilterRule(p_format, "random:v");
971 assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
972 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
973 android_log_addFilterRule(p_format, "random:d");
974 assert (ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
975 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
976 android_log_addFilterRule(p_format, "random:w");
977 assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
978 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
979
980 android_log_addFilterRule(p_format, "crap:*");
981 assert (ANDROID_LOG_VERBOSE== filterPriForTag(p_format, "crap"));
982 assert(android_log_shouldPrintLine(p_format, "crap", ANDROID_LOG_VERBOSE) > 0);
983
984 // invalid expression
985 err = android_log_addFilterRule(p_format, "random:z");
986 assert (err < 0);
987 assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
988 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
989
990 // Issue #550946
991 err = android_log_addFilterString(p_format, " ");
992 assert(err == 0);
993 assert(ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
994
995 // note trailing space
996 err = android_log_addFilterString(p_format, "*:s random:d ");
997 assert(err == 0);
998 assert(ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
999
1000 err = android_log_addFilterString(p_format, "*:s random:z");
1001 assert(err < 0);
1002
1003
1004#if 0
1005 char *ret;
1006 char defaultBuffer[512];
1007
1008 ret = android_log_formatLogLine(p_format,
1009 defaultBuffer, sizeof(defaultBuffer), 0, ANDROID_LOG_ERROR, 123,
1010 123, 123, "random", "nofile", strlen("Hello"), "Hello", NULL);
1011#endif
1012
1013
1014 fprintf(stderr, "tests complete\n");
1015#endif
1016}