static void print_html_summary (FILE * fp, GLog * logger) { char *bw, *size; off_t log_size; print_html_h2 (fp, T_HEAD, 0); print_html_begin_table (fp); print_html_begin_tbody (fp); print_html_begin_tr (fp, 0); print_html_summary_field (fp, logger->process, T_REQUESTS); print_html_summary_field (fp, get_ht_size (ht_unique_visitors), T_UNIQUE_VIS); print_html_summary_field (fp, get_ht_size (ht_referrers), T_REFERRER); if (!logger->piping) { log_size = file_size (conf.ifile); size = filesize_str (log_size); } else { size = alloc_string ("N/A"); } bw = filesize_str ((float) logger->resp_size); if (conf.ifile == NULL) conf.ifile = (char *) "STDIN"; fprintf (fp, "<td>%s</td><td>%s</td>", T_LOG, size); print_html_end_tr (fp); print_html_begin_tr (fp, 0); print_html_summary_field (fp, logger->invalid, T_F_REQUESTS); print_html_summary_field (fp, get_ht_size (ht_requests), T_UNIQUE_FIL); print_html_summary_field (fp, get_ht_size (ht_not_found_requests), T_UNIQUE404); fprintf (fp, "<td>%s</td><td>%s</td>", T_BW, bw); print_html_end_tr (fp); print_html_begin_tr (fp, 0); fprintf (fp, "<td>%s</td>", T_GEN_TIME); fprintf (fp, "<td>%llu</td>", ((long long) end_proc - start_proc)); print_html_summary_field (fp, get_ht_size (ht_requests_static), T_STATIC_FIL); fprintf (fp, "<td colspan=\"4\">%s</td>", conf.ifile); print_html_end_tr (fp); print_html_end_tbody (fp); print_html_end_table (fp); free (bw); free (size); }
/* add a first level item to dashboard */ static void add_item_to_dash (GDash ** dash, GHolderItem item, GModule module) { GDashData *idata; int *idx = &(*dash)->module[module].idx_data; idata = &(*dash)->module[module].data[(*idx)]; idata->metrics = new_gmetrics (); idata->metrics->bw.sbw = filesize_str (item.metrics->bw.nbw); idata->metrics->data = xstrdup (item.metrics->data); idata->metrics->hits = item.metrics->hits; idata->metrics->visitors = item.metrics->visitors; if (conf.append_method && item.metrics->method) idata->metrics->method = item.metrics->method; if (conf.append_protocol && item.metrics->protocol) idata->metrics->protocol = item.metrics->protocol; if (conf.serve_usecs) { idata->metrics->avgts.sts = usecs_to_str (item.metrics->avgts.nts); idata->metrics->cumts.sts = usecs_to_str (item.metrics->cumts.nts); idata->metrics->maxts.sts = usecs_to_str (item.metrics->maxts.nts); } (*idx)++; }
static char * get_str_filesize (GLog * logger, const char *ifile) { if (!logger->piping && ifile != NULL) return filesize_str (file_size (ifile)); else return alloc_string ("N/A"); }
/* get user-agent string for given key */ char * ht_bw_str (GHashTable * ht, const char *key) { gpointer value_ptr; value_ptr = g_hash_table_lookup (ht, key); if (value_ptr != NULL) return filesize_str (*(unsigned long long *) value_ptr); else return alloc_string ("-"); }
/* add a first level item to dashboard */ static void add_item_to_dash (GDash ** dash, GHolderItem item, GModule module) { int *idx = &(*dash)->module[module].idx_data; (*dash)->module[module].data[(*idx)].bandwidth = filesize_str (item.bw); (*dash)->module[module].data[(*idx)].bw = item.bw; (*dash)->module[module].data[(*idx)].data = xstrdup (item.data); (*dash)->module[module].data[(*idx)].hits = item.hits; if (conf.serve_usecs) { (*dash)->module[module].data[(*idx)].usecs = item.usecs; (*dash)->module[module].data[(*idx)].serve_time = usecs_to_str (item.usecs); } (*idx)++; }
/* add an item from a sub_list to the dashboard */ static void add_sub_item_to_dash (GDash ** dash, GHolderItem item, GModule module, int *i) { GSubList *sub_list = item.sub_list; GSubItem *iter; GDashData *idata; char *entry; int *idx; idx = &(*dash)->module[module].idx_data; if (sub_list == NULL) return; for (iter = sub_list->head; iter; iter = iter->next, (*i)++) { entry = render_child_node (iter->metrics->data); if (!entry) continue; idata = &(*dash)->module[module].data[(*idx)]; idata->metrics = new_gmetrics (); idata->metrics->visitors = iter->metrics->visitors; idata->metrics->bw.sbw = filesize_str (iter->metrics->bw.nbw); idata->metrics->data = xstrdup (entry); idata->metrics->hits = iter->metrics->hits; if (conf.serve_usecs) { idata->metrics->avgts.sts = usecs_to_str (iter->metrics->avgts.nts); idata->metrics->cumts.sts = usecs_to_str (iter->metrics->cumts.nts); idata->metrics->maxts.sts = usecs_to_str (iter->metrics->maxts.nts); } idata->is_subitem = 1; (*idx)++; free (entry); } }
/* add an item from a sub_list to the dashboard */ static void add_sub_item_to_dash (GDash ** dash, GHolderItem item, GModule module, int *i) { GSubList *sub_list = item.sub_list; GSubItem *iter; char *entry; int *idx; idx = &(*dash)->module[module].idx_data; for (iter = sub_list->head; iter; iter = iter->next) { entry = render_child_node (iter->data); if (entry) { (*dash)->module[module].data[(*idx)].bandwidth = filesize_str (iter->bw); (*dash)->module[module].data[(*idx)].bw = iter->bw; (*dash)->module[module].data[(*idx)].data = xstrdup (entry); (*dash)->module[module].data[(*idx)].hits = iter->hits; (*dash)->module[module].data[(*idx)++].is_subitem = 1; free (entry); } (*i)++; } }
/* render general statistics */ void display_general (WINDOW * win, char *ifile, GLog * logger) { char *bw, *size, *log_file; char *failed, *not_found, *process, *ref, *req; char *static_files, *now, *visitors, *exclude_ip; int x_field = 2, x_value = 0; size_t n, i, j, max_field = 0, max_value = 0, mod_val, y; typedef struct Field_ { const char *field; char *value; /* char due to log, bw, log_file */ int color; } Field; Field fields[] = { {T_REQUESTS, NULL, COL_CYAN}, {T_UNIQUE_VIS, NULL, COL_CYAN}, {T_REFERRER, NULL, COL_CYAN}, {T_LOG, NULL, COL_CYAN}, {T_F_REQUESTS, NULL, COL_CYAN}, {T_UNIQUE_FIL, NULL, COL_CYAN}, {T_UNIQUE404, NULL, COL_CYAN}, {T_BW, NULL, COL_CYAN}, {T_GEN_TIME, NULL, COL_CYAN}, {T_EXCLUDE_IP, NULL, COL_CYAN}, {T_STATIC_FIL, NULL, COL_CYAN}, {T_LOG_PATH, NULL, COL_YELLOW} }; werase (win); draw_header (win, T_HEAD, " %s", 0, 0, getmaxx (stdscr), 1, 0); if (!logger->piping && ifile != NULL) { size = filesize_str (file_size (ifile)); log_file = alloc_string (ifile); } else { size = alloc_string ("N/A"); log_file = alloc_string ("STDIN"); } bw = filesize_str ((float) logger->resp_size); /* *INDENT-OFF* */ failed = int_to_str (logger->invalid); not_found = int_to_str (get_ht_size (ht_not_found_requests)); process = int_to_str (logger->process); ref = int_to_str (get_ht_size (ht_referrers)); req = int_to_str (get_ht_size(ht_requests)); static_files = int_to_str (get_ht_size(ht_requests_static)); now = int_to_str (((long long) end_proc - start_proc)); visitors = int_to_str (get_ht_size(ht_unique_visitors)); exclude_ip = int_to_str (logger->exclude_ip); fields[0].value = process; fields[1].value = visitors; fields[2].value = ref; fields[3].value = size; fields[4].value = failed; fields[5].value = req; fields[6].value = not_found; fields[7].value = bw; fields[8].value = now; fields[9].value = exclude_ip; fields[10].value = static_files; fields[11].value = log_file; n = ARRAY_SIZE (fields); /* *INDENT-ON* */ for (i = 0, y = 2; i < n; i++) { mod_val = i % 4; if (i > 0 && mod_val == 0) { max_field = 0; max_value = 0; x_field = 2; x_value = 2; y++; } x_field += max_field; mvwprintw (win, y, x_field, "%s", fields[i].field); max_field = 0; for (j = 0; j < n; j++) { size_t len = strlen (fields[j].field); if (j % 4 == mod_val && len > max_field) max_field = len; } max_value = 0; for (j = 0; j < n; j++) { size_t len = strlen (fields[j].value); if (j % 4 == mod_val && len > max_value) max_value = len; } x_value = max_field + x_field + 1; max_field += max_value + 2; wattron (win, A_BOLD | COLOR_PAIR (fields[i].color)); mvwprintw (win, y, x_value, "%s", fields[i].value); wattroff (win, A_BOLD | COLOR_PAIR (fields[i].color)); } for (i = 0; i < n; i++) { free (fields[i].value); } }
static char * get_str_bandwidth (GLog * logger) { return filesize_str ((float) logger->resp_size); }
/* wrapper - get human-readable bandwidth given X bytes */ char * bandwidth_string (unsigned long long bw) { return filesize_str (bw); }
/* render general statistics */ void display_general (WINDOW * win, char *ifile, int piping, int processed, int invalid, unsigned long long bandwidth) { size_t n, i, j, max_field = 0, max_value = 0, mod_val, y; int x_field = 2, x_value = 0; char *bw, *size, *log_file; werase (win); draw_header (win, T_HEAD, 0, 0, getmaxx (stdscr), 1); if (!piping && ifile != NULL) { size = filesize_str (file_size (ifile)); log_file = alloc_string (ifile); } else { size = alloc_string ("N/A"); log_file = alloc_string ("STDIN"); } bw = filesize_str ((float) bandwidth); typedef struct Field_ { char *field; char *value; /* char due to log, bw, log_file */ int color; } Field; /* *INDENT-OFF* */ char *failed = int_to_str (invalid); char *not_found = int_to_str (g_hash_table_size (ht_not_found_requests)); char *process = int_to_str (processed); char *ref = int_to_str (g_hash_table_size (ht_referrers)); char *req = int_to_str (g_hash_table_size (ht_requests)); char *static_files = int_to_str (g_hash_table_size (ht_requests_static)); char *time = int_to_str (((int) end_proc - start_proc)); char *visitors = int_to_str (g_hash_table_size (ht_unique_visitors)); Field fields[] = { {T_REQUESTS, process, COL_CYAN}, {T_UNIQUE_VIS, visitors, COL_CYAN}, {T_REFERRER, ref, COL_CYAN}, {T_LOG, size, COL_CYAN}, {T_F_REQUESTS, failed, COL_CYAN}, {T_UNIQUE_FIL, req, COL_CYAN}, {T_UNIQUE404, not_found, COL_CYAN}, {T_BW, bw, COL_CYAN}, {T_GEN_TIME, time, COL_CYAN}, {T_STATIC_FIL, static_files, COL_CYAN}, {"", alloc_string (""), COL_CYAN}, {T_LOG_PATH, log_file, COL_YELLOW} }; n = ARRAY_SIZE (fields); /* *INDENT-ON* */ for (i = 0, y = 2; i < n; i++) { mod_val = i % 4; if (i > 0 && mod_val == 0) { max_field = 0; max_value = 0; x_field = 2; x_value = 2; y++; } x_field += max_field; mvwprintw (win, y, x_field, "%s", fields[i].field); max_field = 0; for (j = 0; j < n; j++) { size_t len = strlen (fields[j].field); if (j % 4 == mod_val && len > max_field) max_field = len; } max_value = 0; for (j = 0; j < n; j++) { size_t len = strlen (fields[j].value); if (j % 4 == mod_val && len > max_value) max_value = len; } x_value = max_field + x_field + 1; max_field += max_value + 2; wattron (win, A_BOLD | COLOR_PAIR (fields[i].color)); mvwprintw (win, y, x_value, "%s", fields[i].value); wattroff (win, A_BOLD | COLOR_PAIR (fields[i].color)); } for (i = 0; i < n; i++) { free (fields[i].value); } }
/* Get the bandwidth in a human readable format. * * On success, the bandwidth as a string is returned. */ static char * get_str_bandwidth (GLog * glog) { return filesize_str ((float) glog->resp_size); }
static void print_html_request_report (FILE * fp, GHolder * h, int process) { #ifdef TCB_BTREE TCBDB *ht = NULL; #elif TCB_MEMHASH TCMDB *ht = NULL; #else GHashTable *ht; #endif char *data, *bandwidth, *usecs; const char *desc = REQUE_DESC; const char *head = REQUE_HEAD; const char *id = REQUE_ID; float percent; int hits; int i, until = 0; if (h->idx == 0) return; ht = get_ht_by_module (h->module); if (ht == ht_requests_static) { head = STATI_HEAD; id = STATI_ID; desc = STATI_DESC; } else if (ht == ht_not_found_requests) { head = FOUND_HEAD; id = FOUND_ID; desc = FOUND_DESC; } print_html_h2 (fp, head, id); print_p (fp, desc); print_html_begin_table (fp); print_html_begin_thead (fp); fprintf (fp, "<tr>"); fprintf (fp, "<th>Hits</th>"); fprintf (fp, "<th>%%</th>"); fprintf (fp, "<th>Bandwidth</th>"); if (conf.serve_usecs) fprintf (fp, "<th>Time served</th>"); if (conf.append_protocol) fprintf (fp, "<th>Protocol</th>"); if (conf.append_method) fprintf (fp, "<th>Method</th>"); fprintf (fp, "<th>URL<span class=\"r\" onclick=\"t(this)\">◀</span>"); fprintf (fp, "</th>"); fprintf (fp, "</tr>"); print_html_end_thead (fp); print_html_begin_tbody (fp); until = h->idx < MAX_CHOICES ? h->idx : MAX_CHOICES; for (i = 0; i < until; i++) { hits = h->items[i].hits; data = h->items[i].data; percent = get_percentage (process, hits); percent = percent < 0 ? 0 : percent; bandwidth = filesize_str (h->items[i].bw); print_html_begin_tr (fp, i > OUTPUT_N ? 1 : 0); /* hits */ fprintf (fp, "<td>%d</td>", hits); /* percent */ fprintf (fp, "<td>%4.2f%%</td>", percent); /* bandwidth */ fprintf (fp, "<td>"); clean_output (fp, bandwidth); fprintf (fp, "</td>"); /* usecs */ if (conf.serve_usecs) { usecs = usecs_to_str (h->items[i].usecs); fprintf (fp, "<td>"); clean_output (fp, usecs); fprintf (fp, "</td>"); free (usecs); } /* protocol */ if (conf.append_protocol) { fprintf (fp, "<td>"); clean_output (fp, h->items[i].protocol); fprintf (fp, "</td>"); } /* method */ if (conf.append_method) { fprintf (fp, "<td>"); clean_output (fp, h->items[i].method); fprintf (fp, "</td>"); } /* data */ fprintf (fp, "<td>"); clean_output (fp, data); fprintf (fp, "</td>"); print_html_end_tr (fp); free (bandwidth); } print_html_end_tbody (fp); print_html_end_table (fp); }
static void print_html_hosts (FILE * fp, GHolder * h, int process) { GAgents *agents; char *data, *bandwidth, *usecs, *ag, *ptr_value, *host; float percent, l; int hits; int i, j, max, until = 0, delims = 0, colspan = 6; size_t alloc = 0; #ifdef HAVE_LIBGEOIP const char *location = NULL; colspan++; #endif if (h->idx == 0) return; print_html_h2 (fp, HOSTS_HEAD, HOSTS_ID); print_p (fp, HOSTS_DESC); print_html_begin_table (fp); print_html_begin_thead (fp); fprintf (fp, "<tr>"); fprintf (fp, "<th></th>"); fprintf (fp, "<th>Hits</th>"); fprintf (fp, "<th>%%</th>"); fprintf (fp, "<th>Bandwidth</th>"); if (conf.serve_usecs) { colspan++; fprintf (fp, "<th>Time served</th>"); } fprintf (fp, "<th>IP</th>"); #ifdef HAVE_LIBGEOIP fprintf (fp, "<th>Country</th>"); #endif if (conf.enable_html_resolver) { colspan++; fprintf (fp, "<th>Hostname</th>"); } fprintf (fp, "<th style=\"width:100%%;text-align:right;\">"); fprintf (fp, "<span class=\"r\" onclick=\"t(this)\">◀</span>"); fprintf (fp, "</th>"); fprintf (fp, "</tr>"); print_html_end_thead (fp); print_html_begin_tbody (fp); until = h->idx < MAX_CHOICES ? h->idx : MAX_CHOICES; max = 0; for (i = 0; i < until; i++) { if (h->items[i].hits > max) max = h->items[i].hits; } for (i = 0; i < until; i++) { hits = h->items[i].hits; data = h->items[i].data; percent = get_percentage (process, hits); percent = percent < 0 ? 0 : percent; bandwidth = filesize_str (h->items[i].bw); l = get_percentage (max, hits); l = l < 1 ? 1 : l; #ifdef HAVE_LIBTOKYOCABINET ag = tc_db_get_str (ht_hosts_agents, data); #else ag = g_hash_table_lookup (ht_hosts_agents, data); #endif print_html_begin_tr (fp, i > OUTPUT_N ? 1 : 0); fprintf (fp, "<td>"); if (ag != NULL) fprintf (fp, "<span class=\"s\" onclick=\"a(this)\">▶</span>"); else fprintf (fp, "<span class=\"s\">-</span>"); fprintf (fp, "</td>"); fprintf (fp, "<td>%d</td>", hits); fprintf (fp, "<td>%4.2f%%</td>", percent); fprintf (fp, "<td>"); clean_output (fp, bandwidth); fprintf (fp, "</td>"); /* usecs */ if (conf.serve_usecs) { usecs = usecs_to_str (h->items[i].usecs); fprintf (fp, "<td>"); clean_output (fp, usecs); fprintf (fp, "</td>"); free (usecs); } fprintf (fp, "<td>%s</td>", data); #ifdef HAVE_LIBGEOIP location = get_geoip_data (data); fprintf (fp, "<td style=\"white-space:nowrap;\">%s</td>", location); #endif if (conf.enable_html_resolver) { host = reverse_ip (data); fprintf (fp, "<td style=\"white-space:nowrap;\">%s</td>", host); free (host); } fprintf (fp, "<td class=\"graph\">"); fprintf (fp, "<div class=\"bar\" style=\"width:%f%%\"></div>", l); fprintf (fp, "</td>"); print_html_end_tr (fp); /* render agents for each host */ if (ag != NULL) { ptr_value = (char *) ag; delims = count_occurrences (ptr_value, '|'); /* round-up + padding */ alloc = ((strlen (ptr_value) + 300 - 1) / 300) + delims + 1; agents = xmalloc (alloc * sizeof (GAgents)); memset (agents, 0, alloc * sizeof (GAgents)); /* split agents into struct */ split_agent_str (ptr_value, agents, 300); fprintf (fp, "<tr class=\"agent-hide\">\n"); fprintf (fp, "<td colspan=\"%d\">\n", colspan); fprintf (fp, "<div>"); fprintf (fp, "<table class=\"pure-table-striped\">"); /* output agents from struct */ for (j = 0; (j < 10) && (agents[j].agents != NULL); j++) { print_html_begin_tr (fp, 0); fprintf (fp, "<td>"); clean_output (fp, agents[j].agents); fprintf (fp, "</td>"); print_html_end_tr (fp); } fprintf (fp, "</table>\n"); fprintf (fp, "</div>\n"); fprintf (fp, "</td>\n"); print_html_end_tr (fp); for (j = 0; (agents[j].agents != NULL); j++) free (agents[j].agents); free (agents); #ifdef HAVE_LIBTOKYOCABINET if (ag) free (ag); #endif } free (bandwidth); } print_html_end_tbody (fp); print_html_end_table (fp); }
static void print_html_visitors_report (FILE * fp, GHolder * h) { char *data, *bandwidth, buf[DATE_LEN]; float percent, l; int hits, i, max, process = get_ht_size (ht_unique_visitors); /* make compiler happy */ memset (buf, 0, sizeof (buf)); print_html_h2 (fp, VISIT_HEAD, VISIT_ID); print_p (fp, VISIT_DESC); print_html_begin_table (fp); print_html_begin_thead (fp); fprintf (fp, "<tr>"); fprintf (fp, "<th>Visitors</th>"); fprintf (fp, "<th>%%</th>"); fprintf (fp, "<th>Date</th>"); fprintf (fp, "<th>Bandwidth</th>"); fprintf (fp, "<th style=\"width:100%%;text-align:right;\">"); fprintf (fp, "<span class=\"r\" onclick=\"t(this)\">◀</span>"); fprintf (fp, "</th>"); fprintf (fp, "</tr>"); print_html_end_thead (fp); print_html_begin_tbody (fp); max = 0; for (i = 0; i < h->idx; i++) { if (h->items[i].hits > max) max = h->items[i].hits; } for (i = 0; i < h->idx; i++) { hits = h->items[i].hits; data = h->items[i].data; percent = get_percentage (process, hits); percent = percent < 0 ? 0 : percent; bandwidth = filesize_str (h->items[i].bw); l = get_percentage (max, hits); l = l < 1 ? 1 : l; print_html_begin_tr (fp, i > OUTPUT_N ? 1 : 0); /* hits */ fprintf (fp, "<td>%d</td>", hits); if (hits == max) fprintf (fp, "<td class=\"max\">%4.2f%%</td>", percent); else fprintf (fp, "<td>%4.2f%%</td>", percent); /* date */ convert_date (buf, data, "%Y%m%d", "%d/%b/%Y", DATE_LEN); fprintf (fp, "<td>%s</td>", buf); /* bandwidth */ fprintf (fp, "<td>"); clean_output (fp, bandwidth); fprintf (fp, "</td>"); /* bars */ fprintf (fp, "<td class=\"graph\">"); fprintf (fp, "<div class=\"bar\" style=\"width:%f%%\"></div>", l); fprintf (fp, "</td>\n"); print_html_end_tr (fp); free (bandwidth); } print_html_end_tbody (fp); print_html_end_table (fp); }