76
84
#define FILT_COUNT_STATUS 0x800
77
85
#define FILT_COUNT_SRV_STATUS 0x1000
86
#define FILT_COUNT_TERM_CODES 0x2000
88
#define FILT_COUNT_URL_ONLY 0x004000
89
#define FILT_COUNT_URL_COUNT 0x008000
90
#define FILT_COUNT_URL_ERR 0x010000
91
#define FILT_COUNT_URL_TTOT 0x020000
92
#define FILT_COUNT_URL_TAVG 0x040000
93
#define FILT_COUNT_URL_TTOTO 0x080000
94
#define FILT_COUNT_URL_TAVGO 0x100000
95
#define FILT_COUNT_URL_ANY (FILT_COUNT_URL_ONLY|FILT_COUNT_URL_COUNT|FILT_COUNT_URL_ERR| \
96
FILT_COUNT_URL_TTOT|FILT_COUNT_URL_TAVG|FILT_COUNT_URL_TTOTO|FILT_COUNT_URL_TAVGO)
79
98
unsigned int filter = 0;
80
99
unsigned int filter_invert = 0;
367
387
int f, tot, last, linenum, err, parse_err;
368
388
struct timer *t = NULL, *t2;
369
389
struct eb32_node *n;
390
struct url_stat *ustat = NULL;
391
struct ebpt_node *ebpt_old;
372
394
int filter_acc_delay = 0, filter_acc_count = 0;
425
447
filter |= FILT_COUNT_STATUS;
426
448
else if (strcmp(argv[0], "-srv") == 0)
427
449
filter |= FILT_COUNT_SRV_STATUS;
450
else if (strcmp(argv[0], "-tc") == 0)
451
filter |= FILT_COUNT_TERM_CODES;
452
else if (strcmp(argv[0], "-u") == 0)
453
filter |= FILT_COUNT_URL_ONLY;
454
else if (strcmp(argv[0], "-uc") == 0)
455
filter |= FILT_COUNT_URL_COUNT;
456
else if (strcmp(argv[0], "-ue") == 0)
457
filter |= FILT_COUNT_URL_ERR;
458
else if (strcmp(argv[0], "-ua") == 0)
459
filter |= FILT_COUNT_URL_TAVG;
460
else if (strcmp(argv[0], "-ut") == 0)
461
filter |= FILT_COUNT_URL_TTOT;
462
else if (strcmp(argv[0], "-uao") == 0)
463
filter |= FILT_COUNT_URL_TAVGO;
464
else if (strcmp(argv[0], "-uto") == 0)
465
filter |= FILT_COUNT_URL_TTOTO;
428
466
else if (strcmp(argv[0], "-o") == 0) {
430
468
die("Fatal: output file name already specified.\n");
609
651
if (unlikely(filter & FILT_COUNT_STATUS)) {
610
b = field_start(line, STATUS_FIELD + skip_fields);
652
/* first, let's ensure that the line is a traffic line (beginning
653
* with an IP address)
655
b = field_start(line, SOURCE_FIELD + skip_fields);
656
if (*b < '0' || *b > '9') {
661
b = field_start(b, STATUS_FIELD - SOURCE_FIELD + 1);
612
663
truncated_line(linenum, line);
673
if (unlikely(filter & FILT_COUNT_TERM_CODES)) {
674
/* first, let's ensure that the line is a traffic line (beginning
675
* with an IP address)
677
b = field_start(line, SOURCE_FIELD + skip_fields);
678
if (*b < '0' || *b > '9') {
683
b = field_start(b, TERM_CODES_FIELD - SOURCE_FIELD + 1);
685
truncated_line(linenum, line);
688
val = 256 * b[0] + b[1];
690
t2 = insert_value(&timers[0], &t, val);
622
695
if (unlikely(filter & FILT_COUNT_SRV_STATUS)) {
624
697
struct ebmb_node *srv_node;
795
if (unlikely(filter & FILT_COUNT_URL_ANY)) {
796
/* first, let's ensure that the line is a traffic line (beginning
797
* with an IP address)
799
b = field_start(line, SOURCE_FIELD + skip_fields); // avg 95 ns per line
800
if (*b < '0' || *b > '9') {
805
/* let's collect the response time */
806
b = field_start(field_stop(b + 1), TIME_FIELD - SOURCE_FIELD); // avg 115 ns per line
808
truncated_line(linenum, line);
812
/* we have the field TIME_FIELD starting at <b>. We'll
813
* parse the 5 timers to detect errors, it takes avg 55 ns per line.
815
e = b; err = 0; f = 0;
817
array[f] = str2ic(e);
831
/* OK we have our timers in array[3], and err is >0 if at
832
* least one -1 was seen. <e> points to the first char of
833
* the last timer. Let's prepare a new node with that.
835
if (unlikely(!ustat))
836
ustat = calloc(1, sizeof(*ustat));
841
/* use array[4] = total time in case of error */
842
ustat->total_time = (array[3] >= 0) ? array[3] : array[4];
843
ustat->total_time_ok = (array[3] >= 0) ? array[3] : 0;
845
/* the line may be truncated because of a bad request or anything like this,
846
* without a method. Also, if it does not begin with an quote, let's skip to
847
* the next field because it's a capture. Let's fall back to the "method" itself
848
* if there's nothing else.
850
e = field_start(e, METH_FIELD - TIME_FIELD + 1); // avg 100 ns per line
851
while (*e != '"' && *e)
852
e = field_start(e, 2);
855
truncated_line(linenum, line);
859
b = field_start(e, URL_FIELD - METH_FIELD + 1); // avg 40 ns per line
863
/* stop at end of field or first ';' or '?', takes avg 64 ns per line */
866
if (*e == ' ' || *e == '?' || *e == ';' || *e == '\t') {
873
/* now instead of copying the URL for a simple lookup, we'll link
874
* to it from the node we're trying to insert. If it returns a
875
* different value, it was already there. Otherwise we just have
876
* to dynamically realloc an entry using strdup().
878
ustat->node.url.key = (char *)b;
879
ebpt_old = ebis_insert(&timers[0], &ustat->node.url);
881
if (ebpt_old != &ustat->node.url) {
882
struct url_stat *ustat_old;
883
/* node was already there, let's update previous one */
884
ustat_old = container_of(ebpt_old, struct url_stat, node.url);
885
ustat_old->nb_req ++;
886
ustat_old->nb_err += ustat->nb_err;
887
ustat_old->total_time += ustat->total_time;
888
ustat_old->total_time_ok += ustat->total_time_ok;
890
ustat->url = ustat->node.url.key = strdup(ustat->node.url.key);
891
ustat = NULL; /* node was used */
720
897
/* all other cases mean we just want to count lines */
722
899
if (unlikely(!(filter & FILT_COUNT_ONLY)))
1050
else if (filter & FILT_COUNT_TERM_CODES) {
1051
/* output all statuses in the form of <code> <occurrences> */
1052
n = eb32_first(&timers[0]);
1054
t = container_of(n, struct timer, node);
1055
printf("%c%c %d\n", (n->key >> 8), (n->key) & 255, t->count);
1059
else if (unlikely(filter & FILT_COUNT_URL_ANY)) {
1061
struct eb_node *node, *next;
1063
if (!(filter & FILT_COUNT_URL_ONLY)) {
1064
/* we have to sort on another criterion. We'll use timers[1] for the
1068
timers[1] = EB_ROOT; /* reconfigure to accept duplicates */
1069
for (node = eb_first(&timers[0]); node; node = next) {
1070
next = eb_next(node);
1073
ustat = container_of(node, struct url_stat, node.url.node);
1075
if (filter & FILT_COUNT_URL_COUNT)
1076
ustat->node.val.key = ustat->nb_req;
1077
else if (filter & FILT_COUNT_URL_ERR)
1078
ustat->node.val.key = ustat->nb_err;
1079
else if (filter & FILT_COUNT_URL_TTOT)
1080
ustat->node.val.key = ustat->total_time;
1081
else if (filter & FILT_COUNT_URL_TAVG)
1082
ustat->node.val.key = ustat->nb_req ? ustat->total_time / ustat->nb_req : 0;
1083
else if (filter & FILT_COUNT_URL_TTOTO)
1084
ustat->node.val.key = ustat->total_time_ok;
1085
else if (filter & FILT_COUNT_URL_TAVGO)
1086
ustat->node.val.key = (ustat->nb_req - ustat->nb_err) ? ustat->total_time_ok / (ustat->nb_req - ustat->nb_err) : 0;
1088
ustat->node.val.key = 0;
1090
eb64_insert(&timers[1], &ustat->node.val);
1093
timers[0] = timers[1];
1096
printf("#req err ttot tavg oktot okavg url\n");
1098
/* scan the tree in its reverse sorting order */
1099
node = eb_last(&timers[0]);
1101
ustat = container_of(node, struct url_stat, node.url.node);
1102
printf("%d %d %Ld %Ld %Ld %Ld %s\n",
1106
ustat->nb_req ? ustat->total_time / ustat->nb_req : 0,
1107
ustat->total_time_ok,
1108
(ustat->nb_req - ustat->nb_err) ? ustat->total_time_ok / (ustat->nb_req - ustat->nb_err) : 0,
1111
node = eb_prev(node);
875
1117
if (!(filter & FILT_QUIET))