1
/* //device/libs/cutils/logprint.c
3
** Copyright 2006, The Android Open Source Project
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
9
** http://www.apache.org/licenses/LICENSE-2.0
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.
18
#define _GNU_SOURCE /* for asprintf */
27
#include <arpa/inet.h>
29
#include <cutils/logd.h>
30
#include <cutils/logprint.h>
32
typedef struct FilterInfo_t {
34
android_LogPriority mPri;
35
struct FilterInfo_t *p_next;
38
struct AndroidLogFormat_t {
39
android_LogPriority global_pri;
41
AndroidLogPrintFormat format;
44
static FilterInfo * filterinfo_new(const char * tag, android_LogPriority pri)
48
p_ret = (FilterInfo *)calloc(1, sizeof(FilterInfo));
49
p_ret->mTag = strdup(tag);
55
static void filterinfo_free(FilterInfo *p_info)
66
* Note: also accepts 0-9 priorities
67
* returns ANDROID_LOG_UNKNOWN if the character is unrecognized
69
static android_LogPriority filterCharToPri (char c)
71
android_LogPriority pri;
75
if (c >= '0' && c <= '9') {
76
if (c >= ('0'+ANDROID_LOG_SILENT)) {
77
pri = ANDROID_LOG_VERBOSE;
79
pri = (android_LogPriority)(c - '0');
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;
98
pri = ANDROID_LOG_UNKNOWN;
104
static char filterPriToChar (android_LogPriority 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';
115
case ANDROID_LOG_DEFAULT:
116
case ANDROID_LOG_UNKNOWN:
121
static android_LogPriority filterPriForTag(
122
AndroidLogFormat *p_format, const char *tag)
124
FilterInfo *p_curFilter;
126
for (p_curFilter = p_format->filters
127
; p_curFilter != NULL
128
; p_curFilter = p_curFilter->p_next
130
if (0 == strcmp(tag, p_curFilter->mTag)) {
131
if (p_curFilter->mPri == ANDROID_LOG_DEFAULT) {
132
return p_format->global_pri;
134
return p_curFilter->mPri;
139
return p_format->global_pri;
143
static void dumpFilters(AndroidLogFormat *p_format)
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);
152
fprintf(stderr,"%s:%c\n", p_fi->mTag, cPri);
155
fprintf(stderr,"*:%c\n", filterPriToChar(p_format->global_pri));
160
* returns 1 if this log line should be printed based on its priority
161
* and tag, and 0 if it should not
163
int android_log_shouldPrintLine (
164
AndroidLogFormat *p_format, const char *tag, android_LogPriority pri)
166
return pri >= filterPriForTag(p_format, tag);
169
AndroidLogFormat *android_log_format_new()
171
AndroidLogFormat *p_ret;
173
p_ret = calloc(1, sizeof(AndroidLogFormat));
175
p_ret->global_pri = ANDROID_LOG_VERBOSE;
176
p_ret->format = FORMAT_BRIEF;
181
void android_log_format_free(AndroidLogFormat *p_format)
183
FilterInfo *p_info, *p_info_old;
185
p_info = p_format->filters;
187
while (p_info != NULL) {
189
p_info = p_info->p_next;
199
void android_log_setPrintFormat(AndroidLogFormat *p_format,
200
AndroidLogPrintFormat format)
202
p_format->format=format;
206
* Returns FORMAT_OFF on invalid string
208
AndroidLogPrintFormat android_log_formatFromString(const char * formatString)
210
static AndroidLogPrintFormat format;
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;
226
* filterExpression: a single filter expression
229
* returns 0 on success and -1 on invalid expression
231
* Assumes single threaded execution
234
int android_log_addFilterRule(AndroidLogFormat *p_format,
235
const char *filterExpression)
238
size_t tagNameLength;
239
android_LogPriority pri = ANDROID_LOG_DEFAULT;
241
tagNameLength = strcspn(filterExpression, ":");
243
if (tagNameLength == 0) {
247
if(filterExpression[tagNameLength] == ':') {
248
pri = filterCharToPri(filterExpression[tagNameLength+1]);
250
if (pri == ANDROID_LOG_UNKNOWN) {
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
259
if (pri == ANDROID_LOG_DEFAULT) {
260
pri = ANDROID_LOG_DEBUG;
263
p_format->global_pri = pri;
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;
273
// Presently HAVE_STRNDUP is never defined, so the second case is always taken
274
// Darwin doesn't have strnup, everything else does
276
tagName = strndup(filterExpression, tagNameLength);
278
//a few extra bytes copied...
279
tagName = strdup(filterExpression);
280
tagName[tagNameLength] = '\0';
281
#endif /*HAVE_STRNDUP*/
283
FilterInfo *p_fi = filterinfo_new(tagName, pri);
286
p_fi->p_next = p_format->filters;
287
p_format->filters = p_fi;
297
* filterString: a comma/whitespace-separated set of filter expressions
301
* returns 0 on success and -1 on invalid expression
303
* Assumes single threaded execution
307
int android_log_addFilterString(AndroidLogFormat *p_format,
308
const char *filterString)
310
char *filterStringCopy = strdup (filterString);
311
char *p_cur = filterStringCopy;
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);
327
free (filterStringCopy);
330
free (filterStringCopy);
334
static inline char * strip_end(char *str)
336
char *end = str + strlen(str) - 1;
338
while (end >= str && isspace(*end))
344
* Splits a wire-format buffer into an AndroidLogEntry
345
* entry allocated by caller. Pointers will point directly into buf
347
* Returns 0 on success and -1 on invalid wire format (entry will be
348
* in unspecified state)
350
int android_log_processLogBuffer(struct logger_entry *buf,
351
AndroidLogEntry *entry)
353
entry->tv_sec = buf->sec;
354
entry->tv_nsec = buf->nsec;
355
entry->pid = buf->pid;
356
entry->tid = buf->tid;
359
* format: <priority:1><tag:N>\0<message:N>\0
362
* starts at buf->msg+1
364
* starts at buf->msg+1+len(tag)+1
366
* The message may have been truncated by the kernel log driver.
367
* When that happens, we must null-terminate the message ourselves.
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");
380
for (i = 1; i < buf->len; i++) {
381
if (buf->msg[i] == '\0') {
382
if (msgStart == -1) {
391
if (msgStart == -1) {
392
fprintf(stderr, "+++ LOG: malformed log message\n");
396
// incoming message not null-terminated; force it
397
msgEnd = buf->len - 1;
398
buf->msg[msgEnd] = '\0';
401
entry->priority = buf->msg[0];
402
entry->tag = buf->msg + 1;
403
entry->message = buf->msg + msgStart;
404
entry->messageLen = msgEnd - msgStart;
410
* Extract a 4-byte value from a byte stream.
412
static inline uint32_t get4LE(const uint8_t* src)
414
return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
418
* Extract an 8-byte value from a byte stream.
420
static inline uint64_t get8LE(const uint8_t* src)
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;
431
* Recursively convert binary log data to printable form.
433
* This needs to be recursive because you can have lists of lists.
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
439
* Returns 0 on success, 1 on buffer full, -1 on failure.
441
static int android_log_printBinaryEvent(const unsigned char** pEventData,
442
size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen)
444
const unsigned char* eventData = *pEventData;
445
size_t eventDataLen = *pEventDataLen;
446
char* outBuf = *pOutBuf;
447
size_t outBufLen = *pOutBufLen;
452
if (eventDataLen < 1)
457
//fprintf(stderr, "--- type=%d (rem len=%d)\n", type, eventDataLen);
461
/* 32-bit signed int */
465
if (eventDataLen < 4)
467
ival = get4LE(eventData);
471
outCount = snprintf(outBuf, outBufLen, "%d", ival);
472
if (outCount < outBufLen) {
474
outBufLen -= outCount;
481
case EVENT_TYPE_LONG:
482
/* 64-bit signed long */
486
if (eventDataLen < 8)
488
lval = get8LE(eventData);
492
outCount = snprintf(outBuf, outBufLen, "%lld", lval);
493
if (outCount < outBufLen) {
495
outBufLen -= outCount;
502
case EVENT_TYPE_STRING:
503
/* UTF-8 chars, not NULL-terminated */
507
if (eventDataLen < 4)
509
strLen = get4LE(eventData);
513
if (eventDataLen < strLen)
516
if (strLen < outBufLen) {
517
memcpy(outBuf, eventData, strLen);
520
} else if (outBufLen > 0) {
521
/* copy what we can */
522
memcpy(outBuf, eventData, outBufLen);
524
outBufLen -= outBufLen;
528
eventDataLen -= strLen;
531
case EVENT_TYPE_LIST:
532
/* N items, all different types */
537
if (eventDataLen < 1)
540
count = *eventData++;
550
for (i = 0; i < count; i++) {
551
result = android_log_printBinaryEvent(&eventData, &eventDataLen,
552
&outBuf, &outBufLen);
575
fprintf(stderr, "Unknown binary event type %d\n", type);
580
*pEventData = eventData;
581
*pEventDataLen = eventDataLen;
583
*pOutBufLen = outBufLen;
592
* Convert a binary log entry to ASCII form.
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
599
int android_log_processBinaryLogBuffer(struct logger_entry *buf,
600
AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf,
604
unsigned int tagIndex;
605
const unsigned char* eventData;
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;
616
eventData = (const unsigned char*) buf->msg;
620
tagIndex = get4LE(eventData);
625
entry->tag = android_lookupEventTag(map, tagIndex);
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.
635
if (entry->tag == NULL) {
638
tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex);
639
entry->tag = messageBuf;
640
messageBuf += tagLen+1;
641
messageBufLen -= tagLen+1;
645
* Format the event log data into the buffer.
647
char* outBuf = messageBuf;
648
size_t outRemaining = messageBufLen-1; /* leave one for nul byte */
650
result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
653
fprintf(stderr, "Binary log entry conversion failed\n");
655
} else if (result == 1) {
656
if (outBuf > messageBuf) {
657
/* leave an indicator */
660
/* no room to output anything at all */
664
/* pretend we ate all the data */
668
/* eat the silly terminating '\n' */
669
if (inCount == 1 && *eventData == '\n') {
676
"Warning: leftover binary log data (%zu bytes)\n", inCount);
680
* Terminate the buffer. The NUL byte does not count as part of
684
entry->messageLen = outBuf - messageBuf;
685
assert(entry->messageLen == (messageBufLen-1) - outRemaining);
687
entry->message = messageBuf;
693
* Formats a log message into a buffer
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
700
char *android_log_formatLogLine (
701
AndroidLogFormat *p_format,
703
size_t defaultBufferSize,
704
const AndroidLogEntry *entry,
707
#if defined(HAVE_LOCALTIME_R)
713
char prefixBuf[128], suffixBuf[128];
715
int prefixSuffixIsHeaderFooter = 0;
718
priChar = filterPriToChar(entry->priority);
721
* Get the current date/time in pretty form
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.
729
#if defined(HAVE_LOCALTIME_R)
730
ptm = localtime_r(&(entry->tv_sec), &tmBuf);
732
ptm = localtime(&(entry->tv_sec));
734
//strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
735
strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
738
* Construct a buffer containing the log header and log message.
740
size_t prefixLen, suffixLen;
742
switch (p_format->format) {
744
prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
745
"%c/%-8s: ", priChar, entry->tag);
746
strcpy(suffixBuf, "\n"); suffixLen = 1;
749
prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
750
"%c(%5d) ", priChar, entry->pid);
751
suffixLen = snprintf(suffixBuf, sizeof(suffixBuf),
752
" (%s)\n", entry->tag);
755
prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
756
"%c(%5d:%5d) ", priChar, entry->pid, entry->tid);
757
strcpy(suffixBuf, "\n");
763
strcpy(suffixBuf, "\n");
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");
773
case FORMAT_THREADTIME:
774
prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
775
"%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000,
776
entry->pid, entry->tid, priChar, entry->tag);
777
strcpy(suffixBuf, "\n");
781
prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
782
"[ %s.%03ld %5d:%5d %c/%-8s ]\n",
783
timeBuf, entry->tv_nsec / 1000000, entry->pid,
784
entry->tid, priChar, entry->tag);
785
strcpy(suffixBuf, "\n\n");
787
prefixSuffixIsHeaderFooter = 1;
791
prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
792
"%c/%-8s(%5d): ", priChar, entry->tag, entry->pid);
793
strcpy(suffixBuf, "\n");
797
/* 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)
803
if(prefixLen >= sizeof(prefixBuf))
804
prefixLen = sizeof(prefixBuf) - 1;
805
if(suffixLen >= sizeof(suffixBuf))
806
suffixLen = sizeof(suffixBuf) - 1;
808
/* the following code is tragically unreadable */
816
if (prefixSuffixIsHeaderFooter) {
817
// we're just wrapping message with a header/footer
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++;
828
// plus one line for anything not newline-terminated at the end
829
if (pm > entry->message && *(pm-1) != '\n') numLines++;
832
// this is an upper bound--newlines in message may be counted
834
bufferSize = (numLines * (prefixLen + suffixLen)) + entry->messageLen + 1;
836
if (defaultBufferSize >= bufferSize) {
839
ret = (char *)malloc(bufferSize);
846
ret[0] = '\0'; /* to start strcat off */
851
if (prefixSuffixIsHeaderFooter) {
852
strcat(p, prefixBuf);
854
strncat(p, entry->message, entry->messageLen);
855
p += entry->messageLen;
856
strcat(p, suffixBuf);
859
while(pm < (entry->message + entry->messageLen)) {
860
const char *lineStart;
864
// Find the next end-of-line in message
865
while (pm < (entry->message + entry->messageLen)
866
&& *pm != '\n') pm++;
867
lineLen = pm - lineStart;
869
strcat(p, prefixBuf);
871
strncat(p, lineStart, lineLen);
873
strcat(p, suffixBuf);
876
if (*pm == '\n') pm++;
880
if (p_outLength != NULL) {
881
*p_outLength = p - ret;
888
* Either print or do not print log line, based on filter
890
* Returns count bytes written
893
int android_log_printLogLine(
894
AndroidLogFormat *p_format,
896
const AndroidLogEntry *entry)
899
char defaultBuffer[512];
900
char *outBuffer = NULL;
903
outBuffer = android_log_formatLogLine(p_format, defaultBuffer,
904
sizeof(defaultBuffer), entry, &totalLen);
910
ret = write(fd, outBuffer, totalLen);
911
} while (ret < 0 && errno == EINTR);
914
fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
919
if (((size_t)ret) < totalLen) {
920
fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", ret,
926
if (outBuffer != defaultBuffer) {
935
void logprint_run_tests()
939
fprintf(stderr, "tests disabled\n");
945
AndroidLogFormat *p_format;
947
p_format = android_log_format_new();
949
fprintf(stderr, "running tests\n");
953
android_log_addFilterRule(p_format,"*:i");
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);
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);
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);
984
// invalid expression
985
err = android_log_addFilterRule(p_format, "random:z");
987
assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
988
assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
991
err = android_log_addFilterString(p_format, " ");
993
assert(ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
995
// note trailing space
996
err = android_log_addFilterString(p_format, "*:s random:d ");
998
assert(ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
1000
err = android_log_addFilterString(p_format, "*:s random:z");
1006
char defaultBuffer[512];
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);
1014
fprintf(stderr, "tests complete\n");