diff options
author | Sergey Poznyakoff <gray@Pirx.gnu.org.ua> | 2009-04-28 16:27:03 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@Pirx.gnu.org.ua> | 2009-04-28 16:27:03 +0300 |
commit | 20d7f1d7e051c6b021a3f5d088985a74c3370b29 (patch) | |
tree | 5c5dc1c1b401e055096b8ec216a6bd97eb76a520 | |
parent | 29e4b3da0990aca9db232dc3ce0a57722ccf1cac (diff) | |
download | tagr-20d7f1d7e051c6b021a3f5d088985a74c3370b29.tar.gz tagr-20d7f1d7e051c6b021a3f5d088985a74c3370b29.tar.bz2 |
Store timestamps. Implement zero-unknown option.
* src/graph.c (draw_graph): Use timestamps from queue entries.
Implement zero_unknown_option.
* src/output.c: Store timestamps in traffic_history entries.
* src/readconfig.c (cb_monitor, cb_server): Fix checks for
empty ID.
(tagr_kw): New keyword cut-out-fraction.
(readconfig): Reset cut_out_fraction if it is < 1.0.
* src/report.c: Print timestamps.
* src/stat.c (cut_out_fraction): New variable.
(ovf_t, overflow): Remove (spurious now) arguments.
(interpolate, overflow, update_stats): Don't interpolate if
time interval between this sample and the lastly taken one
is greater than step * cut_out_fraction.
* src/tagr.h (TAGR_CUT_OUT): New define.
-rw-r--r-- | TODO | 5 | ||||
-rw-r--r-- | src/graph.c | 46 | ||||
-rw-r--r-- | src/output.c | 3 | ||||
-rw-r--r-- | src/readconfig.c | 16 | ||||
-rw-r--r-- | src/report.c | 23 | ||||
-rw-r--r-- | src/stat.c | 64 | ||||
-rw-r--r-- | src/tagr.h | 8 |
7 files changed, 113 insertions, 52 deletions
@@ -6,15 +6,16 @@ Copyright (C) 2009 Sergey Poznyakoff S: +OK tagr ready C: SAMPLE id 1240903636 12345 3456 S: +OK accepted C: QUIT S: +OK bye -* Zero-unknown option and interrupted data feeds +* Drawing interrupted data feeds -Decide what to do if a data feed gets interrupted. +What to do if zero-inknown is set to `false'? Currently, linear +interpolation is performed. * Synchronous updates Provide an option to schedule graph updates after finishing processing of a feed. diff --git a/src/graph.c b/src/graph.c index 8088773..1197a7d 100644 --- a/src/graph.c +++ b/src/graph.c @@ -87,12 +87,13 @@ draw_graph (FILE *fp, double xscale, yscale; int dotted_style[3]; int full_xsize = graph_xsize + graph_h_margin[0] + graph_h_margin[1]; int full_ysize = graph_ysize + graph_v_margin[0] + graph_v_margin[1]; grid_t grid; unsigned long ymax = mon->max_rate; + time_t start; yscale = (double) graph_ysize / ymax; xscale = (double) graph_xsize / xmax; #define ytr(y) \ (unsigned long) ((ymax >= (y) ? (ymax - (y)) : ymax) * \ @@ -139,44 +140,71 @@ draw_graph (FILE *fp, gdImageLine (graph, 1, full_ysize - 2, full_xsize - 2, full_ysize - 2, i_dark); n = queue_count (dataq); /* Incoming traffic */ - for (i = n - 1, x = 0; i > 0 && x < xmax; i--, x += xstep) + for (i = n - 1, start = 0; i > 0; i--) { struct traffic_history th, tnext; scale_sample (mon, queue_get_ptr (dataq, i), &th); + if (start == 0) + start = th.time; scale_sample (mon, queue_get_ptr (dataq, i - 1), &tnext); + if (start - tnext.time > xmax) + break; + if (zero_unknown_option + && th.time - tnext.time > xstep * cut_out_fraction) + { + gdImageLine (graph, xtr (start - tnext.time), ytr (0), + xtr (start - tnext.time), ytr (tnext.inrate), i_in); + th.inrate = tnext.inrate = 0; + th.outrate = tnext.outrate = 0; + } + if (fill_incoming_option) gdImageLine (graph, - xtr (x), ytr (0), - xtr (x), ytr (tnext.inrate), i_in); - gdImageLine (graph, xtr (x), ytr (th.inrate), - xtr (x + xstep), ytr (tnext.inrate), i_in); + xtr (start - th.time), ytr (0), + xtr (start - th.time), ytr (tnext.inrate), i_in); + gdImageLine (graph, xtr (start - th.time), ytr (th.inrate), + xtr (start - tnext.time), ytr (tnext.inrate), i_in); } /* Outgoing traffic */ gdImageSetBrush (graph, brush_out); - for (i = n - 1, x = 0; i > 0 && x < xmax; i--, x += xstep) + for (i = n - 1, start = 0; i > 0; i--) { struct traffic_history th, tnext; scale_sample (mon, queue_get_ptr (dataq, i), &th); + if (start == 0) + start = th.time; scale_sample (mon, queue_get_ptr (dataq, i - 1), &tnext); + if (start - tnext.time > xmax) + break; - gdImageLine (graph, xtr (x), ytr (th.outrate), - xtr (x + xstep), ytr (tnext.outrate), gdBrushed); + if (zero_unknown_option + && th.time - tnext.time > xstep * cut_out_fraction) + { + gdImageLine (graph, xtr (start - tnext.time), ytr (0), + xtr (start - tnext.time), ytr (tnext.inrate), + gdBrushed); + th.inrate = tnext.inrate = 0; + th.outrate = tnext.outrate = 0; + } + + gdImageLine (graph, xtr (start - th.time), ytr (th.outrate), + xtr (start - tnext.time), ytr (tnext.outrate), gdBrushed); } /* Border */ gdImageRectangle (graph, xtr (0), ytr (0), xtr (xmax), ytr (ymax), i_grid); - + dotted_style[0] = i_grid; dotted_style[1] = gdTransparent; dotted_style[2] = gdTransparent; gdImageSetStyle (graph, dotted_style, 3); diff --git a/src/output.c b/src/output.c index e376ad4..4b6e206 100644 --- a/src/output.c +++ b/src/output.c @@ -38,12 +38,13 @@ scale_sample (struct monitor *mon, } else { out->inrate = in->inrate; out->outrate = in->outrate; } + out->time = in->time; out->inrate *= mon->scale; out->outrate *= mon->scale; } int create_hierarchy (char *dir, int perm) @@ -227,13 +228,13 @@ format_timestamp (FILE *fp, union value v, const char *fmt, int prec) time_t t = v.number; struct tm *tm = localtime (&t); if (!fmt) fmt = "%c"; - fprintftime(fp, fmt, tm, 0, 0); + fprintftime (fp, fmt, tm, 0, 0); } int update_output (struct monitor *mon, struct traffic_record *tr, time_t timestamp, int force_update) { diff --git a/src/readconfig.c b/src/readconfig.c index 9eff4c7..e75cae4 100644 --- a/src/readconfig.c +++ b/src/readconfig.c @@ -86,16 +86,18 @@ cb_monitor (enum grecs_callback_command cmd, struct monitor *mon; void **pdata = cb_data; switch (cmd) { case grecs_callback_section_begin: - if (!value || value->type != GCONF_TYPE_STRING) + if (!value + || value->type != GCONF_TYPE_STRING + || value->v.string == NULL) { grecs_error (locus, 0, _("tag must be a string")); - return 0; + return 1; } mon = xzalloc (sizeof (*mon)); mon->id = strdup (value->v.string); mon->scale = 1.0; mon->ystep = 100; *pdata = mon; @@ -396,16 +398,17 @@ cb_server (enum grecs_callback_command cmd, struct cfg_server *cfg; void **pdata = cb_data; switch (cmd) { case grecs_callback_section_begin: - if (!value || value->type != GCONF_TYPE_STRING) + if (!value || value->type != GCONF_TYPE_STRING + || !value->v.string) { grecs_error (locus, 0, _("tag must be a string")); - return 0; + return 1; } cfg = xzalloc (sizeof (*cfg)); cfg->id = value->v.string; *pdata = cfg; break; @@ -479,12 +482,15 @@ static struct grecs_keyword tagr_kw[] = { { "percent", NULL, N_("Draw in/out percent graph (not implemented)"), /* FIXME */ grecs_type_bool, &percent_option }, { "zero-unknown", NULL, N_("Zero-out missing samples (not implemented)") /* FIXME */, grecs_type_bool, &zero_unknown_option }, + { "cut-out-fraction", N_("arg: double"), NULL, /* FIXME */ + grecs_type_string, &cut_out_fraction, 0, + cb_double }, { "fill-incoming", NULL, N_("Fill incoming graph"), grecs_type_bool, &fill_incoming_option }, { "color-background", NULL, N_("Set background color"), grecs_type_int, color_background, 0, cb_color }, { "color-light", NULL, N_("`Light' color (for the border)"), @@ -544,12 +550,14 @@ readconfig () } if (preprocess_only) exit (grecs_preproc_run (configfile, grecs_preprocessor) ? EX_CONFIG : 0); rc = grecs_parse (configfile); if (rc == 0) mon_base = obstack_finish (&mon_stack); + if (cut_out_fraction < 1.0) + cut_out_fraction = TAGR_CUT_OUT; return rc; } void define_symbol (char *p) { diff --git a/src/report.c b/src/report.c index 398881b..71a735f 100644 --- a/src/report.c +++ b/src/report.c @@ -27,12 +27,13 @@ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <tagr.h> #include <report.h> +#include <fprintftime.h> #include <gdbm.h> static char *dbname; static GDBM_FILE dbf; static void @@ -141,24 +142,34 @@ write_db (struct monitor *mon, struct traffic_record *tr) logmsg (L_ERR, _("failed to write data for %s: %s"), mon->id, gdbm_strerror (gdbm_errno)); } } static void +print_time (FILE *fp, time_t time) +{ + fprintf (fp, "%lu [", (unsigned long) time); + fprintftime (fp, "%Y-%m-%d %H:%M:%S %z", localtime (&time), 0, 0); + fprintf (fp, "]"); +} + +static void print_queue (const char *title, queue_t *q) { int i, count; count = queue_count (q); printf (ngettext ("%s (%d entry):\n", "%s (%d entries):\n", count), title, count); for (i = count - 1; i >= 0; i--) { struct traffic_history *th = queue_get_ptr (q, i); - printf("%d %g %g\n", count - i, th->inrate, th->outrate); + printf ("%d ", count - i); + print_time (stdout, th->time); + printf (" %g %g\n", th->inrate, th->outrate); } } static void print_avg (const char *title, struct avg_acc *avg) { @@ -169,21 +180,19 @@ print_avg (const char *title, struct avg_acc *avg) title, avg->time, buf, avg->count, avg->inrate, avg->outrate); } static void print_tr (datum key, struct traffic_record *tr) { - char buf[512]; - struct tm *tm; int i, count; - tm = localtime (&tr->last.time); printf ("ID: %*.*s\n", key.dsize, key.dsize, key.dptr); - strftime (buf, sizeof buf, "%c", tm); - printf (_("Last sample: %lu (%s) %lu %lu\n"), - tr->last.time, buf, tr->last.in, tr->last.out); + + printf (_("Last sample: ")); + print_time (stdout, tr->last.time); + printf (" %lu %lu\n", tr->last.in, tr->last.out); printf (_("Last rates: %g %g\n"), tr->last_rates.inrate, tr->last_rates.outrate); print_queue (_("Daily rates"), &tr->day_hist); print_avg (_("Weekly average"), &tr->week_avg); @@ -24,14 +24,15 @@ #include <glob.h> #define obstack_chunk_alloc malloc #define obstack_chunk_free free #include <obstack.h> #include <tagr.h> -typedef int (*ovf_t) (struct traffic_history *th, struct traffic_record *tr, - time_t now); +double cut_out_fraction = TAGR_CUT_OUT; + +typedef int (*ovf_t) (struct traffic_history *th, struct traffic_record *tr); void interpolate (queue_t *q, time_t step, time_t now, time_t last_time, struct traffic_history *last_rates, time_t interval, double inrate, double outrate, @@ -40,101 +41,104 @@ interpolate (queue_t *q, { time_t next; struct traffic_history th; if (now - last_time <= step) { + th.time = now; th.inrate = inrate; th.outrate = outrate; verbose (3, _("insert %lu %g %g"), next, th.inrate, th.outrate); queue_put (q, &th); if (ovf) - ovf (&th, tr, now); + ovf (&th, tr); return; } for (next = last_time + step; next <= now; next += step) { + th.time = next; th.inrate = (inrate - last_rates->inrate) * (next - last_time) / interval + last_rates->inrate; th.outrate = (outrate - last_rates->outrate) * (next - last_time) / interval + last_rates->outrate; verbose (3, _("insert %lu %g %g"), next, th.inrate, th.outrate); queue_put (q, &th); if (ovf) - ovf (&th, tr, now); + ovf (&th, tr); } } int overflow (struct traffic_history *th, struct traffic_record *tr, - time_t now, ovf_t ovf, struct avg_acc *avg, queue_t *q, - int maxcount, int step) { - if (now - avg->time >= step) + time_t interval = th->time - avg->time; + if (interval >= step) { struct traffic_history *lastp = queue_get_tail (q); - if (lastp) + if (lastp && interval < step * cut_out_fraction) interpolate (q, step, - now, + th->time, avg->time, lastp, - now - avg->time, + interval, avg->inrate, avg->outrate, ovf, tr); else { struct traffic_history tmp; + tmp.time = avg->time; tmp.inrate = avg->inrate; tmp.outrate = avg->outrate; - verbose (3, _("insert %lu %g %g"), now, tmp.inrate, tmp.outrate); + verbose (3, _("insert %lu %g %g"), + tmp.time, tmp.inrate, tmp.outrate); queue_put (q, &tmp); } avg->inrate = avg->outrate = 0; avg->count = 0; - avg->time = now; + avg->time = th->time; } avg->inrate = (avg->count * avg->inrate + th->inrate) / (avg->count + 1); avg->outrate = (avg->count * avg->outrate + th->outrate) / (avg->count + 1); avg->count++; } int -ovf_monthly (struct traffic_history *th, struct traffic_record *tr, time_t now) +ovf_monthly (struct traffic_history *th, struct traffic_record *tr) { verbose (2, _("begin overflow_monthly %lu %g %g"), - now, th->inrate, th->outrate); - overflow (th, tr, now, NULL, &tr->year_avg, &tr->year_hist, - YEAR_COUNT, YEAR_SAMPLE); + th->time, th->inrate, th->outrate); + overflow (th, tr, NULL, &tr->year_avg, &tr->year_hist, + YEAR_SAMPLE); verbose (2, _("end overflow_monthly")); } int -ovf_weekly (struct traffic_history *th, struct traffic_record *tr, time_t now) +ovf_weekly (struct traffic_history *th, struct traffic_record *tr) { verbose (2, _("begin overflow_weekly %lu %g %g"), - now, th->inrate, th->outrate); - overflow (th, tr, now, ovf_monthly, &tr->month_avg, &tr->month_hist, - MONTH_COUNT, MONTH_SAMPLE); + th->time, th->inrate, th->outrate); + overflow (th, tr, ovf_monthly, &tr->month_avg, &tr->month_hist, + MONTH_SAMPLE); verbose (2, _("end overflow_daily")); } int -ovf_daily (struct traffic_history *th, struct traffic_record *tr, time_t now) +ovf_daily (struct traffic_history *th, struct traffic_record *tr) { verbose (2, _("begin overflow_daily %lu %g %g"), - now, th->inrate, th->outrate); - overflow (th, tr, now, ovf_weekly, &tr->week_avg, &tr->week_hist, - WEEK_COUNT, WEEK_SAMPLE); + th->time, th->inrate, th->outrate); + overflow (th, tr, ovf_weekly, &tr->week_avg, &tr->week_hist, + WEEK_SAMPLE); verbose (2, _("end overflow_daily")); } void update_stats (struct monitor *mon, struct traffic_sample *sample, struct traffic_record *tr) @@ -147,15 +151,21 @@ update_stats (struct monitor *mon, struct traffic_sample *sample, interval = sample->time - tr->last.time; if (interval == 0) { logmsg (L_ERR, _("ignoring zero interval")); return; } + else if (interval < 0) + { + logmsg (L_ERR, _("ignoring negative interval")); + return; + } + inrate = (double) sample->in / interval; outrate = (double) sample->out / interval; - if (lastp) + if (lastp && interval < DAY_SAMPLE * cut_out_fraction) { interpolate (&tr->day_hist, DAY_SAMPLE, sample->time, tr->last.time, &tr->last_rates, @@ -164,19 +174,21 @@ update_stats (struct monitor *mon, struct traffic_sample *sample, ovf_daily, tr); } else { struct traffic_history th; interval = sample->time - tr->last.time; + th.time = sample->time; th.inrate = inrate; th.outrate = outrate; queue_put (&tr->day_hist, &th); } tr->last.time = sample->time; tr->last.in = sample->in; tr->last.out = sample->out; + tr->last_rates.time = sample->time; tr->last_rates.inrate = inrate; tr->last_rates.outrate = outrate; } @@ -235,20 +247,22 @@ _convert (queue_t *q, ovf_t ovf, ovf, tr); } else { struct traffic_history th; interval = hp->time - tr->last.time; + th.time = hp->time; th.inrate = inrate; th.outrate = outrate; queue_put (q, &th); } tr->last.time = hp->time; tr->last.in = hp->in; tr->last.out = hp->out; + tr->last_rates.time = hp->time; tr->last_rates.inrate = inrate; tr->last_rates.outrate = outrate; } } static void @@ -22,12 +22,13 @@ #define TAGR_CONFIGFILE SYSCONFDIR "/tagr.conf" #define TAGR_TEMPLATE SYSCONFDIR "/tagr.tmpl" #define TAGR_PIDFILE "/var/run/tagr.pid" #define TAGR_DBNAME "tagr.db" #define TAGR_DBMODE 0600 +#define TAGR_CUT_OUT 1.5 #define _(s) gettext (s) #define N_(s) s #define gettext(s) s #define ngettext(s,p,c) ((c) == 1 ? (s) : (p)) @@ -45,12 +46,13 @@ struct monitor extern int preprocess_only; extern int log_to_stderr; extern char *pidfile; extern unsigned update_interval; extern int single_process_option; +extern double cut_out_fraction; extern char *user; extern char *basedir; extern char *configfile; extern int foreground; extern char *html_template; @@ -73,19 +75,16 @@ extern int color_grid[3]; extern int color_in_max[3]; extern int color_out_max[3]; extern int color_percent[3]; extern char **number_suffix; extern size_t number_suffix_count; -void assign_string (char **pstr, const char *s); -void assign_string_n (char **pstr, const char *s, size_t length); - int readconfig (void); void config_help (void); void define_symbol (char *s); -void decode_buffer (); + struct monitor *find_monitor (const char *name); struct monitor *find_monitor_id (const char *id); /* html.gram.y */ void begin_eval (); void end_eval (); @@ -163,12 +162,13 @@ void verbose (int level, const char *fmt, ...); /* One 'rounding error' per sample period, so add 4 to total */ #define MAX_HISTORY (DAY_COUNT+WEEK_COUNT+MONTH_COUNT+YEAR_COUNT+4+4) struct traffic_history { + time_t time; double inrate; double outrate; }; typedef struct stat_queue queue_t; struct stat_queue |