Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * bblog.cpp - BBLogger console tool 00004 * 00005 * Created: Thu Jan 21 01:33:45 2010 00006 * Copyright 2006-2010 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU Library General Public License for more details. 00019 * 00020 * Read the full text in the LICENSE.GPL file in the doc directory. 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 // print out first immediately, the first offset, usually is a waiting 00139 // period until everything was started during logging 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 /// @cond INTERNAL 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 // jump to end of file 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 /// @endcond 00257 00258 void 00259 convert_file_csv(BBLogFile &bf, FILE *outf) 00260 { 00261 fawkes::Interface *iface = bf.interface(); 00262 00263 // print header row 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 // Do the conversion! 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 /** BBLogger tool main. 00320 * @param argc argument count 00321 * @param argv arguments 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 }