00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "../bblogfile.h"
00024
00025 #include <utils/system/argparser.h>
00026 #include <utils/system/signal.h>
00027 #include <utils/time/time.h>
00028 #include <utils/system/fam.h>
00029
00030 #include <blackboard/remote.h>
00031 #include <blackboard/internal/instance_factory.h>
00032 #include <interfaces/SwitchInterface.h>
00033
00034 #include <cstdlib>
00035 #include <cstdio>
00036 #include <cerrno>
00037 #include <cstring>
00038 #include <arpa/inet.h>
00039 #include <sys/types.h>
00040 #include <sys/stat.h>
00041 #include <unistd.h>
00042 #include <sys/mman.h>
00043
00044 using namespace fawkes;
00045
00046 void
00047 print_usage(const char *program_name)
00048 {
00049 printf("Usage: %s [-h] [-r host:port] <COMMAND> <logfile>\n"
00050 " %s print <logfile> <index> [index ...]\n"
00051 " %s convert <infile> <outfile> <format>\n"
00052 "\n"
00053 " -h Print this usage information\n"
00054 "COMMANDS:\n"
00055 " watch Continuously watch a log file (like tail)\n"
00056 " info Print meta information of log file\n"
00057 " print Print specific data index\n"
00058 " <index> [index ...] is a list of indices to print\n"
00059 " replay Replay log file in real-time to console\n"
00060 " repair Repair file, i.e. properly set number of entries\n"
00061 " enable Enable logging on a remotely running bblogger\n"
00062 " disable Disable logging on a remotely running bblogger\n"
00063 " convert Convert logfile to different format\n"
00064 " <infile> input log file\n"
00065 " <outfile> converted output file\n"
00066 " <format> format to convert to, currently supported:\n"
00067 " - csv Comma-separated values\n",
00068 program_name, program_name, program_name);
00069 }
00070
00071
00072 int
00073 print_info(std::string &filename)
00074 {
00075 try {
00076 BBLogFile bf(filename.c_str());
00077 bf.print_info();
00078 return 0;
00079 } catch (Exception &e) {
00080 printf("Failed to print info, exception follows\n");
00081 e.print_trace();
00082 return -1;
00083 }
00084 }
00085
00086 int
00087 repair_file(std::string &filename)
00088 {
00089 try {
00090 BBLogFile::repair_file(filename.c_str());
00091 printf("Nothing to repair, files are fine\n");
00092 return 0;
00093 } catch (Exception &e) {
00094 if (strcmp(e.type_id(), "repair-success") == 0) {
00095 printf("Repair successful, actions done follow.\n");
00096 e.print_trace();
00097 return 0;
00098 } else {
00099 printf("Repair failed, exception follows.\n");
00100 e.print_trace();
00101 return -1;
00102 }
00103 }
00104 }
00105
00106 int
00107 print_indexes(std::string &filename, std::vector<unsigned int> &indexes)
00108 {
00109 try {
00110 BBLogFile bf(filename.c_str());
00111 for (unsigned int i = 0; i < indexes.size(); ++i) {
00112 bf.read_index(indexes[i]);
00113 bf.print_entry();
00114 }
00115 return 0;
00116 } catch (Exception &e) {
00117 printf("Failed to print info, exception follows\n");
00118 e.print_trace();
00119 return -1;
00120 }
00121
00122 return 0;
00123 }
00124
00125 int
00126 replay_file(std::string &filename)
00127 {
00128 try {
00129 BBLogFile bf(filename.c_str());
00130
00131 Time last_offset((long)0);
00132
00133 if (! bf.has_next()) {
00134 printf("File does not have any entries, aborting.\n");
00135 return -1;
00136 }
00137
00138
00139
00140 bf.read_next();
00141 bf.print_entry();
00142 last_offset = bf.entry_offset();
00143
00144 Time diff;
00145 while (bf.has_next()) {
00146 bf.read_next();
00147 diff = bf.entry_offset() - last_offset;
00148 diff.wait();
00149 last_offset = bf.entry_offset();
00150 bf.print_entry();
00151 }
00152 return 0;
00153 } catch (Exception &e) {
00154 printf("Failed to print info, exception follows\n");
00155 e.print_trace();
00156 return -1;
00157 }
00158
00159 return 0;
00160 }
00161
00162
00163 class BBLogWatcher
00164 : public FamListener,
00165 public SignalHandler
00166 {
00167 public:
00168 BBLogWatcher(const char *filename, BBLogFile &file)
00169 : __file(file)
00170 {
00171 __quit = false;
00172 __fam = new FileAlterationMonitor();
00173 __fam->add_listener(this);
00174 __fam->watch_file(filename);
00175 SignalManager::register_handler(SIGINT, this);
00176 }
00177
00178 ~BBLogWatcher() {
00179 SignalManager::unregister_handler(this);
00180 __fam->remove_listener(this);
00181 delete __fam;
00182 }
00183
00184 virtual void fam_event(const char *filename, unsigned int mask)
00185 {
00186 if (mask & FAM_DELETE) {
00187 __quit = true;
00188 __fam->interrupt();
00189 } else {
00190 unsigned int remaining = __file.remaining_entries();
00191 for (unsigned int i = 0; i < remaining; ++i) {
00192 __file.read_next();
00193 __file.print_entry();
00194 }
00195 }
00196 }
00197
00198 virtual void handle_signal(int signal)
00199 {
00200 __quit = true;
00201 __fam->interrupt();
00202 }
00203
00204 void run()
00205 {
00206 while (! __quit) {
00207 __fam->process_events(-1);
00208 }
00209 }
00210
00211
00212 private:
00213 bool __quit;
00214 FileAlterationMonitor *__fam;
00215 BBLogFile &__file;
00216 };
00217
00218 int
00219 watch_file(std::string &filename)
00220 {
00221 BBLogFile file(filename.c_str(), NULL, false);
00222 if (file.remaining_entries() > 0) {
00223
00224 file.read_index(file.remaining_entries() - 1);
00225 }
00226 BBLogWatcher watcher(filename.c_str(), file);
00227 watcher.run();
00228
00229 return 0;
00230 }
00231
00232
00233 int
00234 set_enabled(const char *hostname, unsigned short int port, bool enabled)
00235 {
00236 bool rv = 0;
00237
00238 BlackBoard *bb = new RemoteBlackBoard(hostname, port);
00239 SwitchInterface *si = bb->open_for_reading<SwitchInterface>("BBLogger");
00240 if ( ! si->has_writer() ) {
00241 printf("No writer exists, BBLogger not loaded?\n");
00242 rv = -1;
00243 } else {
00244 if (enabled) {
00245 si->msgq_enqueue(new SwitchInterface::EnableSwitchMessage());
00246 } else {
00247 si->msgq_enqueue(new SwitchInterface::DisableSwitchMessage());
00248 }
00249 }
00250
00251 bb->close(si);
00252 delete bb;
00253 return rv;
00254 }
00255
00256
00257
00258 void
00259 convert_file_csv(BBLogFile &bf, FILE *outf)
00260 {
00261 fawkes::Interface *iface = bf.interface();
00262
00263
00264 fprintf(outf, "# Time relative to beginning (in sec)");
00265 InterfaceFieldIterator i;
00266 for (i = iface->fields(); i != iface->fields_end(); ++i) {
00267 fprintf(outf, ";%s (%s[%zu])",
00268 i.get_name(), i.get_typename(), i.get_length());
00269 }
00270 fprintf(outf, "\n");
00271
00272 while (bf.has_next()) {
00273 bf.read_next();
00274 fprintf(outf, "%f", bf.entry_offset().in_sec());
00275
00276 InterfaceFieldIterator i;
00277 for (i = iface->fields(); i != iface->fields_end(); ++i) {
00278 fprintf(outf, ";%s", i.get_value_string());
00279 }
00280 fprintf(outf, "\n");
00281 }
00282 }
00283
00284
00285 int
00286 convert_file(std::string &infile, std::string &outfile, std::string &format)
00287 {
00288 if (format != "csv") {
00289 printf("Unsupported output format '%s'\n", format.c_str());
00290 return 8;
00291 }
00292
00293 FILE *outf = fopen(outfile.c_str(), "wx");
00294 if (!outf) {
00295 perror("Failed to open output file");
00296 return 3;
00297 }
00298
00299 try {
00300 BBLogFile bf(infile.c_str());
00301
00302
00303 if (format == "csv") {
00304 convert_file_csv(bf, outf);
00305 }
00306
00307 } catch (Exception &e) {
00308 printf("Failed to convert log file: %s\n", e.what());
00309 e.print_trace();
00310 fclose(outf);
00311 return 4;
00312 }
00313
00314 fclose(outf);
00315
00316 return 0;
00317 }
00318
00319
00320
00321
00322
00323 int
00324 main(int argc, char **argv)
00325 {
00326 ArgumentParser argp(argc, argv, "h");
00327
00328 if ( argp.has_arg("h") ) {
00329 print_usage(argv[0]);
00330 exit(0);
00331 }
00332
00333 std::string command, file;
00334 if (argp.num_items() < 1) {
00335 printf("Invalid number of arguments\n");
00336 print_usage(argv[0]);
00337 exit(1);
00338 } else if (argp.num_items() >= 2) {
00339 file = argp.items()[1];
00340 }
00341
00342 command = argp.items()[0];
00343
00344 if (command == "watch") {
00345 return watch_file(file);
00346
00347 } else if (command == "info") {
00348 return print_info(file);
00349
00350 } else if (command == "print") {
00351 std::vector<const char *> index_strings = argp.items();
00352 index_strings.erase(index_strings.begin(), index_strings.begin() + 2);
00353
00354 std::vector<unsigned int> indexes(index_strings.size());
00355 for (unsigned int i = 0; i < index_strings.size(); ++i) {
00356 long l = atol(index_strings[i]);
00357 if (l < 0) throw Exception("Invalid index %li", l);
00358
00359 indexes[i] = l;
00360 }
00361
00362 if (indexes.size() == 0) {
00363 printf("No indexes given.\n\n");
00364 print_usage(argv[0]);
00365 exit(6);
00366 }
00367
00368 return print_indexes(file, indexes);
00369
00370 } else if (command == "replay") {
00371 return replay_file(file);
00372
00373 } else if (command == "repair") {
00374 return repair_file(file);
00375
00376 } else if ( (command == "enable") || (command == "disable")) {
00377 char *host = strdup("localhost");
00378 unsigned short int port = 1910;
00379 if (argp.has_arg("r")) {
00380 argp.parse_hostport("r", &host, &port);
00381 }
00382 int rv = set_enabled(host, port, (command == "enable"));
00383 free(host);
00384 return rv;
00385
00386 } else if (command == "convert") {
00387 if (argp.num_items() != 4) {
00388 printf("Invalid number of arguments\n");
00389 print_usage(argv[0]);
00390 exit(7);
00391 }
00392 std::string outfile = argp.items()[2];
00393 std::string format = argp.items()[3];
00394 return convert_file(file, outfile, format);
00395
00396 } else {
00397 printf("Invalid command '%s'\n", command.c_str());
00398 print_usage(argv[0]);
00399 exit(2);
00400 }
00401
00402 return 0;
00403 }