summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Salyzyn2016-10-18 13:30:11 -0500
committerMark Salyzyn2016-11-04 17:22:52 -0500
commit4fd0507b20d5afcc7b67ec355dcd89df62e62fc6 (patch)
tree1ee80a99ec5ecedb6615909f9ef138d862755000 /liblog/logprint.c
parent530711b39e0447b0ce6824de936cedc294634e0e (diff)
downloadplatform-system-core-4fd0507b20d5afcc7b67ec355dcd89df62e62fc6.tar.gz
platform-system-core-4fd0507b20d5afcc7b67ec355dcd89df62e62fc6.tar.xz
platform-system-core-4fd0507b20d5afcc7b67ec355dcd89df62e62fc6.zip
liblog: logcat: logprint support -v descriptive
Expand logprint feature to pull out the log tag description fields, parse them and merge into the logging content. Add -v descriptive, -v colour(british, hidden) and -v help. Also added a unit test for the descriptive format borrowing from event tags that have been unchanged since 2009. Had to add -v help because we have too many undocumented formats and format adverbs. Test: gTest logcat-unit-tests --gtest_filter=logcat.descriptive Bug: 31456426 Change-Id: I93a1c003b7a3f4c332544946fdedb7277919cec3
Diffstat (limited to 'liblog/logprint.c')
-rw-r--r--liblog/logprint.c286
1 files changed, 252 insertions, 34 deletions
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 1ff71363c..fb942a1a5 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -21,13 +21,13 @@
21#include <assert.h> 21#include <assert.h>
22#include <ctype.h> 22#include <ctype.h>
23#include <errno.h> 23#include <errno.h>
24#include <inttypes.h>
24#include <pwd.h> 25#include <pwd.h>
25#include <stdbool.h> 26#include <stdbool.h>
26#include <stdint.h> 27#include <stdint.h>
27#include <stdio.h> 28#include <stdio.h>
28#include <stdlib.h> 29#include <stdlib.h>
29#include <string.h> 30#include <string.h>
30#include <inttypes.h>
31#include <sys/param.h> 31#include <sys/param.h>
32#include <sys/types.h> 32#include <sys/types.h>
33 33
@@ -58,9 +58,16 @@ struct AndroidLogFormat_t {
58 bool epoch_output; 58 bool epoch_output;
59 bool monotonic_output; 59 bool monotonic_output;
60 bool uid_output; 60 bool uid_output;
61 bool descriptive_output;
61}; 62};
62 63
63/* 64/*
65 * API issues prevent us from exposing "descriptive" in AndroidLogFormat_t
66 * during android_log_processBinaryLogBuffer(), so we break layering.
67 */
68static bool descriptive_output = false;
69
70/*
64 * gnome-terminal color tags 71 * gnome-terminal color tags
65 * See http://misc.flogisoft.com/bash/tip_colors_and_formatting 72 * See http://misc.flogisoft.com/bash/tip_colors_and_formatting
66 * for ideas on how to set the forground color of the text for xterm. 73 * for ideas on how to set the forground color of the text for xterm.
@@ -209,6 +216,8 @@ LIBLOG_ABI_PUBLIC AndroidLogFormat *android_log_format_new()
209 p_ret->epoch_output = false; 216 p_ret->epoch_output = false;
210 p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC; 217 p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC;
211 p_ret->uid_output = false; 218 p_ret->uid_output = false;
219 p_ret->descriptive_output = false;
220 descriptive_output = false;
212 221
213 return p_ret; 222 return p_ret;
214} 223}
@@ -267,6 +276,10 @@ LIBLOG_ABI_PUBLIC int android_log_setPrintFormat(
267 case FORMAT_MODIFIER_UID: 276 case FORMAT_MODIFIER_UID:
268 p_format->uid_output = true; 277 p_format->uid_output = true;
269 return 0; 278 return 0;
279 case FORMAT_MODIFIER_DESCRIPT:
280 p_format->descriptive_output = true;
281 descriptive_output = true;
282 return 0;
270 default: 283 default:
271 break; 284 break;
272 } 285 }
@@ -294,6 +307,7 @@ LIBLOG_ABI_PUBLIC AndroidLogPrintFormat android_log_formatFromString(
294 else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME; 307 else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
295 else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG; 308 else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
296 else if (strcmp(formatString, "color") == 0) format = FORMAT_MODIFIER_COLOR; 309 else if (strcmp(formatString, "color") == 0) format = FORMAT_MODIFIER_COLOR;
310 else if (strcmp(formatString, "colour") == 0) format = FORMAT_MODIFIER_COLOR;
297 else if (strcmp(formatString, "usec") == 0) format = FORMAT_MODIFIER_TIME_USEC; 311 else if (strcmp(formatString, "usec") == 0) format = FORMAT_MODIFIER_TIME_USEC;
298 else if (strcmp(formatString, "printable") == 0) format = FORMAT_MODIFIER_PRINTABLE; 312 else if (strcmp(formatString, "printable") == 0) format = FORMAT_MODIFIER_PRINTABLE;
299 else if (strcmp(formatString, "year") == 0) format = FORMAT_MODIFIER_YEAR; 313 else if (strcmp(formatString, "year") == 0) format = FORMAT_MODIFIER_YEAR;
@@ -301,6 +315,7 @@ LIBLOG_ABI_PUBLIC AndroidLogPrintFormat android_log_formatFromString(
301 else if (strcmp(formatString, "epoch") == 0) format = FORMAT_MODIFIER_EPOCH; 315 else if (strcmp(formatString, "epoch") == 0) format = FORMAT_MODIFIER_EPOCH;
302 else if (strcmp(formatString, "monotonic") == 0) format = FORMAT_MODIFIER_MONOTONIC; 316 else if (strcmp(formatString, "monotonic") == 0) format = FORMAT_MODIFIER_MONOTONIC;
303 else if (strcmp(formatString, "uid") == 0) format = FORMAT_MODIFIER_UID; 317 else if (strcmp(formatString, "uid") == 0) format = FORMAT_MODIFIER_UID;
318 else if (strcmp(formatString, "descriptive") == 0) format = FORMAT_MODIFIER_DESCRIPT;
304 else { 319 else {
305 extern char *tzname[2]; 320 extern char *tzname[2];
306 static const char gmt[] = "GMT"; 321 static const char gmt[] = "GMT";
@@ -566,6 +581,19 @@ static inline uint64_t get8LE(const uint8_t* src)
566 return ((uint64_t) high << 32) | (uint64_t) low; 581 return ((uint64_t) high << 32) | (uint64_t) low;
567} 582}
568 583
584static bool findChar(const char** cp, size_t* len, int c) {
585 while (*len && isspace(**cp)) {
586 ++*cp;
587 --*len;
588 }
589 if (c == INT_MAX) return *len;
590 if (*len && (**cp == c)) {
591 ++*cp;
592 --*len;
593 return true;
594 }
595 return false;
596}
569 597
570/* 598/*
571 * Recursively convert binary log data to printable form. 599 * Recursively convert binary log data to printable form.
@@ -578,27 +606,128 @@ static inline uint64_t get8LE(const uint8_t* src)
578 * 606 *
579 * Returns 0 on success, 1 on buffer full, -1 on failure. 607 * Returns 0 on success, 1 on buffer full, -1 on failure.
580 */ 608 */
609enum objectType {
610 TYPE_OBJECTS = '1',
611 TYPE_BYTES = '2',
612 TYPE_MILLISECONDS = '3',
613 TYPE_ALLOCATIONS = '4',
614 TYPE_ID = '5',
615 TYPE_PERCENT = '6'
616};
617
581static int android_log_printBinaryEvent(const unsigned char** pEventData, 618static int android_log_printBinaryEvent(const unsigned char** pEventData,
582 size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen) 619 size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen,
620 const char** fmtStr, size_t* fmtLen)
583{ 621{
584 const unsigned char* eventData = *pEventData; 622 const unsigned char* eventData = *pEventData;
585 size_t eventDataLen = *pEventDataLen; 623 size_t eventDataLen = *pEventDataLen;
586 char* outBuf = *pOutBuf; 624 char* outBuf = *pOutBuf;
625 char* outBufSave = outBuf;
587 size_t outBufLen = *pOutBufLen; 626 size_t outBufLen = *pOutBufLen;
627 size_t outBufLenSave = outBufLen;
588 unsigned char type; 628 unsigned char type;
589 size_t outCount; 629 size_t outCount;
590 int result = 0; 630 int result = 0;
631 const char* cp;
632 size_t len;
633 int64_t lval;
591 634
592 if (eventDataLen < 1) 635 if (eventDataLen < 1)
593 return -1; 636 return -1;
594 type = *eventData++; 637 type = *eventData++;
595 eventDataLen--; 638 eventDataLen--;
596 639
640 cp = NULL;
641 len = 0;
642 if (fmtStr && *fmtStr && fmtLen && *fmtLen && **fmtStr) {
643 cp = *fmtStr;
644 len = *fmtLen;
645 }
646 /*
647 * event.logtag format specification:
648 *
649 * Optionally, after the tag names can be put a description for the value(s)
650 * of the tag. Description are in the format
651 * (<name>|data type[|data unit])
652 * Multiple values are separated by commas.
653 *
654 * The data type is a number from the following values:
655 * 1: int
656 * 2: long
657 * 3: string
658 * 4: list
659 * 5: float
660 *
661 * The data unit is a number taken from the following list:
662 * 1: Number of objects
663 * 2: Number of bytes
664 * 3: Number of milliseconds
665 * 4: Number of allocations
666 * 5: Id
667 * 6: Percent
668 * Default value for data of type int/long is 2 (bytes).
669 */
670 if (!cp || !findChar(&cp, &len, '(')) {
671 len = 0;
672 } else {
673 char* outBufLastSpace = NULL;
674
675 findChar(&cp, &len, INT_MAX);
676 while (len && *cp && (*cp != '|') && (*cp != ')')) {
677 if (outBufLen <= 0) {
678 /* halt output */
679 goto no_room;
680 }
681 outBufLastSpace = isspace(*cp) ? outBuf : NULL;
682 *outBuf = *cp;
683 ++outBuf;
684 ++cp;
685 --outBufLen;
686 --len;
687 }
688 if (outBufLastSpace) {
689 outBufLen += outBuf - outBufLastSpace;
690 outBuf = outBufLastSpace;
691 }
692 if (outBufLen <= 0) {
693 /* halt output */
694 goto no_room;
695 }
696 if (outBufSave != outBuf) {
697 *outBuf = '=';
698 ++outBuf;
699 --outBufLen;
700 }
701
702 if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
703 static const unsigned char typeTable[] = {
704 EVENT_TYPE_INT,
705 EVENT_TYPE_LONG,
706 EVENT_TYPE_STRING,
707 EVENT_TYPE_LIST,
708 EVENT_TYPE_FLOAT
709 };
710
711 if ((*cp >= '1') &&
712 (*cp < (char)('1' + (sizeof(typeTable) / sizeof(typeTable[0])))) &&
713 (type != typeTable[(size_t)(*cp - '1')])) len = 0;
714
715 if (len) {
716 ++cp;
717 --len;
718 } else {
719 /* reset the format */
720 outBuf = outBufSave;
721 outBufLen = outBufLenSave;
722 }
723 }
724 }
725 lval = 0;
597 switch (type) { 726 switch (type) {
598 case EVENT_TYPE_INT: 727 case EVENT_TYPE_INT:
599 /* 32-bit signed int */ 728 /* 32-bit signed int */
600 { 729 {
601 int ival; 730 int32_t ival;
602 731
603 if (eventDataLen < 4) 732 if (eventDataLen < 4)
604 return -1; 733 return -1;
@@ -606,35 +735,24 @@ static int android_log_printBinaryEvent(const unsigned char** pEventData,
606 eventData += 4; 735 eventData += 4;
607 eventDataLen -= 4; 736 eventDataLen -= 4;
608 737
609 outCount = snprintf(outBuf, outBufLen, "%d", ival); 738 lval = ival;
610 if (outCount < outBufLen) {
611 outBuf += outCount;
612 outBufLen -= outCount;
613 } else {
614 /* halt output */
615 goto no_room;
616 }
617 } 739 }
618 break; 740 goto pr_lval;
619 case EVENT_TYPE_LONG: 741 case EVENT_TYPE_LONG:
620 /* 64-bit signed long */ 742 /* 64-bit signed long */
621 { 743 if (eventDataLen < 8)
622 uint64_t lval; 744 return -1;
623 745 lval = get8LE(eventData);
624 if (eventDataLen < 8) 746 eventData += 8;
625 return -1; 747 eventDataLen -= 8;
626 lval = get8LE(eventData); 748 pr_lval:
627 eventData += 8; 749 outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
628 eventDataLen -= 8; 750 if (outCount < outBufLen) {
629 751 outBuf += outCount;
630 outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval); 752 outBufLen -= outCount;
631 if (outCount < outBufLen) { 753 } else {
632 outBuf += outCount; 754 /* halt output */
633 outBufLen -= outCount; 755 goto no_room;
634 } else {
635 /* halt output */
636 goto no_room;
637 }
638 } 756 }
639 break; 757 break;
640 case EVENT_TYPE_FLOAT: 758 case EVENT_TYPE_FLOAT:
@@ -674,6 +792,11 @@ static int android_log_printBinaryEvent(const unsigned char** pEventData,
674 if (eventDataLen < strLen) 792 if (eventDataLen < strLen)
675 return -1; 793 return -1;
676 794
795 if (cp && (strLen == 0)) {
796 /* reset the format if no content */
797 outBuf = outBufSave;
798 outBufLen = outBufLenSave;
799 }
677 if (strLen < outBufLen) { 800 if (strLen < outBufLen) {
678 memcpy(outBuf, eventData, strLen); 801 memcpy(outBuf, eventData, strLen);
679 outBuf += strLen; 802 outBuf += strLen;
@@ -710,7 +833,7 @@ static int android_log_printBinaryEvent(const unsigned char** pEventData,
710 833
711 for (i = 0; i < count; i++) { 834 for (i = 0; i < count; i++) {
712 result = android_log_printBinaryEvent(&eventData, &eventDataLen, 835 result = android_log_printBinaryEvent(&eventData, &eventDataLen,
713 &outBuf, &outBufLen); 836 &outBuf, &outBufLen, fmtStr, fmtLen);
714 if (result != 0) 837 if (result != 0)
715 goto bail; 838 goto bail;
716 839
@@ -736,12 +859,90 @@ static int android_log_printBinaryEvent(const unsigned char** pEventData,
736 fprintf(stderr, "Unknown binary event type %d\n", type); 859 fprintf(stderr, "Unknown binary event type %d\n", type);
737 return -1; 860 return -1;
738 } 861 }
862 if (cp && len) {
863 if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
864 switch (*cp) {
865 case TYPE_OBJECTS:
866 outCount = 0;
867 /* outCount = snprintf(outBuf, outBufLen, " objects"); */
868 break;
869 case TYPE_BYTES:
870 if ((lval != 0) && ((lval % 1024) == 0)) {
871 /* repaint with multiplier */
872 static const char suffixTable[] = { 'K', 'M', 'G', 'T' };
873 size_t idx = 0;
874 outBuf -= outCount;
875 outBufLen += outCount;
876 do {
877 lval /= 1024;
878 if ((lval % 1024) != 0) break;
879 } while (++idx < ((sizeof(suffixTable) /
880 sizeof(suffixTable[0])) - 1));
881 outCount = snprintf(outBuf, outBufLen,
882 "%" PRId64 "%cB",
883 lval, suffixTable[idx]);
884 } else {
885 outCount = snprintf(outBuf, outBufLen, "B");
886 }
887 break;
888 case TYPE_MILLISECONDS:
889 if (((lval <= -1000) || (1000 <= lval)) &&
890 (outBufLen || (outBuf[-1] == '0'))) {
891 /* repaint as (fractional) seconds, possibly saving space */
892 if (outBufLen) outBuf[0] = outBuf[-1];
893 outBuf[-1] = outBuf[-2];
894 outBuf[-2] = outBuf[-3];
895 outBuf[-3] = '.';
896 while ((outBufLen == 0) || (*outBuf == '0')) {
897 --outBuf;
898 ++outBufLen;
899 }
900 if (*outBuf != '.') {
901 ++outBuf;
902 --outBufLen;
903 }
904 outCount = snprintf(outBuf, outBufLen, "s");
905 } else {
906 outCount = snprintf(outBuf, outBufLen, "ms");
907 }
908 break;
909 case TYPE_ALLOCATIONS:
910 outCount = 0;
911 /* outCount = snprintf(outBuf, outBufLen, " allocations"); */
912 break;
913 case TYPE_ID:
914 outCount = 0;
915 break;
916 case TYPE_PERCENT:
917 outCount = snprintf(outBuf, outBufLen, "%%");
918 break;
919 default: /* ? */
920 outCount = 0;
921 break;
922 }
923 ++cp;
924 --len;
925 if (outCount < outBufLen) {
926 outBuf += outCount;
927 outBufLen -= outCount;
928 } else if (outCount) {
929 /* halt output */
930 goto no_room;
931 }
932 }
933 if (!findChar(&cp, &len, ')')) len = 0;
934 if (!findChar(&cp, &len, ',')) len = 0;
935 }
739 936
740bail: 937bail:
741 *pEventData = eventData; 938 *pEventData = eventData;
742 *pEventDataLen = eventDataLen; 939 *pEventDataLen = eventDataLen;
743 *pOutBuf = outBuf; 940 *pOutBuf = outBuf;
744 *pOutBufLen = outBufLen; 941 *pOutBufLen = outBufLen;
942 if (cp) {
943 *fmtStr = cp;
944 *fmtLen = len;
945 }
745 return result; 946 return result;
746 947
747no_room: 948no_room:
@@ -764,7 +965,7 @@ LIBLOG_ABI_PUBLIC int android_log_processBinaryLogBuffer(
764 char *messageBuf, int messageBufLen) 965 char *messageBuf, int messageBufLen)
765{ 966{
766 size_t inCount; 967 size_t inCount;
767 unsigned int tagIndex; 968 uint32_t tagIndex;
768 const unsigned char* eventData; 969 const unsigned char* eventData;
769 970
770 entry->tv_sec = buf->sec; 971 entry->tv_sec = buf->sec;
@@ -817,7 +1018,7 @@ LIBLOG_ABI_PUBLIC int android_log_processBinaryLogBuffer(
817 if (entry->tag == NULL) { 1018 if (entry->tag == NULL) {
818 size_t tagLen; 1019 size_t tagLen;
819 1020
820 tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex); 1021 tagLen = snprintf(messageBuf, messageBufLen, "[%" PRIu32 "]", tagIndex);
821 if (tagLen >= (size_t)messageBufLen) { 1022 if (tagLen >= (size_t)messageBufLen) {
822 tagLen = messageBufLen - 1; 1023 tagLen = messageBufLen - 1;
823 } 1024 }
@@ -831,10 +1032,27 @@ LIBLOG_ABI_PUBLIC int android_log_processBinaryLogBuffer(
831 * Format the event log data into the buffer. 1032 * Format the event log data into the buffer.
832 */ 1033 */
833 char* outBuf = messageBuf; 1034 char* outBuf = messageBuf;
834 size_t outRemaining = messageBufLen-1; /* leave one for nul byte */ 1035 size_t outRemaining = messageBufLen - 1; /* leave one for nul byte */
835 int result; 1036 int result;
1037 const char* fmtStr = NULL;
1038 size_t fmtLen = 0;
1039 if (descriptive_output && map) {
1040 fmtStr = android_lookupEventFormat_len(map, &fmtLen, tagIndex);
1041 }
836 result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf, 1042 result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
837 &outRemaining); 1043 &outRemaining, &fmtStr, &fmtLen);
1044 if ((result == 1) && fmtStr) {
1045 /* We overflowed :-(, let's repaint the line w/o format dressings */
1046 eventData = (const unsigned char*)buf->msg;
1047 if (buf2->hdr_size) {
1048 eventData = ((unsigned char *)buf2) + buf2->hdr_size;
1049 }
1050 eventData += 4;
1051 outBuf = messageBuf;
1052 outRemaining = messageBufLen - 1;
1053 result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
1054 &outRemaining, NULL, NULL);
1055 }
838 if (result < 0) { 1056 if (result < 0) {
839 fprintf(stderr, "Binary log entry conversion failed\n"); 1057 fprintf(stderr, "Binary log entry conversion failed\n");
840 return -1; 1058 return -1;