blob: 988c3070f60f2a4bbb26c4401528c2d3fe4415c9 [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001#include <stdio.h>
2#include <stdlib.h>
3#include <getopt.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7#include <inttypes.h>
8#include <errno.h>
9
Brian Silvermanfe9b7a22014-02-10 15:03:42 -080010#include "aos/linux_code/logging/binary_log_file.h"
Brian Silvermanf665d692013-02-17 22:11:39 -080011#include "aos/common/logging/logging_impl.h"
brians343bc112013-02-10 01:53:46 +000012
13namespace {
14
15const char *kArgsHelp = "[OPTION]... [FILE]\n"
16 "Display log file FILE (created by BinaryLogReader) to stdout.\n"
17 "FILE is \"aos_log-current\" by default.\n"
18 "\n"
19 " -n, --name NAME only display entries from processes named NAME\n"
20 " -l, --level LEVEL "
21 "only display log entries at least as important as LEVEL\n"
22 " // -p, --pid PID only display log entries from process PID\n"
23 " -f, --follow "
24 "wait when the end of the file is reached (implies --end)\n"
25 " -t, --terminate stop when the end of file is reached (default)\n"
26 " -b, --beginning start at the beginning of the file (default)\n"
27 " -e, --end start at the end of the file\n"
28 " -s, --skip NUMBER skip NUMBER matching logs\n"
29 " // -m, --max NUMBER only display up to NUMBER logs\n"
30 " // -o, --format FORMAT use FORMAT to display log entries\n"
Brian Silvermana52ba162013-02-28 15:01:12 -080031 " -h, --help display this help and exit\n"
brians343bc112013-02-10 01:53:46 +000032 "\n"
33 "LEVEL must be DEBUG, INFO, WARNING, ERROR, or FATAL.\n"
34 " It defaults to INFO.\n"
35 "\n"
36 "TODO(brians) implement the commented out ones and changing FILE\n";
37
38void PrintHelpAndExit() {
39 fprintf(stderr, "Usage: %s %s", program_invocation_name, kArgsHelp);
40
41 exit(EXIT_SUCCESS);
42}
43
44} // namespace
45
46int main(int argc, char **argv) {
47 const char *filter_name = NULL;
48 log_level filter_level = INFO;
49 bool follow = false, start_at_beginning = true;
50 const char *filename = "aos_log-current";
51
52 while (true) {
53 static struct option long_options[] = {
54 {"name", required_argument, NULL, 'n'},
55 {"level", required_argument, NULL, 'l'},
56 {"pid", required_argument, NULL, 'p'},
57
58 {"follow", no_argument, NULL, 'f'},
59 {"terminate", no_argument, NULL, 't'},
60 {"beginning", no_argument, NULL, 'b'},
61 {"end", no_argument, NULL, 'e'},
62 {"skip", required_argument, NULL, 's'},
63 {"max", required_argument, NULL, 'm'},
64
65 {"format", required_argument, NULL, 'o'},
66
67 {"help", no_argument, NULL, 'h'},
68 {0, 0, 0, 0}
69 };
70 int option_index = 0;
71
72 const int c = getopt_long(argc, argv, "n:l:p:fts:m:o:h",
73 long_options, &option_index);
74 if (c == -1) { // if we're at the end
75 break;
76 }
77 switch (c) {
78 case 0:
79 fprintf(stderr, "LogDisplayer: got a 0 option but didn't set up any\n");
80 abort();
81 case 'n':
82 filter_name = optarg;
83 break;
84 case 'l':
Brian Silvermanab6615c2013-03-05 20:29:29 -080085 filter_level = ::aos::logging::str_log(optarg);
brians343bc112013-02-10 01:53:46 +000086 if (filter_level == LOG_UNKNOWN) {
87 fprintf(stderr, "LogDisplayer: unknown log level '%s'\n", optarg);
88 exit(EXIT_FAILURE);
89 }
90 break;
91 case 'p':
92 abort();
93 break;
94 case 'f':
95 follow = true;
96 start_at_beginning = false;
97 break;
98 case 't':
99 follow = false;
100 break;
101 case 'b':
102 start_at_beginning = true;
103 break;
104 case 'e':
105 start_at_beginning = false;
106 break;
107 case 'm':
108 abort();
109 break;
110 case 'o':
111 abort();
112 break;
113 case 'h':
114 PrintHelpAndExit();
115 break;
116 case '?':
117 break;
118 default:
Brian Silvermanab6615c2013-03-05 20:29:29 -0800119 fprintf(stderr, "LogDisplayer: in a bad spot (%s: %d)\n",
120 __FILE__, __LINE__);
brians343bc112013-02-10 01:53:46 +0000121 abort();
122 }
123 }
124
125 fprintf(stderr, "displaying down to level %s from file '%s'\n",
Brian Silvermanab6615c2013-03-05 20:29:29 -0800126 ::aos::logging::log_str(filter_level), filename);
brians343bc112013-02-10 01:53:46 +0000127 if (optind < argc) {
128 fprintf(stderr, "non-option ARGV-elements: ");
129 while (optind < argc) {
130 fprintf(stderr, "%s\n", argv[optind++]);
131 }
132 }
133
134 int fd = open(filename, O_RDONLY);
135 if (fd == -1) {
136 fprintf(stderr, "error: couldn't open file '%s' for reading because of %s\n",
137 filename, strerror(errno));
138 exit(EXIT_FAILURE);
139 }
Brian Silvermanab6615c2013-03-05 20:29:29 -0800140 ::aos::logging::LogFileAccessor accessor(fd, false);
brians343bc112013-02-10 01:53:46 +0000141 if (!start_at_beginning) {
142 accessor.MoveToEnd();
143 }
Brian Silvermanab6615c2013-03-05 20:29:29 -0800144 const ::aos::logging::LogFileMessageHeader *msg;
145 ::aos::logging::LogMessage log_message;
brians343bc112013-02-10 01:53:46 +0000146 do {
147 msg = accessor.ReadNextMessage(follow);
148 if (msg == NULL) continue;
Brian Silvermanab6615c2013-03-05 20:29:29 -0800149 if (::aos::logging::log_gt_important(filter_level, msg->level)) continue;
brians343bc112013-02-10 01:53:46 +0000150 if (filter_name != NULL &&
Brian Silvermanab6615c2013-03-05 20:29:29 -0800151 strcmp(filter_name,
152 reinterpret_cast<const char *>(msg) + sizeof(*msg)) != 0) {
brians343bc112013-02-10 01:53:46 +0000153 continue;
154 }
Brian Silvermanf665d692013-02-17 22:11:39 -0800155
156 log_message.source = msg->source;
157 log_message.sequence = msg->sequence;
158 log_message.level = msg->level;
159 log_message.seconds = msg->time_sec;
160 log_message.nseconds = msg->time_nsec;
161 strncpy(log_message.name,
162 reinterpret_cast<const char *>(msg) + sizeof(*msg),
163 sizeof(log_message.name));
164 strncpy(log_message.message,
165 reinterpret_cast<const char *>(msg) + sizeof(*msg) +
166 msg->name_size,
167 sizeof(log_message.message));
Brian Silvermanab6615c2013-03-05 20:29:29 -0800168 ::aos::logging::internal::PrintMessage(stdout, log_message);
brians343bc112013-02-10 01:53:46 +0000169 } while (msg != NULL);
170}