// Copyright 2006-2014 The Android Open Source Project #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_LOG_ROTATE_SIZE_KBYTES 16 #define DEFAULT_MAX_ROTATED_LOGS 4 static AndroidLogFormat * g_logformat; /* logd prefixes records with a length field */ #define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t) struct log_device_t { const char* device; bool binary; struct logger *logger; struct logger_list *logger_list; bool printed; char label; log_device_t* next; log_device_t(const char* d, bool b, char l) { device = d; binary = b; label = l; next = NULL; printed = false; } }; namespace android { /* Global Variables */ static const char * g_outputFileName = NULL; static int g_logRotateSizeKBytes = 0; // 0 means "no log rotation" static int g_maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded" static int g_outFD = -1; static off_t g_outByteCount = 0; static int g_printBinary = 0; static int g_devCount = 0; static EventTagMap* g_eventTagMap = NULL; static int openLogFile (const char *pathname) { return open(pathname, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); } static void rotateLogs() { int err; // Can't rotate logs if we're not outputting to a file if (g_outputFileName == NULL) { return; } close(g_outFD); // Compute the maximum number of digits needed to count up to g_maxRotatedLogs in decimal. // eg: g_maxRotatedLogs == 30 -> log10(30) == 1.477 -> maxRotationCountDigits == 2 int maxRotationCountDigits = (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0; for (int i = g_maxRotatedLogs ; i > 0 ; i--) { char *file0, *file1; asprintf(&file1, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i); if (i - 1 == 0) { asprintf(&file0, "%s", g_outputFileName); } else { asprintf(&file0, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i - 1); } err = rename (file0, file1); if (err < 0 && errno != ENOENT) { perror("while rotating log files"); } free(file1); free(file0); } g_outFD = openLogFile (g_outputFileName); if (g_outFD < 0) { perror ("couldn't open output file"); exit(-1); } g_outByteCount = 0; } void printBinary(struct log_msg *buf) { size_t size = buf->len(); TEMP_FAILURE_RETRY(write(g_outFD, buf, size)); } static void processBuffer(log_device_t* dev, struct log_msg *buf) { int bytesWritten = 0; int err; AndroidLogEntry entry; char binaryMsgBuf[1024]; if (dev->binary) { err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry, g_eventTagMap, binaryMsgBuf, sizeof(binaryMsgBuf)); //printf(">>> pri=%d len=%d msg='%s'\n", // entry.priority, entry.messageLen, entry.message); } else { err = android_log_processLogBuffer(&buf->entry_v1, &entry); } if (err < 0) { goto error; } if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority)) { if (false && g_devCount > 1) { binaryMsgBuf[0] = dev->label; binaryMsgBuf[1] = ' '; bytesWritten = write(g_outFD, binaryMsgBuf, 2); if (bytesWritten < 0) { perror("output error"); exit(-1); } } bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry); if (bytesWritten < 0) { perror("output error"); exit(-1); } } g_outByteCount += bytesWritten; if (g_logRotateSizeKBytes > 0 && (g_outByteCount / 1024) >= g_logRotateSizeKBytes ) { rotateLogs(); } error: //fprintf (stderr, "Error processing record\n"); return; } static void maybePrintStart(log_device_t* dev) { if (!dev->printed) { dev->printed = true; if (g_devCount > 1 && !g_printBinary) { char buf[1024]; snprintf(buf, sizeof(buf), "--------- beginning of %s\n", dev->device); if (write(g_outFD, buf, strlen(buf)) < 0) { perror("output error"); exit(-1); } } } } static void setupOutput() { if (g_outputFileName == NULL) { g_outFD = STDOUT_FILENO; } else { struct stat statbuf; g_outFD = openLogFile (g_outputFileName); if (g_outFD < 0) { perror ("couldn't open output file"); exit(-1); } fstat(g_outFD, &statbuf); g_outByteCount = statbuf.st_size; } } static void show_help(const char *cmd) { fprintf(stderr,"Usage: %s [options] [filterspecs]\n", cmd); fprintf(stderr, "options include:\n" " -s Set default filter to silent.\n" " Like specifying filterspec '*:s'\n" " -f Log to file. Default to stdout\n" " -r [] Rotate log every kbytes. (16 if unspecified). Requires -f\n" " -n Sets max number of rotated logs to , default 4\n" " -v Sets the log print format, where is:\n\n" " brief color long process raw tag thread threadtime time\n\n" " -c clear (flush) the entire log and exit\n" " -d dump the log and then exit (don't block)\n" " -t print only the most recent lines (implies -d)\n" " -t '