2 * Copyright (C) 2007 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
31 #include <arpa/inet.h>
37 #define DEFAULT_LOG_ROTATE_SIZE_KBYTES 16
38 #define DEFAULT_MAX_ROTATED_LOGS 4
40 #define LOG_FILE_DIR "/dev/log_"
42 static log_format* g_logformat;
43 static bool g_nonblock = false;
44 static int g_tail_lines = 0;
46 static const char * g_output_filename = NULL;
47 static int g_log_rotate_size_kbytes = 0; // 0 means "no log rotation"
48 static int g_max_rotated_logs = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded"
49 static int g_outfd = -1;
50 static off_t g_out_byte_count = 0;
51 static int g_dev_count = 0;
53 struct queued_entry_t {
55 unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
56 struct logger_entry entry __attribute__((aligned(4)));
58 struct queued_entry_t* next;
61 static int cmp(struct queued_entry_t* a, struct queued_entry_t* b)
63 int n = a->entry.sec - b->entry.sec;
68 return a->entry.nsec - b->entry.nsec;
76 struct queued_entry_t* queue;
77 struct log_device_t* next;
80 static void enqueue(struct log_device_t* device, struct queued_entry_t* entry)
82 if( device->queue == NULL)
84 device->queue = entry;
88 struct queued_entry_t** e = &device->queue;
89 while(*e && cmp(entry, *e) >= 0 )
98 static int open_logfile (const char *pathname)
100 return open(pathname, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
103 static void rotate_logs()
110 // Can't rotate logs if we're not outputting to a file
111 if (g_output_filename == NULL) {
117 for (i = g_max_rotated_logs ; i > 0 ; i--)
119 snprintf(file1, 255, "%s.%d", g_output_filename, i);
122 snprintf(file0, 255, "%s", g_output_filename);
124 snprintf(file0, 255, "%s.%d", g_output_filename, i - 1);
127 err = rename (file0, file1);
129 if (err < 0 && errno != ENOENT) {
130 perror("while rotating log files");
134 g_outfd = open_logfile (g_output_filename);
137 perror ("couldn't open output file");
141 g_out_byte_count = 0;
146 static void processBuffer(struct log_device_t* dev, struct logger_entry *buf)
148 int bytes_written = 0;
153 err = log_process_log_buffer(buf, &entry);
159 if (log_should_print_line(g_logformat, entry.tag, entry.priority)) {
160 if (false && g_dev_count > 1) {
162 mgs_buf[0] = dev->device[0];
164 bytes_written = write(g_outfd, mgs_buf, 2);
165 if (bytes_written < 0)
167 perror("output error");
172 bytes_written = log_print_log_line(g_logformat, g_outfd, &entry);
174 if (bytes_written < 0)
176 perror("output error");
181 g_out_byte_count += bytes_written;
183 if (g_log_rotate_size_kbytes > 0 && (g_out_byte_count / 1024) >= g_log_rotate_size_kbytes)
189 //fprintf (stderr, "Error processing record\n");
193 static void chooseFirst(struct log_device_t* dev, struct log_device_t** firstdev)
195 for (*firstdev = NULL; dev != NULL; dev = dev->next) {
196 if (dev->queue != NULL && (*firstdev == NULL || cmp(dev->queue, (*firstdev)->queue) < 0))
203 static void maybePrintStart(struct log_device_t* dev) {
206 if (g_dev_count > 1 ) {
208 snprintf(buf, sizeof(buf), "--------- beginning of %s\n", dev->device);
209 if (write(g_outfd, buf, strlen(buf)) < 0) {
210 perror("output error");
217 static void skipNextEntry(struct log_device_t* dev) {
218 maybePrintStart(dev);
219 struct queued_entry_t* entry = dev->queue;
220 dev->queue = entry->next;
224 static void printNextEntry(struct log_device_t* dev)
226 maybePrintStart(dev);
227 processBuffer(dev, &dev->queue->entry);
232 static void read_log_lines(struct log_device_t* devices)
234 struct log_device_t* dev;
237 int queued_lines = 0;
238 bool sleep = false; // for exit immediately when log buffer is empty and g_nonblock value is true.
243 for (dev=devices; dev; dev = dev->next) {
251 struct timeval timeout = { 0, 5000 /* 5ms */ }; // If we oversleep it's ok, i.e. ignore EINTR.
253 for (dev=devices; dev; dev = dev->next) {
254 FD_SET(dev->fd, &readset);
256 result = select(max + 1, &readset, NULL, NULL, sleep ? NULL : &timeout);
257 } while (result == -1 && errno == EINTR);
260 for (dev=devices; dev; dev = dev->next) {
261 if (FD_ISSET(dev->fd, &readset)) {
262 struct queued_entry_t* entry = (struct queued_entry_t *)malloc(sizeof( struct queued_entry_t));
264 fprintf(stderr,"Can't malloc queued_entry\n");
269 /* NOTE: driver guarantees we read exactly one full entry */
270 ret = read(dev->fd, entry->buf, LOGGER_ENTRY_MAX_LEN);
272 if (errno == EINTR) {
276 if (errno == EAGAIN) {
280 perror("dlogutil read");
284 fprintf(stderr, "read: Unexpected EOF!\n");
288 entry->entry.msg[entry->entry.len] = '\0';
296 // we did our short timeout trick and there's nothing new
297 // print everything we have and wait for more data
300 chooseFirst(devices, &dev);
304 if (g_tail_lines == 0 || queued_lines <= g_tail_lines) {
312 // the caller requested to just dump the log and exit
317 // print all that aren't the last in their list
319 while (g_tail_lines == 0 || queued_lines > g_tail_lines) {
320 chooseFirst(devices, &dev);
321 if (dev == NULL || dev->queue->next == NULL) {
324 if (g_tail_lines == 0) {
339 static int clear_log(int logfd)
341 return ioctl(logfd, LOGGER_FLUSH_LOG);
344 /* returns the total size of the log's ring buffer */
345 static int get_log_size(int logfd)
347 return ioctl(logfd, LOGGER_GET_LOG_BUF_SIZE);
350 /* returns the readable size of the log's ring buffer (that is, amount of the log consumed) */
351 static int get_log_readable_size(int logfd)
353 return ioctl(logfd, LOGGER_GET_LOG_LEN);
356 static void setup_output()
359 if (g_output_filename == NULL) {
360 g_outfd = STDOUT_FILENO;
365 g_outfd = open_logfile (g_output_filename);
368 perror ("couldn't open output file");
372 fstat(g_outfd, &statbuf);
374 g_out_byte_count = statbuf.st_size;
378 static int set_log_format(const char * formatString)
380 static log_print_format format;
382 format = log_format_from_string(formatString);
384 if (format == FORMAT_OFF) {
385 // FORMAT_OFF means invalid string
389 log_set_print_format(g_logformat, format);
394 static void show_help(const char *cmd)
396 fprintf(stderr,"Usage: %s [options] [filterspecs]\n", cmd);
398 fprintf(stderr, "options include:\n"
399 " -s Set default filter to silent.\n"
400 " Like specifying filterspec '*:s'\n"
401 " -f <filename> Log to file. Default to stdout\n"
402 " -r [<kbytes>] Rotate log every kbytes. (16 if unspecified). Requires -f\n"
403 " -n <count> Sets max number of rotated logs to <count>, default 4\n"
404 " -v <format> Sets the log print format, where <format> is one of:\n\n"
405 " brief process tag thread raw time threadtime long\n\n"
406 " -c clear (flush) the entire log and exit\n"
407 " -d dump the log and then exit (don't block)\n"
408 " -t <count> print only the most recent <count> lines (implies -d)\n"
409 " -g get the size of the log's ring buffer and exit\n"
410 " -b <buffer> request alternate ring buffer\n"
411 " ('main' (default), 'radio', 'system')");
414 fprintf(stderr,"\nfilterspecs are a series of \n"
415 " <tag>[:priority]\n\n"
416 "where <tag> is a log component tag (or * for all) and priority is:\n"
423 " S Silent (supress all output)\n"
424 "\n'*' means '*:d' and <tag> by itself means <tag>:v\n"
425 "If no filterspec is found, filter defaults to '*:I'\n"
426 "\nIf not specified with -v, format is set defaults to \"brief\"\n\n");
433 int main(int argc, char **argv)
436 int has_set_log_format = 0;
437 int is_clear_log = 0;
441 // const char *forceFilters = NULL;
442 struct log_device_t* devices = NULL;
443 struct log_device_t* dev;
445 g_logformat = (log_format *)log_format_new();
447 if (argc == 2 && 0 == strcmp(argv[1], "--test")) {
448 logprint_run_tests();
452 if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
460 ret = getopt(argc, argv, "cdt:gsf:r:n:v:b:D");
468 // default to all silent
469 log_add_filter_rule(g_logformat, "*:s");
483 g_tail_lines = atoi(optarg);
492 char* buf = (char*) malloc(strlen(LOG_FILE_DIR) + strlen(optarg) + 1);
494 fprintf(stderr,"Can't malloc LOG_FILE_DIR\n");
497 strcpy(buf, LOG_FILE_DIR);
499 // snprintf(buf, strlen(LOG_FILE_DIR) + strlen(optarg) + 1, "%s%s", LOG_FILE_DIR, optarg);
506 dev->next = (struct log_device_t *)malloc( sizeof(struct log_device_t));
507 if (dev->next == NULL) {
508 fprintf(stderr,"Can't malloc log_device\n");
511 dev->next->device = buf;
513 dev->next->printed = false;
514 dev->next->queue = NULL;
515 dev->next->next = NULL;
518 devices = (struct log_device_t *)malloc( sizeof(struct log_device_t));
519 if (devices == NULL) {
520 fprintf(stderr,"Can't malloc log_device\n");
523 devices->device = buf;
525 devices->printed = false;
526 devices->queue = NULL;
527 devices->next = NULL;
534 // redirect output to a file
536 g_output_filename = optarg;
541 // if (optarg == NULL) {
542 // fprintf(stderr,"optarg == null\n");
543 // g_log_rotate_size_kbytes = DEFAULT_LOG_ROTATE_SIZE_KBYTES;
545 //long logRotateSize;
548 if (!isdigit(optarg[0])) {
549 fprintf(stderr,"Invalid parameter to -r\n");
553 g_log_rotate_size_kbytes = atoi(optarg);
558 if (!isdigit(optarg[0])) {
559 fprintf(stderr,"Invalid parameter to -r\n");
564 g_max_rotated_logs = atoi(optarg);
568 err = set_log_format (optarg);
570 fprintf(stderr,"Invalid parameter to -v\n");
575 has_set_log_format = 1;
579 fprintf(stderr,"Unrecognized Option\n");
587 devices = (struct log_device_t *)malloc( sizeof(struct log_device_t));
588 if (devices == NULL) {
589 fprintf(stderr,"Can't malloc log_device\n");
592 devices->device = strdup("/dev/"LOGGER_LOG_MAIN);
594 devices->printed = false;
595 devices->queue = NULL;
596 devices->next = NULL;
601 (mode & O_RDONLY) ? R_OK : 0
602 | (mode & O_WRONLY) ? W_OK : 0;
604 // only add this if it's available
605 if (0 == access("/dev/"LOGGER_LOG_SYSTEM, accessmode)) {
606 devices->next = (struct log_device_t *)malloc( sizeof(struct log_device_t));
607 if (devices->next == NULL) {
608 fprintf(stderr,"Can't malloc log_device\n");
611 devices->next->device = strdup("/dev/"LOGGER_LOG_SYSTEM);
612 devices->next->fd = -1;
613 devices->next->printed = false;
614 devices->next->queue = NULL;
615 devices->next->next = NULL;
618 if (0 == access("/dev/"LOGGER_LOG_APPS, accessmode)) {
619 devices->next = (struct log_device_t *)malloc( sizeof(struct log_device_t));
620 if (devices->next == NULL) {
621 fprintf(stderr,"Can't malloc log_device\n");
624 devices->next->device = strdup("/dev/"LOGGER_LOG_APPS);
625 devices->next->fd = -1;
626 devices->next->printed = false;
627 devices->next->queue = NULL;
628 devices->next->next = NULL;
632 // only add this if it's available
634 if ((fd = open("/dev/"LOGGER_LOG_SYSTEM, mode)) != -1) {
635 devices->next = (struct log_device_t *)malloc( sizeof(struct log_device_t));
636 devices->next->device = strdup("/dev/"LOGGER_LOG_SYSTEM);
637 devices->next->fd = -1;
638 devices->next->printed = false;
639 devices->next->queue = NULL;
640 devices->next->next = NULL;
648 if (g_log_rotate_size_kbytes != 0 && g_output_filename == NULL)
650 fprintf(stderr,"-r requires -f as well\n");
658 if (has_set_log_format == 0) {
659 err = set_log_format("brief");
662 const char* logFormat = getenv("DLOG_PRINTF_LOG");
664 if (logFormat != NULL) {
665 err = set_log_format("brief");
668 fprintf(stderr, "invalid format in DLOG_PRINTF_LOG '%s'\n", logFormat);
673 err = log_add_filter_string(g_logformat, forceFilters);
675 fprintf (stderr, "Invalid filter expression in -logcat option\n");
678 } else if (argc == optind) {
679 // Add from environment variable
680 char *env_tags_orig = getenv("DLOG_LOG_TAGS");
682 if (env_tags_orig != NULL) {
683 err = log_add_filter_string(g_logformat, env_tags_orig);
686 fprintf(stderr, "Invalid filter expression in DLOG_LOG_TAGS\n");
692 // Add from commandline
694 fprintf(stderr,"arc = %d, optind = %d ,Kb %d, rotate %d\n", argc, optind,g_log_rotate_size_kbytes,g_max_rotated_logs);
698 // Add from environment variable
699 //char *env_tags_orig = getenv("DLOG_TAGS");
700 log_add_filter_string(g_logformat, "*:d");
705 for (i = optind ; i < argc ; i++) {
706 err = log_add_filter_string(g_logformat, argv[i]);
709 fprintf (stderr, "Invalid filter expression '%s'\n", argv[i]);
720 dev->fd = open(dev->device, mode);
722 fprintf(stderr, "Unable to open log device '%s': %s\n",
723 dev->device, strerror(errno));
729 ret = clear_log(dev->fd);
739 size = get_log_size(dev->fd);
745 readable = get_log_readable_size(dev->fd);
751 printf("%s: ring buffer is %dKb (%dKb consumed), "
752 "max entry is %db, max payload is %db\n", dev->device,
753 size / 1024, readable / 1024,
754 (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
768 read_log_lines(devices);