aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@Pirx.gnu.org.ua>2009-04-28 16:27:03 +0300
committerSergey Poznyakoff <gray@Pirx.gnu.org.ua>2009-04-28 16:27:03 +0300
commit20d7f1d7e051c6b021a3f5d088985a74c3370b29 (patch)
tree5c5dc1c1b401e055096b8ec216a6bd97eb76a520
parent29e4b3da0990aca9db232dc3ce0a57722ccf1cac (diff)
downloadtagr-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--TODO5
-rw-r--r--src/graph.c46
-rw-r--r--src/output.c3
-rw-r--r--src/readconfig.c16
-rw-r--r--src/report.c23
-rw-r--r--src/stat.c64
-rw-r--r--src/tagr.h8
7 files changed, 113 insertions, 52 deletions
diff --git a/TODO b/TODO
index 9a8e27f..b2edd7c 100644
--- a/TODO
+++ b/TODO
@@ -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);
diff --git a/src/stat.c b/src/stat.c
index 813c5cb..434d19e 100644
--- a/src/stat.c
+++ b/src/stat.c
@@ -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
diff --git a/src/tagr.h b/src/tagr.h
index 1d8aac1..f95a249 100644
--- a/src/tagr.h
+++ b/src/tagr.h
@@ -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

Return to:

Send suggestions and report system problems to the System administrator.