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