1 /*
2 Copyright (C) 2013 Andrew Caudwell (acaudwell@gmail.com)
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version
7 3 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "settings.h"
19
20 #include "core/logger.h"
21 #include "core/sdlapp.h"
22 #include "core/seeklog.h"
23 #include "logentry.h"
24
25 #include <time.h>
26 #include <algorithm>
27 #include <boost/algorithm/string.hpp>
28
29 LogstalgiaSettings settings;
30
31 //display help message
help(bool extended_help)32 void LogstalgiaSettings::help(bool extended_help) {
33
34 #ifdef _WIN32
35 //resize window to fit help message
36 SDLApp::resizeConsole(920);
37 SDLApp::showConsole(true);
38 #endif
39
40 printf("Logstalgia v%s\n", LOGSTALGIA_VERSION);
41
42 printf("Usage: logstalgia [options] logfile\n\n");
43 printf("Options:\n");
44 printf(" -WIDTHxHEIGHT Set window size\n");
45 printf(" -f, --fullscreen Fullscreen\n");
46 printf(" --screen SCREEN Screen number\n");
47 printf(" --window-position XxY Initial window position\n");
48 printf(" --frameless Frameless window\n");
49 printf(" --title TITLE Set a title\n\n");
50
51 printf(" -b --background FFFFFF Background colour in hex\n\n");
52
53 printf(" -x --full-hostnames Show full request ip/hostname\n");
54 printf(" -s --simulation-speed Simulation speed (default: 1)\n");
55 printf(" -p --pitch-speed Speed balls travel across screen (default: 0.15)\n");
56 printf(" -u --update-rate Page summary update rate (default: 5)\n\n");
57
58 printf(" -g name,(HOST|URI|CODE)=regex[,SEP=chars][,MAX=n][,ABBR=n],percent[,colour]\n");
59 printf(" Group together requests where the HOST, URI\n");
60 printf(" or response CODE matches a regular expression\n\n");
61
62 printf(" --address-separators CHARS List of address separator characters\n");
63 printf(" --address-max-depth DEPTH Maximum depth to display in address summarizer\n");
64 printf(" --address-abbr-depth DEPTH Minimum abbreviation depth of address summarizer\n\n");
65
66 printf(" --path-separators CHARS Default list of path separator characters\n");
67 printf(" --path-max-depth DEPTH Default maximum path depth\n");
68 printf(" --path-abbr-depth DEPTH Default minimum path abbreviation depth\n\n");
69
70 printf(" --paddle-mode MODE Paddle mode (single, pid, vhost)\n");
71 printf(" --paddle-position POSITION Paddle position as a fraction of the view width\n\n");
72
73 printf(" --display-fields FIELDS Comma separated list of fields shown on hover:\n");
74 printf(" timestamp,hostname,path,method,protocol\n");
75 printf(" response_size,response_code,referrer\n");
76 printf(" user_agent,vhost,pid,log_entry\n\n");
77
78 printf(" --sync Read from STDIN, ignoring entries before now\n\n");
79
80 printf(" --from, --to 'YYYY-MM-DD hh:mm:ss' Show entries from a specific time period\n\n");
81
82 printf(" --start-position POSITION Begin at some position in the log (0.0 - 1.0)\n");
83 printf(" --stop-position POSITION Stop at some position\n\n");
84
85 printf(" --no-bounce No bouncing\n\n");
86
87 printf(" --hide-response-code Hide response code\n");
88 printf(" --hide-paddle Hide paddle\n");
89 printf(" --hide-paddle-tokens Hide paddle tokens shown in multi-paddle modes\n");
90 printf(" --hide-url-prefix Hide URL protocol and hostname prefix\n\n");
91
92 printf(" --disable-auto-skip Disable skipping of empty time periods\n");
93 printf(" --disable-progress Disable the progress bar\n");
94 printf(" --disable-glow Disable the glow effect\n\n");
95
96 printf(" --font-size SIZE Font size\n\n");
97
98 printf(" --glow-duration Duration of the glow (default: 0.15)\n");
99 printf(" --glow-multiplier Adjust the amount of glow (default: 1.25)\n");
100 printf(" --glow-intensity Intensity of the glow (default: 0.5)\n\n");
101
102 printf(" --load-config CONF_FILE Load a config file\n");
103 printf(" --save-config CONF_FILE Save a config file with the current options\n");
104 printf(" --detect-changes Automatically reload modified config file\n\n");
105
106 printf(" -o, --output-ppm-stream FILE Write frames as PPM to a file ('-' for STDOUT)\n");
107 printf(" -r, --output-framerate FPS Framerate of output (25,30,60)\n\n");
108
109 printf("FILE should be a log file or '-' to read STDIN.\n\n");
110
111 if(extended_help) {
112 }
113
114 #ifdef _WIN32
115 if(!SDLApp::existing_console) {
116 printf("Press Enter\n");
117 getchar();
118 }
119 #endif
120
121 exit(0);
122 }
123
LogstalgiaSettings()124 LogstalgiaSettings::LogstalgiaSettings() {
125 log_level = LOG_LEVEL_OFF;
126 splash = -1.0f;
127 run_tests = false;
128
129 setLogstalgiaDefaults();
130
131 default_section_name = "logstalgia";
132
133 //translate args
134 arg_aliases["g"] = "group";
135 arg_aliases["p"] = "start-position";
136 arg_aliases["b"] = "background";
137 arg_aliases["x"] = "full-hostnames";
138 arg_aliases["u"] = "update-rate";
139 arg_aliases["s"] = "simulation-speed";
140 arg_aliases["speed"] = "simulation-speed";
141 arg_aliases["p"] = "pitch-speed";
142 arg_aliases["c"] = "splash";
143 arg_aliases["H"] = "extended-help";
144 arg_aliases["h"] = "help";
145 arg_aliases["?"] = "help";
146
147 //command line only options
148 conf_sections["help"] = "command-line";
149 conf_sections["test"] = "command-line";
150 conf_sections["extended-help"] = "command-line";
151 conf_sections["load-config"] = "command-line";
152 conf_sections["save-config"] = "command-line";
153 conf_sections["log-level"] = "command-line";
154 conf_sections["splash"] = "command-line";
155
156 // arg types
157
158 arg_types["font-size"] = "int";
159 arg_types["address-max-depth"] = "int";
160 arg_types["address-abbr-depth"] = "int";
161 arg_types["path-max-depth"] = "int";
162 arg_types["path-abbr-depth"] = "int";
163
164 arg_types["help"] = "bool";
165 arg_types["test"] = "bool";
166 arg_types["extended-help"] = "bool";
167 arg_types["splash"] = "bool";
168
169 arg_types["sync"] = "bool";
170 arg_types["full-hostnames"] = "bool";
171 arg_types["no-bounce"] = "bool";
172 arg_types["detect-changes"] = "bool";
173 arg_types["ffp"] = "bool";
174
175 arg_types["hide-paddle"] = "bool";
176 arg_types["hide-paddle-tokens"] = "bool";
177 arg_types["hide-response-code"] = "bool";
178 arg_types["hide-url-prefix"] = "bool";
179
180 arg_types["disable-auto-skip"] = "bool";
181 arg_types["disable-progress"] = "bool";
182 arg_types["disable-glow"] = "bool";
183
184 arg_types["glow-intensity"] = "float";
185 arg_types["glow-multiplier"] = "float";
186 arg_types["glow-duration"] = "float";
187 arg_types["paddle-position"] = "float";
188
189 arg_types["pitch-speed"] = "float";
190 arg_types["simulation-speed"] = "float";
191 arg_types["update-rate"] = "float";
192
193 arg_types["group"] = "multi-value";
194
195 arg_types["to"] = "string";
196 arg_types["from"] = "string";
197 arg_types["log-level"] = "string";
198 arg_types["load-config"] = "string";
199 arg_types["save-config"] = "string";
200 arg_types["path"] = "string";
201 arg_types["background"] = "string";
202 arg_types["start-position"] = "string";
203 arg_types["stop-position"] = "string";
204 arg_types["paddle-mode"] = "string";
205 arg_types["display-fields"] = "string";
206 arg_types["address-separators"] = "string";
207 arg_types["group-separators"] = "string";
208
209 arg_types["title"] = "string";
210 }
211
setLogstalgiaDefaults()212 void LogstalgiaSettings::setLogstalgiaDefaults() {
213
214 path = "";
215 display_fields.clear();
216 display_log_entry = false;
217
218 sync = false;
219
220 start_time = stop_time = 0;
221
222 start_position = 0.0f;
223 stop_position = 1.0f;
224
225 address_max_depth = 0;
226 address_abbr_depth = 0;
227 address_separators = ".:";
228
229 path_max_depth = 0;
230 path_abbr_depth = 0;
231 path_separators = "/";
232
233 detect_changes = false;
234
235 paddle_mode = PADDLE_SINGLE;
236 paddle_position = 0.67f;
237
238 pitch_speed = 0.15f;
239 simulation_speed = 1.0f;
240 update_rate = 5.0f;
241
242 glow_intensity = 0.5f;
243 glow_multiplier = 1.25f;
244 glow_duration = 0.15f;
245
246 disable_auto_skip = false;
247 disable_progress = false;
248 disable_glow = false;
249
250 hide_response_code = false;
251 hide_paddle = false;
252 hide_url_prefix = false;
253 hide_paddle_tokens = false;
254
255 no_bounce = false;
256
257 mask_hostnames = true;
258
259 ffp = false;
260
261 background_colour = vec3(0.0f, 0.0f, 0.0f);
262
263 font_size = 14;
264
265 title = "";
266
267 groups.clear();
268 }
269
commandLineOption(const std::string & name,const std::string & value)270 void LogstalgiaSettings::commandLineOption(const std::string& name, const std::string& value) {
271
272 if(name == "help") {
273 help();
274 }
275
276 if(name == "test") {
277 run_tests = true;
278 return;
279 }
280
281 if(name == "extended-help") {
282 help(true);
283 }
284
285 if(name == "splash") {
286 splash = 10.0f;
287 return;
288 }
289
290 if(name == "load-config" && value.size() > 0) {
291 load_config = value;
292 return;
293 }
294
295 if(name == "save-config" && value.size() > 0) {
296 save_config = value;
297 return;
298 }
299
300 if(name == "log-level") {
301 if(value == "warn") {
302 log_level = LOG_LEVEL_WARN;
303 } else if(value == "debug") {
304 log_level = LOG_LEVEL_DEBUG;
305 } else if(value == "info") {
306 log_level = LOG_LEVEL_INFO;
307 } else if(value == "error") {
308 log_level = LOG_LEVEL_ERROR;
309 } else if(value == "pedantic") {
310 log_level = LOG_LEVEL_PEDANTIC;
311 }
312 return;
313 }
314
315 std::string invalid_error = std::string("invalid ") + name + std::string(" value");
316 throw ConfFileException(invalid_error, "", 0);
317 }
318
importLogstalgiaSettings(ConfFile & conffile,ConfSection * settings)319 void LogstalgiaSettings::importLogstalgiaSettings(ConfFile& conffile, ConfSection* settings) {
320
321 setLogstalgiaDefaults();
322
323 if(settings == 0) settings = conffile.getSection(default_section_name);
324
325 if(settings == 0) {
326 settings = conffile.addSection("logstalgia");
327 }
328
329 ConfEntry* entry = 0;
330
331 if((entry = settings->getEntry("glow-intensity")) != 0) {
332
333 if(!entry->hasValue()) conffile.entryException(entry, "specify glow-intensity (float)");
334
335 glow_intensity = entry->getFloat();
336
337 if(glow_intensity <= 0.0f) {
338 conffile.invalidValueException(entry);
339 }
340 }
341
342 if((entry = settings->getEntry("glow-multiplier")) != 0) {
343
344 if(!entry->hasValue()) conffile.entryException(entry, "specify glow-multiplier (float)");
345
346 glow_multiplier = entry->getFloat();
347
348 if(glow_multiplier <= 0.0f) {
349 conffile.invalidValueException(entry);
350 }
351 }
352
353 if((entry = settings->getEntry("glow-duration")) != 0) {
354
355 if(!entry->hasValue()) conffile.entryException(entry, "specify glow-duration (float)");
356
357 glow_duration = entry->getFloat();
358
359 if(glow_duration <= 0.0f || glow_duration > 1.0f) {
360 conffile.invalidValueException(entry);
361 }
362 }
363
364 if((entry = settings->getEntry("font-size")) != 0) {
365
366 if(!entry->hasValue()) conffile.entryException(entry, "specify font size");
367
368 font_size = entry->getInt();
369
370 if(font_size<1 || font_size>100) {
371 conffile.invalidValueException(entry);
372 }
373 }
374
375 if((entry = settings->getEntry("address-separators")) != 0) {
376
377 if(!entry->hasValue()) conffile.entryException(entry, "specify address separators");
378
379 address_separators = entry->getString();
380
381 if(address_separators.empty() || address_separators.size() > 100) {
382 conffile.invalidValueException(entry);
383 }
384 }
385
386 if((entry = settings->getEntry("address-max-depth")) != 0) {
387
388 if(!entry->hasValue()) conffile.entryException(entry, "specify address max depth");
389
390 address_max_depth = entry->getInt();
391
392 if(address_max_depth < 0) {
393 conffile.invalidValueException(entry);
394 }
395 }
396
397 if((entry = settings->getEntry("address-abbr-depth")) != 0) {
398
399 if(!entry->hasValue()) conffile.entryException(entry, "specify address abbreviation depth");
400
401 address_abbr_depth = entry->getInt();
402
403 if(address_abbr_depth < -1) {
404 conffile.invalidValueException(entry);
405 }
406 }
407
408 if((entry = settings->getEntry("path-separators")) != 0) {
409
410 if(!entry->hasValue()) conffile.entryException(entry, "specify path separators");
411
412 path_separators = entry->getString();
413
414 if(path_separators.empty() || path_separators.size() > 100) {
415 conffile.invalidValueException(entry);
416 }
417 }
418
419 if((entry = settings->getEntry("path-max-depth")) != 0) {
420
421 if(!entry->hasValue()) conffile.entryException(entry, "specify path max depth");
422
423 path_max_depth = entry->getInt();
424
425 if(path_max_depth < 0) {
426 conffile.invalidValueException(entry);
427 }
428 }
429
430 if((entry = settings->getEntry("path-abbr-depth")) != 0) {
431
432 if(!entry->hasValue()) conffile.entryException(entry, "specify path abbreviation depth");
433
434 path_abbr_depth = entry->getInt();
435
436 if(path_abbr_depth < -1) {
437 conffile.invalidValueException(entry);
438 }
439 }
440
441 if((entry = settings->getEntry("background")) != 0) {
442
443 if(!entry->hasValue()) conffile.entryException(entry, "specify background colour (FFFFFF)");
444
445 int r,g,b;
446
447 std::string colstring = entry->getString();
448
449 if(entry->isVec3()) {
450 background_colour = entry->getVec3();
451 } else if(colstring.size()==6 && sscanf(colstring.c_str(), "%02x%02x%02x", &r, &g, &b) == 3) {
452 background_colour = vec3(r,g,b);
453 background_colour /= 255.0f;
454 } else {
455 conffile.invalidValueException(entry);
456 }
457 }
458
459 if((entry = settings->getEntry("from")) != 0) {
460
461 if(!entry->hasValue()) conffile.entryException(entry, "specify from (YYYY-MM-DD hh:mm:ss)");
462
463 if(!parseDateTime(entry->getString(), start_time)) {
464 conffile.invalidValueException(entry);
465 }
466 }
467
468 if((entry = settings->getEntry("to")) != 0) {
469
470 if(!entry->hasValue()) conffile.entryException(entry, "specify to (YYYY-MM-DD hh:mm:ss)");
471
472 if(!parseDateTime(entry->getString(), stop_time)) {
473 conffile.invalidValueException(entry);
474 }
475 }
476
477 if((entry = settings->getEntry("start-position")) != 0) {
478
479 if(!entry->hasValue()) conffile.entryException(entry, "specify start-position (float,random)");
480
481 start_position = entry->getFloat();
482
483 if(start_position<=0.0 || start_position>=1.0) {
484 conffile.entryException(entry, "start-position outside of range 0.0 - 1.0 (non-inclusive)");
485 }
486 }
487
488 if((entry = settings->getEntry("stop-position")) != 0) {
489
490 if(!entry->hasValue()) conffile.entryException(entry, "specify stop-position (float)");
491
492 stop_position = entry->getFloat();
493
494 if(stop_position<=0.0 || stop_position>1.0) {
495 conffile.entryException(entry, "stop-position outside of range 0.0 - 1.0 (inclusive)");
496 }
497 }
498
499 if((entry = settings->getEntry("group")) != 0) {
500
501 ConfEntryList* group_entries = settings->getEntries("group");
502
503 for(ConfEntry* entry : *group_entries) {
504 if(!entry->hasValue()) conffile.entryException(entry, "specify group definition");
505
506 SummarizerGroup group;
507 std::string error;
508
509 if(!SummarizerGroup::parse(entry->getString(), group, error)) {
510 if(error.empty()) error = "invalid group definition";
511 conffile.entryException(entry, error);
512 }
513
514 groups.push_back(group);
515 }
516 }
517
518 if((entry = settings->getEntry("paddle-mode")) != 0) {
519
520 if(!entry->hasValue()) conffile.entryException(entry, "specify paddle-mode (vhost,pid)");
521
522 std::string paddle_mode_string = entry->getString();
523
524 if(paddle_mode_string == "single") {
525 paddle_mode = PADDLE_SINGLE;
526
527 } else if(paddle_mode_string == "pid") {
528 paddle_mode = PADDLE_PID;
529
530 } else if(paddle_mode_string == "vhost") {
531 paddle_mode = PADDLE_VHOST;
532
533 } else {
534 conffile.entryException(entry, "invalid paddle-mode");
535 }
536 }
537
538 if((entry = settings->getEntry("paddle-position")) != 0) {
539
540 if(!entry->hasValue()) conffile.entryException(entry, "specify paddle-position (0.25 - 0.75)");
541
542 paddle_position = entry->getFloat();
543
544 if(paddle_position < 0.25f || paddle_position > 0.75f) {
545 conffile.entryException(entry, "paddle-position outside of range 0.25 - 0.75");
546 }
547 }
548
549 if((entry = settings->getEntry("pitch-speed")) != 0) {
550
551 if(!entry->hasValue()) conffile.entryException(entry, "specify pitch speed (0.1 to 10.0)");
552
553 pitch_speed = entry->getFloat();
554
555 if(pitch_speed < 0.1f || pitch_speed > 10.0f) {
556 conffile.entryException(entry, "pitch speed should be between 0.1 and 10.0");
557 }
558 }
559
560 if((entry = settings->getEntry("simulation-speed")) != 0) {
561
562 if(!entry->hasValue()) conffile.entryException(entry, "specify simulation speed (0.1 to 30)");
563
564 simulation_speed = entry->getFloat();
565
566 if(simulation_speed < 0.1f || simulation_speed > 30.0f) {
567 conffile.entryException(entry, "simulation speed should be between 0.1 and 30");
568 }
569 }
570
571 if((entry = settings->getEntry("update-rate")) != 0) {
572
573 if(!entry->hasValue()) conffile.entryException(entry, "specify update rate (1 to 60)");
574
575 update_rate = entry->getFloat();
576
577 if(update_rate < 1.0f || update_rate > 60.0f) {
578 conffile.entryException(entry, "update rate should be between 1 and 60");
579 }
580 }
581
582 if(settings->getBool("sync")) {
583 sync = true;
584 }
585
586 if(settings->getBool("hide-paddle")) {
587 paddle_mode = PADDLE_NONE;
588 }
589
590 if(settings->getBool("hide-paddle-tokens")) {
591 hide_paddle_tokens = true;
592 }
593
594 if(settings->getBool("hide-response-code")) {
595 hide_response_code = true;
596 }
597
598 if(settings->getBool("no-bounce")) {
599 no_bounce = true;
600 }
601
602 if(settings->getBool("disable-auto-skip")) {
603 disable_auto_skip = true;
604 }
605
606 if(settings->getBool("disable-progress")) {
607 disable_progress = true;
608 }
609
610 if(settings->getBool("disable-glow")) {
611 disable_glow = true;
612 }
613
614 if(settings->getBool("full-hostnames")) {
615 mask_hostnames = false;
616 }
617
618 if(settings->getBool("hide-url-prefix")) {
619 hide_url_prefix = true;
620 }
621
622 if(settings->getBool("ffp")) {
623 ffp = true;
624 }
625
626 if(settings->getBool("detect-changes")) {
627 detect_changes = true;
628 }
629
630 if((entry = settings->getEntry("display-fields")) != 0) {
631 display_fields.clear();
632 display_log_entry = false;
633
634 if(!entry->hasValue()) conffile.missingValueException(entry);
635
636 std::string field_list = entry->getString();
637
638 boost::algorithm::erase_all(field_list, " ");
639
640 size_t sep;
641 while((sep = field_list.find(",")) != std::string::npos) {
642
643 if(sep == 0 && field_list.size()==1) break;
644
645 if(sep == 0) {
646 field_list = field_list.substr(sep+1, field_list.size()-1);
647 continue;
648 }
649
650 std::string field = field_list.substr(0, sep);
651 display_fields.push_back(field);
652 field_list = field_list.substr(sep+1, field_list.size()-1);
653 }
654
655 if(field_list.size() > 0 && field_list != ",") {
656 display_fields.push_back(field_list);
657 }
658
659 const std::vector<std::string>& valid_fields = LogEntry::getFields();
660
661 for(const std::string& field : display_fields) {
662 if(std::find(valid_fields.begin(), valid_fields.end(), field) == valid_fields.end()) {
663 std::string invalid_field_error = std::string("invalid display field ") + field;
664 conffile.entryException(entry, invalid_field_error);
665 }
666
667 if(field == "log_entry") {
668 display_log_entry = true;
669 }
670 }
671 }
672
673 //validate path
674 if(settings->hasValue("path")) {
675 path = settings->getString("path");
676 }
677
678 if (path.empty() && !isatty(fileno(stdin))) {
679 path = "-";
680 }
681
682 if(path == "-") {
683 /*
684 if(log_format.size() == 0) {
685 throw ConfFileException("log-format required when reading from STDIN", "", 0);
686 }*/
687
688 #ifdef _WIN32
689 DWORD available_bytes;
690 HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
691
692 while(PeekNamedPipe(stdin_handle, 0, 0, 0,
693 &available_bytes, 0) && available_bytes==0 && !std::cin.fail()) {
694 SDL_Delay(100);
695 }
696 #else
697 while(std::cin.peek() == EOF && !std::cin.fail()) SDL_Delay(100);
698 #endif
699
700 std::cin.clear();
701 }
702
703 if((entry = settings->getEntry("title")) != 0) {
704
705 if(!entry->hasValue()) conffile.entryException(entry, "specify title");
706
707 title = entry->getString();
708 }
709
710 }
711
exportLogstalgiaSettings(ConfFile & conf)712 void LogstalgiaSettings::exportLogstalgiaSettings(ConfFile& conf) {
713
714 ConfSection* settings = conf.addSection("logstalgia");
715
716 settings->addEntry(new ConfEntry("glow-intensity", glow_intensity));
717 settings->addEntry(new ConfEntry("glow-multiplier", glow_multiplier));
718 settings->addEntry(new ConfEntry("glow-duration", glow_duration));
719 settings->addEntry(new ConfEntry("font-size", font_size));
720
721 if(address_separators != ".:") {
722 settings->addEntry(new ConfEntry("address-separators", address_separators));
723 }
724
725 if(address_max_depth != 0) {
726 settings->addEntry(new ConfEntry("address-max-depth", address_max_depth));
727 }
728
729 if(address_abbr_depth != 0) {
730 settings->addEntry(new ConfEntry("address-abbr-depth", address_abbr_depth));
731 }
732
733 if(path_separators != "/") {
734 settings->addEntry(new ConfEntry("path-separators", path_separators));
735 }
736
737 if(path_max_depth != 0) {
738 settings->addEntry(new ConfEntry("group-max-depth", path_max_depth));
739 }
740
741 if(path_abbr_depth != 0) {
742 settings->addEntry(new ConfEntry("group-abbr-depth", path_abbr_depth));
743 }
744
745 if(!display_fields.empty()) {
746
747 std::string display_fields_string;
748
749 for(const std::string& field : display_fields) {
750 if(!display_fields_string.empty()) display_fields_string += ",";
751 display_fields_string += field;
752 }
753
754 settings->addEntry(new ConfEntry("display-fields", display_fields_string));
755 }
756
757 if(background_colour != vec3(0.0f)) {
758 char background_hex[256];
759 vec3 bg = background_colour * 255.0f;
760 snprintf(background_hex, 256, "%02X%02X%02X", (int)bg.x,(int)bg.y,(int)bg.z);
761 settings->addEntry(new ConfEntry("background", std::string(background_hex)));
762 }
763
764 if(start_time != 0) {
765 char timestr[256];
766 struct tm* timeinfo = localtime ( &start_time );
767 strftime(timestr, 256, "%s", timeinfo);
768 settings->addEntry(new ConfEntry("from", std::string(timestr)));
769 }
770
771 if(stop_time != 0) {
772 char timestr[256];
773 struct tm* timeinfo = localtime ( &stop_time );
774 strftime(timestr, 256, "%s", timeinfo);
775 settings->addEntry(new ConfEntry("to", std::string(timestr)));
776 }
777
778 if(start_position > 0.0f) {
779 settings->addEntry(new ConfEntry("start-position", start_position));
780 }
781
782 if(stop_position < 1.0f) {
783 settings->addEntry(new ConfEntry("start-position", stop_position));
784 }
785
786 for(const SummarizerGroup& group : groups) {
787 settings->addEntry("group", group.definition);
788 }
789
790 if(paddle_mode != PADDLE_NONE) {
791 std::string paddle_mode_string;
792
793 switch(paddle_mode) {
794 case PADDLE_PID:
795 paddle_mode_string = "pid";
796 break;
797 case PADDLE_VHOST:
798 paddle_mode_string = "vhost";
799 break;
800 case PADDLE_SINGLE:
801 default:
802 break;
803 }
804
805 if(!paddle_mode_string.empty()) {
806 settings->addEntry(new ConfEntry("paddle-mode", paddle_mode_string));
807 }
808 } else {
809 settings->addEntry(new ConfEntry("hide-paddle", true));
810 }
811
812 settings->addEntry(new ConfEntry("paddle-position", paddle_position));
813 settings->addEntry(new ConfEntry("pitch-speed", pitch_speed));
814
815 if(simulation_speed != 1.0f) {
816 settings->addEntry(new ConfEntry("simulation-speed", simulation_speed));
817 }
818
819 if(update_rate != 5.0f) {
820 settings->addEntry(new ConfEntry("update-rate", update_rate));
821 }
822
823 if(sync) {
824 settings->addEntry(new ConfEntry("sync", sync));
825 }
826
827 if(hide_paddle_tokens) {
828 settings->addEntry(new ConfEntry("hide-paddle-tokens", hide_paddle_tokens));
829 }
830
831 if(hide_response_code) {
832 settings->addEntry(new ConfEntry("hide-response-code", hide_response_code));
833 }
834
835 if(no_bounce) {
836 settings->addEntry(new ConfEntry("no-bounce", no_bounce));
837 }
838
839 if(disable_auto_skip) {
840 settings->addEntry(new ConfEntry("disable-auto-skip", disable_auto_skip));
841 }
842
843 if(disable_progress) {
844 settings->addEntry(new ConfEntry("disable-progress", disable_progress));
845 }
846
847 if(disable_glow) {
848 settings->addEntry(new ConfEntry("disable-glow", disable_glow));
849 }
850
851 if(mask_hostnames == false) {
852 settings->addEntry(new ConfEntry("full-hostnames", true));
853 }
854
855 if(hide_url_prefix) {
856 settings->addEntry(new ConfEntry("hide-url-prefix", hide_url_prefix));
857 }
858
859 if(ffp) {
860 settings->addEntry(new ConfEntry("ffp", ffp));
861 }
862
863 if(detect_changes) {
864 settings->addEntry(new ConfEntry("detect-changes", true));
865 }
866
867 settings->addEntry("path", path);
868
869 if (title.length() > 0) {
870 settings->addEntry(new ConfEntry("title", title));
871 }
872 }
873
874 // SummarizerGroup
875
SummarizerGroup()876 SummarizerGroup::SummarizerGroup() {
877 max_depth = 0;
878 abbrev_depth = 0;
879 percent = 0;
880 colour = vec3(0.0f);
881 }
882
parse(const std::string & group_string,SummarizerGroup & group,std::string & error)883 bool SummarizerGroup::parse(const std::string& group_string, SummarizerGroup& group, std::string& error) {
884
885 std::vector<std::string> group_definition;
886 Regex groupregex("^([^,]+),(?:(HOST|CODE|URI)=)?([^,]+)(?:,SEP=([^,]+))?(?:,MAX=([^,]+))?(?:,ABBR=([^,]+))?,(\\d+)(?:,([^,]+))?$");
887 groupregex.match(group_string, &group_definition);
888
889 /*
890 for(int i=0;i<group_definition.size();i++) {
891 debugLog("group_definition[%d] = %s", i, group_definition[i].c_str());
892 }
893 */
894
895 // TODO: make this white?
896 vec3 colour(0.0f, 0.0f, 0.0f);
897
898 if(group_definition.size()>=6) {
899 std::string group_name = group_definition[0];
900 std::string group_type = group_definition[1];
901 std::string group_regex = group_definition[2];
902 std::string separators = group_definition[3];
903
904 if(group_type.empty()) group_type = "URI";
905 if(separators.empty()) separators = settings.path_separators;
906
907 int max_depth = group_definition[4].empty() ? settings.path_max_depth : atoi(group_definition[4].c_str());
908 int abbrev_depth = group_definition[5].empty() ? settings.path_abbr_depth : atoi(group_definition[5].c_str());
909
910 int percent = atoi(group_definition[6].c_str());
911
912 debugLog("group name %s type %s regex %s max %d abbrev %d percent %d",
913 group_name.c_str(), group_type.c_str(), group_regex.c_str(), max_depth, abbrev_depth, percent);
914
915 // TODO: allow ommiting percent, if percent == 0, divide up remaining space amoung groups with no percent
916
917 //check for optional colour param
918 if(group_definition.size() >= 8) {
919 int r, g, b;
920 if(sscanf(group_definition[7].c_str(), "%02x%02x%02x", &r, &g, &b) == 3) {
921 colour = vec3( r, g, b );
922 debugLog("r = %d, g = %d, b = %d\n", r, g, b);
923 colour /= 255.0f;
924 }
925 }
926
927 Regex regex(group_regex, true);
928 if(!regex.isValid()) {
929 error = "invalid regular expression '" + group_regex + "'";
930 return false;
931 }
932
933 if(percent < 0 || percent > 100) {
934 error = "invalid percent value";
935 return false;
936 }
937
938 if(abbrev_depth < -1) {
939 error = "invalid ABBR value";
940 return false;
941 }
942
943 if(max_depth < 0) {
944 error = "invalid MAX value";
945 return false;
946 }
947
948 group.title = group_name;
949 group.type = group_type;
950 group.regex = group_regex;
951 group.separators = separators;
952 group.max_depth = max_depth;
953 group.abbrev_depth = abbrev_depth;
954 group.percent = percent;
955 group.colour = colour;
956 group.definition = group_string;
957
958 return true;
959 }
960
961 return false;
962 }
963