blob: a7480d51e470dfcb47b64f2cd6643f3a95e5ef22 [file] [log] [blame]
Mark Salyzyncf4aa032013-11-22 07:54:30 -08001/*
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07002**
Mark Salyzyn40b21552013-12-18 12:59:01 -08003** Copyright 2006-2014, The Android Open Source Project
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -07004**
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
Colin Cross9227bd32013-07-23 16:59:20 -070029#include <log/logd.h>
30#include <log/logprint.h>
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070031
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;
Mark Salyzyn40b21552013-12-18 12:59:01 -0800380 char *msg = buf->msg;
381 struct logger_entry_v2 *buf2 = (struct logger_entry_v2 *)buf;
382 if (buf2->hdr_size) {
383 msg = ((char *)buf2) + buf2->hdr_size;
384 }
Nick Kraleviche1ede152011-10-18 15:23:33 -0700385 for (i = 1; i < buf->len; i++) {
Mark Salyzyn40b21552013-12-18 12:59:01 -0800386 if (msg[i] == '\0') {
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700387 if (msgStart == -1) {
388 msgStart = i + 1;
389 } else {
390 msgEnd = i;
391 break;
392 }
Nick Kraleviche1ede152011-10-18 15:23:33 -0700393 }
394 }
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700395
396 if (msgStart == -1) {
397 fprintf(stderr, "+++ LOG: malformed log message\n");
Nick Kralevich63f4a842011-10-17 10:45:03 -0700398 return -1;
399 }
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700400 if (msgEnd == -1) {
401 // incoming message not null-terminated; force it
402 msgEnd = buf->len - 1;
Mark Salyzyn40b21552013-12-18 12:59:01 -0800403 msg[msgEnd] = '\0';
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700404 }
405
Mark Salyzyn40b21552013-12-18 12:59:01 -0800406 entry->priority = msg[0];
407 entry->tag = msg + 1;
408 entry->message = msg + msgStart;
Jeff Sharkeya820a0e2011-10-26 18:40:39 -0700409 entry->messageLen = msgEnd - msgStart;
Nick Kralevich63f4a842011-10-17 10:45:03 -0700410
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700411 return 0;
412}
413
414/*
415 * Extract a 4-byte value from a byte stream.
416 */
417static inline uint32_t get4LE(const uint8_t* src)
418{
419 return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
420}
421
422/*
423 * Extract an 8-byte value from a byte stream.
424 */
425static inline uint64_t get8LE(const uint8_t* src)
426{
427 uint32_t low, high;
428
429 low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
430 high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
431 return ((long long) high << 32) | (long long) low;
432}
433
434
435/*
436 * Recursively convert binary log data to printable form.
437 *
438 * This needs to be recursive because you can have lists of lists.
439 *
440 * If we run out of room, we stop processing immediately. It's important
441 * for us to check for space on every output element to avoid producing
442 * garbled output.
443 *
444 * Returns 0 on success, 1 on buffer full, -1 on failure.
445 */
446static int android_log_printBinaryEvent(const unsigned char** pEventData,
447 size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen)
448{
449 const unsigned char* eventData = *pEventData;
450 size_t eventDataLen = *pEventDataLen;
451 char* outBuf = *pOutBuf;
452 size_t outBufLen = *pOutBufLen;
453 unsigned char type;
454 size_t outCount;
455 int result = 0;
456
457 if (eventDataLen < 1)
458 return -1;
459 type = *eventData++;
460 eventDataLen--;
461
462 //fprintf(stderr, "--- type=%d (rem len=%d)\n", type, eventDataLen);
463
464 switch (type) {
465 case EVENT_TYPE_INT:
466 /* 32-bit signed int */
467 {
468 int ival;
469
470 if (eventDataLen < 4)
471 return -1;
472 ival = get4LE(eventData);
473 eventData += 4;
474 eventDataLen -= 4;
475
476 outCount = snprintf(outBuf, outBufLen, "%d", ival);
477 if (outCount < outBufLen) {
478 outBuf += outCount;
479 outBufLen -= outCount;
480 } else {
481 /* halt output */
482 goto no_room;
483 }
484 }
485 break;
486 case EVENT_TYPE_LONG:
487 /* 64-bit signed long */
488 {
489 long long lval;
490
491 if (eventDataLen < 8)
492 return -1;
493 lval = get8LE(eventData);
494 eventData += 8;
495 eventDataLen -= 8;
496
497 outCount = snprintf(outBuf, outBufLen, "%lld", lval);
498 if (outCount < outBufLen) {
499 outBuf += outCount;
500 outBufLen -= outCount;
501 } else {
502 /* halt output */
503 goto no_room;
504 }
505 }
506 break;
507 case EVENT_TYPE_STRING:
508 /* UTF-8 chars, not NULL-terminated */
509 {
510 unsigned int strLen;
511
512 if (eventDataLen < 4)
513 return -1;
514 strLen = get4LE(eventData);
515 eventData += 4;
516 eventDataLen -= 4;
517
518 if (eventDataLen < strLen)
519 return -1;
520
521 if (strLen < outBufLen) {
522 memcpy(outBuf, eventData, strLen);
523 outBuf += strLen;
524 outBufLen -= strLen;
525 } else if (outBufLen > 0) {
526 /* copy what we can */
527 memcpy(outBuf, eventData, outBufLen);
528 outBuf += outBufLen;
529 outBufLen -= outBufLen;
530 goto no_room;
531 }
532 eventData += strLen;
533 eventDataLen -= strLen;
534 break;
535 }
536 case EVENT_TYPE_LIST:
537 /* N items, all different types */
538 {
539 unsigned char count;
540 int i;
541
542 if (eventDataLen < 1)
543 return -1;
544
545 count = *eventData++;
546 eventDataLen--;
547
548 if (outBufLen > 0) {
549 *outBuf++ = '[';
550 outBufLen--;
551 } else {
552 goto no_room;
553 }
554
555 for (i = 0; i < count; i++) {
556 result = android_log_printBinaryEvent(&eventData, &eventDataLen,
557 &outBuf, &outBufLen);
558 if (result != 0)
559 goto bail;
560
561 if (i < count-1) {
562 if (outBufLen > 0) {
563 *outBuf++ = ',';
564 outBufLen--;
565 } else {
566 goto no_room;
567 }
568 }
569 }
570
571 if (outBufLen > 0) {
572 *outBuf++ = ']';
573 outBufLen--;
574 } else {
575 goto no_room;
576 }
577 }
578 break;
579 default:
580 fprintf(stderr, "Unknown binary event type %d\n", type);
581 return -1;
582 }
583
584bail:
585 *pEventData = eventData;
586 *pEventDataLen = eventDataLen;
587 *pOutBuf = outBuf;
588 *pOutBufLen = outBufLen;
589 return result;
590
591no_room:
592 result = 1;
593 goto bail;
594}
595
596/**
597 * Convert a binary log entry to ASCII form.
598 *
599 * For convenience we mimic the processLogBuffer API. There is no
600 * pre-defined output length for the binary data, since we're free to format
601 * it however we choose, which means we can't really use a fixed-size buffer
602 * here.
603 */
604int android_log_processBinaryLogBuffer(struct logger_entry *buf,
605 AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf,
606 int messageBufLen)
607{
608 size_t inCount;
609 unsigned int tagIndex;
610 const unsigned char* eventData;
611
612 entry->tv_sec = buf->sec;
613 entry->tv_nsec = buf->nsec;
614 entry->priority = ANDROID_LOG_INFO;
615 entry->pid = buf->pid;
616 entry->tid = buf->tid;
617
618 /*
619 * Pull the tag out.
620 */
621 eventData = (const unsigned char*) buf->msg;
Mark Salyzyn40b21552013-12-18 12:59:01 -0800622 struct logger_entry_v2 *buf2 = (struct logger_entry_v2 *)buf;
623 if (buf2->hdr_size) {
624 eventData = ((unsigned char *)buf2) + buf2->hdr_size;
625 }
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700626 inCount = buf->len;
627 if (inCount < 4)
628 return -1;
629 tagIndex = get4LE(eventData);
630 eventData += 4;
631 inCount -= 4;
632
633 if (map != NULL) {
634 entry->tag = android_lookupEventTag(map, tagIndex);
635 } else {
636 entry->tag = NULL;
637 }
638
639 /*
640 * If we don't have a map, or didn't find the tag number in the map,
641 * stuff a generated tag value into the start of the output buffer and
642 * shift the buffer pointers down.
643 */
644 if (entry->tag == NULL) {
645 int tagLen;
646
647 tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex);
648 entry->tag = messageBuf;
649 messageBuf += tagLen+1;
650 messageBufLen -= tagLen+1;
651 }
652
653 /*
654 * Format the event log data into the buffer.
655 */
656 char* outBuf = messageBuf;
657 size_t outRemaining = messageBufLen-1; /* leave one for nul byte */
658 int result;
659 result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
660 &outRemaining);
661 if (result < 0) {
662 fprintf(stderr, "Binary log entry conversion failed\n");
663 return -1;
664 } else if (result == 1) {
665 if (outBuf > messageBuf) {
666 /* leave an indicator */
667 *(outBuf-1) = '!';
668 } else {
669 /* no room to output anything at all */
670 *outBuf++ = '!';
671 outRemaining--;
672 }
673 /* pretend we ate all the data */
674 inCount = 0;
675 }
676
677 /* eat the silly terminating '\n' */
678 if (inCount == 1 && *eventData == '\n') {
679 eventData++;
680 inCount--;
681 }
682
683 if (inCount != 0) {
684 fprintf(stderr,
Andrew Hsiehd2c8f522012-02-27 16:48:18 -0800685 "Warning: leftover binary log data (%zu bytes)\n", inCount);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700686 }
687
688 /*
689 * Terminate the buffer. The NUL byte does not count as part of
690 * entry->messageLen.
691 */
692 *outBuf = '\0';
693 entry->messageLen = outBuf - messageBuf;
694 assert(entry->messageLen == (messageBufLen-1) - outRemaining);
695
696 entry->message = messageBuf;
697
698 return 0;
699}
700
701/**
702 * Formats a log message into a buffer
703 *
704 * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer
705 * If return value != defaultBuffer, caller must call free()
706 * Returns NULL on malloc error
707 */
708
709char *android_log_formatLogLine (
710 AndroidLogFormat *p_format,
711 char *defaultBuffer,
712 size_t defaultBufferSize,
713 const AndroidLogEntry *entry,
714 size_t *p_outLength)
715{
716#if defined(HAVE_LOCALTIME_R)
717 struct tm tmBuf;
718#endif
719 struct tm* ptm;
720 char timeBuf[32];
721 char headerBuf[128];
722 char prefixBuf[128], suffixBuf[128];
723 char priChar;
724 int prefixSuffixIsHeaderFooter = 0;
725 char * ret = NULL;
726
727 priChar = filterPriToChar(entry->priority);
728
729 /*
730 * Get the current date/time in pretty form
731 *
732 * It's often useful when examining a log with "less" to jump to
733 * a specific point in the file by searching for the date/time stamp.
734 * For this reason it's very annoying to have regexp meta characters
735 * in the time stamp. Don't use forward slashes, parenthesis,
736 * brackets, asterisks, or other special chars here.
737 */
738#if defined(HAVE_LOCALTIME_R)
739 ptm = localtime_r(&(entry->tv_sec), &tmBuf);
740#else
741 ptm = localtime(&(entry->tv_sec));
742#endif
743 //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
744 strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
745
746 /*
747 * Construct a buffer containing the log header and log message.
748 */
749 size_t prefixLen, suffixLen;
750
751 switch (p_format->format) {
752 case FORMAT_TAG:
753 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
754 "%c/%-8s: ", priChar, entry->tag);
755 strcpy(suffixBuf, "\n"); suffixLen = 1;
756 break;
757 case FORMAT_PROCESS:
758 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
759 "%c(%5d) ", priChar, entry->pid);
760 suffixLen = snprintf(suffixBuf, sizeof(suffixBuf),
761 " (%s)\n", entry->tag);
762 break;
763 case FORMAT_THREAD:
764 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
Andrew Hsiehd2c8f522012-02-27 16:48:18 -0800765 "%c(%5d:%5d) ", priChar, entry->pid, entry->tid);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700766 strcpy(suffixBuf, "\n");
767 suffixLen = 1;
768 break;
769 case FORMAT_RAW:
770 prefixBuf[0] = 0;
771 prefixLen = 0;
772 strcpy(suffixBuf, "\n");
773 suffixLen = 1;
774 break;
775 case FORMAT_TIME:
776 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
777 "%s.%03ld %c/%-8s(%5d): ", timeBuf, entry->tv_nsec / 1000000,
778 priChar, entry->tag, entry->pid);
779 strcpy(suffixBuf, "\n");
780 suffixLen = 1;
781 break;
782 case FORMAT_THREADTIME:
783 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
784 "%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000,
Andrew Hsiehd2c8f522012-02-27 16:48:18 -0800785 entry->pid, entry->tid, priChar, entry->tag);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700786 strcpy(suffixBuf, "\n");
787 suffixLen = 1;
788 break;
789 case FORMAT_LONG:
790 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
Andrew Hsiehd2c8f522012-02-27 16:48:18 -0800791 "[ %s.%03ld %5d:%5d %c/%-8s ]\n",
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700792 timeBuf, entry->tv_nsec / 1000000, entry->pid,
Andrew Hsiehd2c8f522012-02-27 16:48:18 -0800793 entry->tid, priChar, entry->tag);
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700794 strcpy(suffixBuf, "\n\n");
795 suffixLen = 2;
796 prefixSuffixIsHeaderFooter = 1;
797 break;
798 case FORMAT_BRIEF:
799 default:
800 prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
801 "%c/%-8s(%5d): ", priChar, entry->tag, entry->pid);
802 strcpy(suffixBuf, "\n");
803 suffixLen = 1;
804 break;
805 }
Keith Prestonb45b5c92010-02-11 15:12:53 -0600806 /* snprintf has a weird return value. It returns what would have been
807 * written given a large enough buffer. In the case that the prefix is
808 * longer then our buffer(128), it messes up the calculations below
809 * possibly causing heap corruption. To avoid this we double check and
810 * set the length at the maximum (size minus null byte)
811 */
812 if(prefixLen >= sizeof(prefixBuf))
813 prefixLen = sizeof(prefixBuf) - 1;
814 if(suffixLen >= sizeof(suffixBuf))
815 suffixLen = sizeof(suffixBuf) - 1;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700816
817 /* the following code is tragically unreadable */
818
819 size_t numLines;
820 size_t i;
821 char *p;
822 size_t bufferSize;
823 const char *pm;
824
825 if (prefixSuffixIsHeaderFooter) {
826 // we're just wrapping message with a header/footer
827 numLines = 1;
828 } else {
829 pm = entry->message;
830 numLines = 0;
831
832 // The line-end finding here must match the line-end finding
833 // in for ( ... numLines...) loop below
834 while (pm < (entry->message + entry->messageLen)) {
835 if (*pm++ == '\n') numLines++;
836 }
837 // plus one line for anything not newline-terminated at the end
838 if (pm > entry->message && *(pm-1) != '\n') numLines++;
839 }
840
841 // this is an upper bound--newlines in message may be counted
842 // extraneously
843 bufferSize = (numLines * (prefixLen + suffixLen)) + entry->messageLen + 1;
844
845 if (defaultBufferSize >= bufferSize) {
846 ret = defaultBuffer;
847 } else {
848 ret = (char *)malloc(bufferSize);
849
850 if (ret == NULL) {
851 return ret;
852 }
853 }
854
855 ret[0] = '\0'; /* to start strcat off */
856
857 p = ret;
858 pm = entry->message;
859
860 if (prefixSuffixIsHeaderFooter) {
861 strcat(p, prefixBuf);
862 p += prefixLen;
863 strncat(p, entry->message, entry->messageLen);
864 p += entry->messageLen;
865 strcat(p, suffixBuf);
866 p += suffixLen;
867 } else {
868 while(pm < (entry->message + entry->messageLen)) {
869 const char *lineStart;
870 size_t lineLen;
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700871 lineStart = pm;
872
873 // Find the next end-of-line in message
874 while (pm < (entry->message + entry->messageLen)
875 && *pm != '\n') pm++;
876 lineLen = pm - lineStart;
877
878 strcat(p, prefixBuf);
879 p += prefixLen;
880 strncat(p, lineStart, lineLen);
881 p += lineLen;
882 strcat(p, suffixBuf);
883 p += suffixLen;
884
885 if (*pm == '\n') pm++;
886 }
887 }
888
889 if (p_outLength != NULL) {
890 *p_outLength = p - ret;
891 }
892
893 return ret;
894}
895
896/**
897 * Either print or do not print log line, based on filter
898 *
899 * Returns count bytes written
900 */
901
Joe Onoratoe2bf2ea2010-03-01 09:11:54 -0800902int android_log_printLogLine(
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700903 AndroidLogFormat *p_format,
904 int fd,
905 const AndroidLogEntry *entry)
906{
907 int ret;
908 char defaultBuffer[512];
909 char *outBuffer = NULL;
910 size_t totalLen;
911
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700912 outBuffer = android_log_formatLogLine(p_format, defaultBuffer,
913 sizeof(defaultBuffer), entry, &totalLen);
914
915 if (!outBuffer)
916 return -1;
917
918 do {
919 ret = write(fd, outBuffer, totalLen);
920 } while (ret < 0 && errno == EINTR);
921
922 if (ret < 0) {
923 fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
924 ret = 0;
925 goto done;
926 }
927
928 if (((size_t)ret) < totalLen) {
929 fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", ret,
930 (int)totalLen);
931 goto done;
932 }
933
934done:
935 if (outBuffer != defaultBuffer) {
936 free(outBuffer);
937 }
938
939 return ret;
940}
941
942
943
944void logprint_run_tests()
945{
946#if 0
947
948 fprintf(stderr, "tests disabled\n");
949
950#else
951
952 int err;
953 const char *tag;
954 AndroidLogFormat *p_format;
955
956 p_format = android_log_format_new();
957
958 fprintf(stderr, "running tests\n");
959
960 tag = "random";
961
962 android_log_addFilterRule(p_format,"*:i");
963
964 assert (ANDROID_LOG_INFO == filterPriForTag(p_format, "random"));
965 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
966 android_log_addFilterRule(p_format, "*");
967 assert (ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
968 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
969 android_log_addFilterRule(p_format, "*:v");
970 assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
971 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
972 android_log_addFilterRule(p_format, "*:i");
973 assert (ANDROID_LOG_INFO == filterPriForTag(p_format, "random"));
974 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
975
976 android_log_addFilterRule(p_format, "random");
977 assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
978 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
979 android_log_addFilterRule(p_format, "random:v");
980 assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
981 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
982 android_log_addFilterRule(p_format, "random:d");
983 assert (ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
984 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
985 android_log_addFilterRule(p_format, "random:w");
986 assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
987 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
988
989 android_log_addFilterRule(p_format, "crap:*");
990 assert (ANDROID_LOG_VERBOSE== filterPriForTag(p_format, "crap"));
991 assert(android_log_shouldPrintLine(p_format, "crap", ANDROID_LOG_VERBOSE) > 0);
992
993 // invalid expression
994 err = android_log_addFilterRule(p_format, "random:z");
995 assert (err < 0);
996 assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
997 assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
998
999 // Issue #550946
1000 err = android_log_addFilterString(p_format, " ");
1001 assert(err == 0);
1002 assert(ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
1003
1004 // note trailing space
1005 err = android_log_addFilterString(p_format, "*:s random:d ");
1006 assert(err == 0);
1007 assert(ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
1008
1009 err = android_log_addFilterString(p_format, "*:s random:z");
1010 assert(err < 0);
1011
1012
1013#if 0
1014 char *ret;
1015 char defaultBuffer[512];
1016
1017 ret = android_log_formatLogLine(p_format,
1018 defaultBuffer, sizeof(defaultBuffer), 0, ANDROID_LOG_ERROR, 123,
1019 123, 123, "random", "nofile", strlen("Hello"), "Hello", NULL);
1020#endif
1021
1022
1023 fprintf(stderr, "tests complete\n");
1024#endif
1025}