Fawkes API Fawkes Development Version
bblog.cpp
1
2/***************************************************************************
3 * bblog.cpp - BBLogger console tool
4 *
5 * Created: Thu Jan 21 01:33:45 2010
6 * Copyright 2006-2010 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * Read the full text in the LICENSE.GPL file in the doc directory.
21 */
22
23#include "../bblogfile.h"
24
25#include <arpa/inet.h>
26#include <blackboard/internal/instance_factory.h>
27#include <blackboard/remote.h>
28#include <interfaces/SwitchInterface.h>
29#include <sys/mman.h>
30#include <sys/stat.h>
31#include <sys/types.h>
32#include <utils/system/argparser.h>
33#include <utils/system/fam.h>
34#include <utils/system/signal.h>
35#include <utils/time/time.h>
36
37#include <cerrno>
38#include <cstdio>
39#include <cstdlib>
40#include <cstring>
41#include <unistd.h>
42
43using namespace fawkes;
44
45void
46print_usage(const char *program_name)
47{
48 printf("Usage: %s [-h] [-r host:port] <COMMAND> <logfile>\n"
49 " %s print <logfile> <index> [index ...]\n"
50 " %s convert <infile> <outfile> <format>\n"
51 "\n"
52 " -h Print this usage information\n"
53 "COMMANDS:\n"
54 " watch Continuously watch a log file (like tail)\n"
55 " info Print meta information of log file\n"
56 " print Print specific data index\n"
57 " <index> [index ...] is a list of indices to print\n"
58 " replay Replay log file in real-time to console\n"
59 " repair Repair file, i.e. properly set number of entries\n"
60 " enable Enable logging on a remotely running bblogger\n"
61 " disable Disable logging on a remotely running bblogger\n"
62 " convert Convert logfile to different format\n"
63 " <infile> input log file\n"
64 " <outfile> converted output file\n"
65 " <format> format to convert to, currently supported:\n"
66 " - csv Comma-separated values\n",
67 program_name,
68 program_name,
69 program_name);
70}
71
72int
73print_info(std::string &filename)
74{
75 try {
76 BBLogFile bf(filename.c_str());
77 bf.print_info();
78 return 0;
79 } catch (Exception &e) {
80 printf("Failed to print info, exception follows\n");
81 e.print_trace();
82 return -1;
83 }
84}
85
86int
87repair_file(std::string &filename)
88{
89 try {
90 BBLogFile::repair_file(filename.c_str());
91 printf("Nothing to repair, files are fine\n");
92 return 0;
93 } catch (Exception &e) {
94 if (strcmp(e.type_id(), "repair-success") == 0) {
95 printf("Repair successful, actions done follow.\n");
96 e.print_trace();
97 return 0;
98 } else {
99 printf("Repair failed, exception follows.\n");
100 e.print_trace();
101 return -1;
102 }
103 }
104}
105
106int
107print_indexes(std::string &filename, std::vector<unsigned int> &indexes)
108{
109 try {
110 BBLogFile bf(filename.c_str());
111 for (unsigned int i = 0; i < indexes.size(); ++i) {
112 bf.read_index(indexes[i]);
113 bf.print_entry();
114 }
115 return 0;
116 } catch (Exception &e) {
117 printf("Failed to print info, exception follows\n");
118 e.print_trace();
119 return -1;
120 }
121
122 return 0;
123}
124
125int
126replay_file(std::string &filename)
127{
128 try {
129 BBLogFile bf(filename.c_str());
130
131 Time last_offset((long)0);
132
133 if (!bf.has_next()) {
134 printf("File does not have any entries, aborting.\n");
135 return -1;
136 }
137
138 // print out first immediately, the first offset, usually is a waiting
139 // period until everything was started during logging
140 bf.read_next();
141 bf.print_entry();
142 last_offset = bf.entry_offset();
143
144 Time diff;
145 while (bf.has_next()) {
146 bf.read_next();
147 diff = bf.entry_offset() - last_offset;
148 diff.wait();
149 last_offset = bf.entry_offset();
150 bf.print_entry();
151 }
152 return 0;
153 } catch (Exception &e) {
154 printf("Failed to print info, exception follows\n");
155 e.print_trace();
156 return -1;
157 }
158
159 return 0;
160}
161/// @cond INTERNAL
162
163class BBLogWatcher : public FamListener, public SignalHandler
164{
165public:
166 BBLogWatcher(const char *filename, BBLogFile &file) : file_(file)
167 {
168 quit_ = false;
169 fam_ = new FileAlterationMonitor();
170 fam_->add_listener(this);
171 fam_->watch_file(filename);
173 }
174
175 ~BBLogWatcher()
176 {
178 fam_->remove_listener(this);
179 delete fam_;
180 }
181
182 virtual void
183 fam_event(const char *filename, unsigned int mask)
184 {
185 if (mask & FAM_DELETE) {
186 quit_ = true;
187 fam_->interrupt();
188 } else {
189 unsigned int remaining = file_.remaining_entries();
190 for (unsigned int i = 0; i < remaining; ++i) {
191 file_.read_next();
192 file_.print_entry();
193 }
194 }
195 }
196
197 virtual void
198 handle_signal(int signal)
199 {
200 quit_ = true;
201 fam_->interrupt();
202 }
203
204 void
205 run()
206 {
207 while (!quit_) {
208 fam_->process_events(-1);
209 }
210 }
211
212private:
213 bool quit_;
215 BBLogFile & file_;
216};
217
218int
219watch_file(std::string &filename)
220{
221 BBLogFile file(filename.c_str(), NULL, false);
222 if (file.remaining_entries() > 0) {
223 // jump to end of file
224 file.read_index(file.remaining_entries() - 1);
225 }
226 BBLogWatcher watcher(filename.c_str(), file);
227 watcher.run();
228
229 return 0;
230}
231
232int
233set_enabled(const char *hostname, unsigned short int port, bool enabled)
234{
235 bool rv = 0;
236
237 BlackBoard * bb = new RemoteBlackBoard(hostname, port);
238 SwitchInterface *si = bb->open_for_reading<SwitchInterface>("BBLogger");
239 if (!si->has_writer()) {
240 printf("No writer exists, BBLogger not loaded?\n");
241 rv = -1;
242 } else {
243 if (enabled) {
245 } else {
247 }
248 }
249
250 bb->close(si);
251 delete bb;
252 return rv;
253}
254
255/// @endcond
256
257void
258convert_file_csv(BBLogFile &bf, FILE *outf)
259{
260 fawkes::Interface *iface = bf.interface();
261
262 // print header row
263 fprintf(outf, "# Time relative to beginning (in sec)");
265 for (i = iface->fields(); i != iface->fields_end(); ++i) {
266 fprintf(outf, ";%s (%s[%zu])", i.get_name(), i.get_typename(), i.get_length());
267 }
268 fprintf(outf, "\n");
269
270 while (bf.has_next()) {
271 bf.read_next();
272 fprintf(outf, "%f", bf.entry_offset().in_sec());
273
275 for (i = iface->fields(); i != iface->fields_end(); ++i) {
276 fprintf(outf, ";%s", i.get_value_string());
277 }
278 fprintf(outf, "\n");
279 }
280}
281
282int
283convert_file(std::string &infile, std::string &outfile, std::string &format)
284{
285 if (format != "csv") {
286 printf("Unsupported output format '%s'\n", format.c_str());
287 return 8;
288 }
289
290 FILE *outf = fopen(outfile.c_str(), "wx");
291 if (!outf) {
292 perror("Failed to open output file");
293 return 3;
294 }
295
296 try {
297 BBLogFile bf(infile.c_str());
298
299 // Do the conversion!
300 if (format == "csv") {
301 convert_file_csv(bf, outf);
302 }
303
304 } catch (Exception &e) {
305 printf("Failed to convert log file: %s\n", e.what());
306 e.print_trace();
307 fclose(outf);
308 return 4;
309 }
310
311 fclose(outf);
312
313 return 0;
314}
315
316/** BBLogger tool main.
317 * @param argc argument count
318 * @param argv arguments
319 */
320int
321main(int argc, char **argv)
322{
323 ArgumentParser argp(argc, argv, "h");
324
325 if (argp.has_arg("h")) {
326 print_usage(argv[0]);
327 exit(0);
328 }
329
330 std::string command, file;
331 if (argp.num_items() < 1) {
332 printf("Invalid number of arguments\n");
333 print_usage(argv[0]);
334 exit(1);
335 } else if (argp.num_items() >= 2) {
336 file = argp.items()[1];
337 }
338
339 command = argp.items()[0];
340
341 if (command == "watch") {
342 return watch_file(file);
343
344 } else if (command == "info") {
345 return print_info(file);
346
347 } else if (command == "print") {
348 std::vector<const char *> index_strings = argp.items();
349 index_strings.erase(index_strings.begin(), index_strings.begin() + 2);
350
351 std::vector<unsigned int> indexes(index_strings.size());
352 for (unsigned int i = 0; i < index_strings.size(); ++i) {
353 long l = atol(index_strings[i]);
354 if (l < 0)
355 throw Exception("Invalid index %li", l);
356
357 indexes[i] = l;
358 }
359
360 if (indexes.size() == 0) {
361 printf("No indexes given.\n\n");
362 print_usage(argv[0]);
363 exit(6);
364 }
365
366 return print_indexes(file, indexes);
367
368 } else if (command == "replay") {
369 return replay_file(file);
370
371 } else if (command == "repair") {
372 return repair_file(file);
373
374 } else if ((command == "enable") || (command == "disable")) {
375 char * host = strdup("localhost");
376 unsigned short int port = 1910;
377 if (argp.has_arg("r")) {
378 argp.parse_hostport("r", &host, &port);
379 }
380 int rv = set_enabled(host, port, (command == "enable"));
381 free(host);
382 return rv;
383
384 } else if (command == "convert") {
385 if (argp.num_items() != 4) {
386 printf("Invalid number of arguments\n");
387 print_usage(argv[0]);
388 exit(7);
389 }
390 std::string outfile = argp.items()[2];
391 std::string format = argp.items()[3];
392 return convert_file(file, outfile, format);
393
394 } else {
395 printf("Invalid command '%s'\n", command.c_str());
396 print_usage(argv[0]);
397 exit(2);
398 }
399
400 return 0;
401}
Class to easily access bblogger log files.
Definition: bblogfile.h:40
bool has_next()
Check if another entry is available.
Definition: bblogfile.cpp:266
void read_next()
Read next entry.
Definition: bblogfile.cpp:283
const fawkes::Time & entry_offset() const
Get current entry offset.
Definition: bblogfile.cpp:514
static void repair_file(const char *filename)
Repair file.
Definition: bblogfile.cpp:323
fawkes::Interface * interface()
Get interface instance.
Definition: bblogfile.cpp:484
void read_index(unsigned int index)
Read entry at particular index.
Definition: bblogfile.cpp:238
unsigned int remaining_entries()
Get number of remaining entries.
Definition: bblogfile.cpp:605
Parse command line arguments.
Definition: argparser.h:64
The BlackBoard abstract class.
Definition: blackboard.h:46
virtual Interface * open_for_reading(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for reading.
virtual void close(Interface *interface)=0
Close interface.
Base class for exceptions in Fawkes.
Definition: exception.h:36
void print_trace() noexcept
Prints trace to stderr.
Definition: exception.cpp:601
virtual const char * what() const noexcept
Get primary string.
Definition: exception.cpp:639
const char * type_id() const
Get type ID.
Definition: exception.cpp:304
File Alteration Monitor Listener.
Definition: fam.h:36
virtual void fam_event(const char *filename, unsigned int mask)=0
Event has been raised.
Monitors files for changes.
Definition: fam.h:71
Interface field iterator.
size_t get_length() const
Get length of current field.
const char * get_name() const
Get name of current field.
const char * get_value_string(const char *array_sep=", ")
Get value of current field as string.
const char * get_typename() const
Get type of current field as string.
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:80
InterfaceFieldIterator fields_end()
Invalid iterator.
Definition: interface.cpp:1240
unsigned int msgq_enqueue(Message *message, bool proxy=false)
Enqueue message at end of queue.
Definition: interface.cpp:915
InterfaceFieldIterator fields()
Get iterator over all fields of this interface instance.
Definition: interface.cpp:1231
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:848
Remote BlackBoard.
Definition: remote.h:50
Interface for signal handling.
Definition: signal.h:36
virtual void handle_signal(int signal)=0
Signal hanlding method.
static void unregister_handler(int signum)
Unregister a SignalHandler for a signal.
Definition: signal.cpp:136
static SignalHandler * register_handler(int signum, SignalHandler *handler)
Register a SignalHandler for a signal.
Definition: signal.cpp:113
DisableSwitchMessage Fawkes BlackBoard Interface Message.
EnableSwitchMessage Fawkes BlackBoard Interface Message.
SwitchInterface Fawkes BlackBoard Interface.
A class for handling time.
Definition: time.h:93
void wait()
Wait (sleep) for this time.
Definition: time.cpp:736
double in_sec() const
Convet time to seconds.
Definition: time.cpp:219
Fawkes library namespace.