blob: 7b56f3538b25f6315fe142f3c0d1d114efd54b3c [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 Silverman88471dc2014-02-15 22:35:42 -080010#include <algorithm>
11
Brian Silvermanfe9b7a22014-02-10 15:03:42 -080012#include "aos/linux_code/logging/binary_log_file.h"
Brian Silvermanf665d692013-02-17 22:11:39 -080013#include "aos/common/logging/logging_impl.h"
Brian Silverman88471dc2014-02-15 22:35:42 -080014#include "aos/common/queue_types.h"
15
16using ::aos::logging::linux_code::LogFileMessageHeader;
brians343bc112013-02-10 01:53:46 +000017
18namespace {
19
20const char *kArgsHelp = "[OPTION]... [FILE]\n"
21 "Display log file FILE (created by BinaryLogReader) to stdout.\n"
22 "FILE is \"aos_log-current\" by default.\n"
23 "\n"
24 " -n, --name NAME only display entries from processes named NAME\n"
25 " -l, --level LEVEL "
26 "only display log entries at least as important as LEVEL\n"
27 " // -p, --pid PID only display log entries from process PID\n"
28 " -f, --follow "
29 "wait when the end of the file is reached (implies --end)\n"
30 " -t, --terminate stop when the end of file is reached (default)\n"
31 " -b, --beginning start at the beginning of the file (default)\n"
32 " -e, --end start at the end of the file\n"
33 " -s, --skip NUMBER skip NUMBER matching logs\n"
34 " // -m, --max NUMBER only display up to NUMBER logs\n"
35 " // -o, --format FORMAT use FORMAT to display log entries\n"
Brian Silvermana52ba162013-02-28 15:01:12 -080036 " -h, --help display this help and exit\n"
brians343bc112013-02-10 01:53:46 +000037 "\n"
38 "LEVEL must be DEBUG, INFO, WARNING, ERROR, or FATAL.\n"
39 " It defaults to INFO.\n"
40 "\n"
41 "TODO(brians) implement the commented out ones and changing FILE\n";
42
43void PrintHelpAndExit() {
44 fprintf(stderr, "Usage: %s %s", program_invocation_name, kArgsHelp);
45
46 exit(EXIT_SUCCESS);
47}
48
49} // namespace
50
51int main(int argc, char **argv) {
52 const char *filter_name = NULL;
Brian Silverman88471dc2014-02-15 22:35:42 -080053 size_t filter_length;
brians343bc112013-02-10 01:53:46 +000054 log_level filter_level = INFO;
55 bool follow = false, start_at_beginning = true;
56 const char *filename = "aos_log-current";
57
58 while (true) {
59 static struct option long_options[] = {
60 {"name", required_argument, NULL, 'n'},
61 {"level", required_argument, NULL, 'l'},
62 {"pid", required_argument, NULL, 'p'},
63
64 {"follow", no_argument, NULL, 'f'},
65 {"terminate", no_argument, NULL, 't'},
66 {"beginning", no_argument, NULL, 'b'},
67 {"end", no_argument, NULL, 'e'},
68 {"skip", required_argument, NULL, 's'},
69 {"max", required_argument, NULL, 'm'},
70
71 {"format", required_argument, NULL, 'o'},
72
73 {"help", no_argument, NULL, 'h'},
74 {0, 0, 0, 0}
75 };
76 int option_index = 0;
77
78 const int c = getopt_long(argc, argv, "n:l:p:fts:m:o:h",
79 long_options, &option_index);
80 if (c == -1) { // if we're at the end
81 break;
82 }
83 switch (c) {
84 case 0:
85 fprintf(stderr, "LogDisplayer: got a 0 option but didn't set up any\n");
86 abort();
87 case 'n':
88 filter_name = optarg;
Brian Silverman88471dc2014-02-15 22:35:42 -080089 filter_length = strlen(filter_name);
brians343bc112013-02-10 01:53:46 +000090 break;
91 case 'l':
Brian Silvermanab6615c2013-03-05 20:29:29 -080092 filter_level = ::aos::logging::str_log(optarg);
brians343bc112013-02-10 01:53:46 +000093 if (filter_level == LOG_UNKNOWN) {
94 fprintf(stderr, "LogDisplayer: unknown log level '%s'\n", optarg);
95 exit(EXIT_FAILURE);
96 }
97 break;
98 case 'p':
99 abort();
100 break;
101 case 'f':
102 follow = true;
103 start_at_beginning = false;
104 break;
105 case 't':
106 follow = false;
107 break;
108 case 'b':
109 start_at_beginning = true;
110 break;
111 case 'e':
112 start_at_beginning = false;
113 break;
114 case 'm':
115 abort();
116 break;
117 case 'o':
118 abort();
119 break;
120 case 'h':
121 PrintHelpAndExit();
122 break;
123 case '?':
124 break;
125 default:
Brian Silvermanab6615c2013-03-05 20:29:29 -0800126 fprintf(stderr, "LogDisplayer: in a bad spot (%s: %d)\n",
127 __FILE__, __LINE__);
brians343bc112013-02-10 01:53:46 +0000128 abort();
129 }
130 }
131
132 fprintf(stderr, "displaying down to level %s from file '%s'\n",
Brian Silvermanab6615c2013-03-05 20:29:29 -0800133 ::aos::logging::log_str(filter_level), filename);
brians343bc112013-02-10 01:53:46 +0000134 if (optind < argc) {
135 fprintf(stderr, "non-option ARGV-elements: ");
136 while (optind < argc) {
137 fprintf(stderr, "%s\n", argv[optind++]);
138 }
139 }
140
141 int fd = open(filename, O_RDONLY);
142 if (fd == -1) {
143 fprintf(stderr, "error: couldn't open file '%s' for reading because of %s\n",
144 filename, strerror(errno));
145 exit(EXIT_FAILURE);
146 }
Brian Silverman003ba4b2014-02-10 16:56:18 -0800147 ::aos::logging::linux_code::LogFileAccessor accessor(fd, false);
brians343bc112013-02-10 01:53:46 +0000148 if (!start_at_beginning) {
149 accessor.MoveToEnd();
150 }
Brian Silverman88471dc2014-02-15 22:35:42 -0800151
152 const LogFileMessageHeader *msg;
Brian Silvermanab6615c2013-03-05 20:29:29 -0800153 ::aos::logging::LogMessage log_message;
brians343bc112013-02-10 01:53:46 +0000154 do {
155 msg = accessor.ReadNextMessage(follow);
Brian Silverman003ba4b2014-02-10 16:56:18 -0800156 if (msg == NULL) {
157 fputs("reached end of file\n", stderr);
158 return 0;
159 }
Brian Silverman88471dc2014-02-15 22:35:42 -0800160
161 if (msg->type == LogFileMessageHeader::MessageType::kStructType) {
162 size_t bytes = msg->message_size;
163 ::aos::MessageType *type = ::aos::MessageType::Deserialize(
164 reinterpret_cast<const char *>(msg + 1), &bytes);
165 ::aos::type_cache::Add(*type);
brians343bc112013-02-10 01:53:46 +0000166 continue;
167 }
Brian Silvermanf665d692013-02-17 22:11:39 -0800168
Brian Silverman88471dc2014-02-15 22:35:42 -0800169 if (::aos::logging::log_gt_important(filter_level, msg->level)) continue;
170 if (filter_name != NULL) {
171 if (filter_length != msg->name_size) continue;
172 if (memcmp(filter_name,
173 reinterpret_cast<const char *>(msg) + sizeof(*msg),
174 filter_length) !=
175 0) {
176 continue;
177 }
178 }
179
Brian Silvermanf665d692013-02-17 22:11:39 -0800180 log_message.source = msg->source;
181 log_message.sequence = msg->sequence;
182 log_message.level = msg->level;
183 log_message.seconds = msg->time_sec;
184 log_message.nseconds = msg->time_nsec;
Brian Silverman88471dc2014-02-15 22:35:42 -0800185 memcpy(log_message.name, reinterpret_cast<const char *>(msg) + sizeof(*msg),
186 ::std::min<size_t>(sizeof(log_message.name), msg->name_size));
187 log_message.message_length = msg->message_size;
188 log_message.name_length = msg->name_size;
189
190 switch (msg->type) {
191 case LogFileMessageHeader::MessageType::kStruct: {
192 const char *position =
193 reinterpret_cast<const char *>(msg + 1) + msg->name_size;
194 memcpy(&log_message.structure.type_id, position,
195 sizeof(log_message.structure.type_id));
196 position += sizeof(log_message.structure.type_id);
197
198 uint32_t length;
199 memcpy(&length, position, sizeof(length));
200 log_message.structure.string_length = length;
201 position += sizeof(length);
202 memcpy(log_message.structure.serialized, position, length);
203 position += length;
204
205 log_message.message_length -=
206 sizeof(log_message.structure.type_id) + sizeof(uint32_t) +
207 log_message.structure.string_length;
208 memcpy(log_message.structure.serialized +
209 log_message.structure.string_length,
210 position, log_message.message_length);
211
212 log_message.type = ::aos::logging::LogMessage::Type::kStruct;
213 break;
214 }
215 case LogFileMessageHeader::MessageType::kString:
216 memcpy(
217 log_message.message,
218 reinterpret_cast<const char *>(msg) + sizeof(*msg) + msg->name_size,
219 ::std::min<size_t>(sizeof(log_message.message), msg->message_size));
220 log_message.type = ::aos::logging::LogMessage::Type::kString;
221 break;
222 case LogFileMessageHeader::MessageType::kStructType:
223 LOG(FATAL, "shouldn't get here\n");
224 break;
225 };
Brian Silvermanab6615c2013-03-05 20:29:29 -0800226 ::aos::logging::internal::PrintMessage(stdout, log_message);
brians343bc112013-02-10 01:53:46 +0000227 } while (msg != NULL);
228}