1 /* //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 33 typedef struct FilterInfo_t { 34 char *mTag; 35 android_LogPriority mPri; 36 struct FilterInfo_t *p_next; 37 } FilterInfo; 38 39 struct AndroidLogFormat_t { 40 android_LogPriority global_pri; 41 FilterInfo *filters; 42 AndroidLogPrintFormat format; 43 }; 44 filterinfo_new(const char * tag,android_LogPriority pri)45 static 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 filterinfo_free(FilterInfo * p_info)56 static 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 */ filterCharToPri(char c)70 static 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 filterPriToChar(android_LogPriority pri)105 static 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 filterPriForTag(AndroidLogFormat * p_format,const char * tag)122 static 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 */ dumpFilters(AndroidLogFormat * p_format)144 static 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 */ android_log_shouldPrintLine(AndroidLogFormat * p_format,const char * tag,android_LogPriority pri)164 int android_log_shouldPrintLine ( 165 AndroidLogFormat *p_format, const char *tag, android_LogPriority pri) 166 { 167 return pri >= filterPriForTag(p_format, tag); 168 } 169 android_log_format_new()170 AndroidLogFormat *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 android_log_format_free(AndroidLogFormat * p_format)182 void 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 android_log_setPrintFormat(AndroidLogFormat * p_format,AndroidLogPrintFormat format)200 void 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 */ android_log_formatFromString(const char * formatString)209 AndroidLogPrintFormat 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 android_log_addFilterRule(AndroidLogFormat * p_format,const char * filterExpression)235 int 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; 292 error: 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 android_log_addFilterString(AndroidLogFormat * p_format,const char * filterString)308 int 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; 330 error: 331 free (filterStringCopy); 332 return -1; 333 } 334 strip_end(char * str)335 static 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 */ android_log_processLogBuffer(struct logger_entry * buf,AndroidLogEntry * entry)351 int 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 */ get4LE(const uint8_t * src)372 static 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 */ get8LE(const uint8_t * src)380 static 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 */ android_log_printBinaryEvent(const unsigned char ** pEventData,size_t * pEventDataLen,char ** pOutBuf,size_t * pOutBufLen)401 static 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 539 bail: 540 *pEventData = eventData; 541 *pEventDataLen = eventDataLen; 542 *pOutBuf = outBuf; 543 *pOutBufLen = outBufLen; 544 return result; 545 546 no_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 */ android_log_processBinaryLogBuffer(struct logger_entry * buf,AndroidLogEntry * entry,const EventTagMap * map,char * messageBuf,int messageBufLen)559 int 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 android_log_formatLogLine(AndroidLogFormat * p_format,char * defaultBuffer,size_t defaultBufferSize,const AndroidLogEntry * entry,size_t * p_outLength)660 char *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 android_log_filterAndPrintLogLine(AndroidLogFormat * p_format,int fd,const AndroidLogEntry * entry)844 int 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 881 done: 882 if (outBuffer != defaultBuffer) { 883 free(outBuffer); 884 } 885 886 return ret; 887 } 888 889 890 logprint_run_tests()891 void 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 } 973