Permalink
Browse files

Merge pull request #56 from hirose31/feature/virtical-line

[WIP] Support a virtical line
  • Loading branch information...
2 parents b31839c + 7987706 commit 348e4b9e3645dc75410c16b563abd9699b0a49e6 @kazeburo committed Mar 5, 2014
Showing with 234 additions and 1 deletion.
  1. +82 −0 lib/GrowthForecast/Data.pm
  2. +13 −0 lib/GrowthForecast/Data/MySQL.pm
  3. +8 −0 lib/GrowthForecast/RRD.pm
  4. +131 −1 lib/GrowthForecast/Web.pm
View
82 lib/GrowthForecast/Data.pm
@@ -108,6 +108,20 @@ CREATE TABLE IF NOT EXISTS complex_graphs (
UNIQUE (service_name, section_name, graph_name)
)
EOF
+
+ $dbh->do(<<EOF);
+CREATE TABLE IF NOT EXISTS vrules (
+ id INTEGER NOT NULL PRIMARY KEY,
+ graph_path VARCHAR(255) NOT NULL,
+ time INT UNSIGNED NOT NULL,
+ color VARCHAR(255) NOT NULL DEFAULT '#FF0000',
+ description TEXT
+)
+EOF
+ $dbh->do(<<EOF);
+CREATE INDEX IF NOT EXISTS time_graph_path on vrules (time, graph_path)
+EOF
+
return;
};
}
@@ -526,5 +540,73 @@ sub get_all_complex_graph_all {
\@ret;
}
+sub update_vrule {
+ my ($self, $graph_path, $time, $color, $desc) = @_;
+
+ $self->dbh->query(
+ 'INSERT INTO vrules (graph_path,time,color,description) values (?,?,?,?)',
+ $graph_path, $time, $color, $desc
+ );
+
+ my $row = $self->dbh->select_row(
+ 'SELECT * FROM vrules WHERE graph_path = ? AND time = ? AND color = ? AND description = ?',
+ $graph_path, $time, $color, $desc,
+ );
+
+ return $row;
+}
+
+# "$span" is a parameter named "t",
+# "$from" and "$to" are paramters same nameed.
+sub get_vrule {
+ my ($self, $span, $from, $to, $graph_path) = @_;
+
+ my($from_time, $to_time) = (0, time);
+ # same rule as GrowthForecast::RRD#calc_period
+ if ( $span eq 'all' ) {
+ $from_time = 0;
+ $to_time = 4294967295; # unsigned int max
+ } elsif ( $span eq 'c' || $span eq 'sc' ) {
+ my $from_time = HTTP::Date::str2time($from);
+ die "invalid from date: $from" unless $from_time;
+ my $to_time = $to ? HTTP::Date::str2time($to) : time;
+ die "invalid to date: $to" unless $to_time;
+ die "from($from) is newer than to($to)" if $from_time > $to_time;
+ } elsif ( $span eq 'h' || $span eq 'sh' ) {
+ $from_time = time -1 * 60 * 60 * 2;
+ } elsif ( $span eq 'n' || $span eq 'sn' ) {
+ $from_time = time -1 * 60 * 60 * 14;
+ } elsif ( $span eq 'w' ) {
+ $from_time = time -1 * 60 * 60 * 24 * 8;
+ } elsif ( $span eq 'm' ) {
+ $from_time = time -1 * 60 * 60 * 24 * 35;
+ } elsif ( $span eq 'y' ) {
+ $from_time = time -1 * 60 * 60 * 24 * 400;
+ } elsif ( $span eq '3d' ) {
+ $from_time = time -1 * 60 * 60 * 24 * 3;
+ } elsif ( $span eq '8h' ) {
+ $from_time = time -1 * 8 * 60 * 60;
+ } elsif ( $span eq '4h' ) {
+ $from_time = time -1 * 4 * 60 * 60;
+ } else {
+ $from_time = time -1 * 60 * 60 * 33; # 33 hours
+ }
+
+ my @vrules = ();
+
+ my @gp = split '/', substr($graph_path, 1);
+
+ my $rows = $self->dbh->select_all(
+ 'SELECT * FROM vrules WHERE (time BETWEEN ? and ?) AND graph_path in ("/",?,?,?)',
+ $from_time, $to_time,
+ "/$gp[0]",
+ "/$gp[0]/$gp[1]",
+ "/$gp[0]/$gp[1]/$gp[2]",
+ );
+ push @vrules, @$rows;
+
+ return @vrules;
+}
+
1;
View
13 lib/GrowthForecast/Data/MySQL.pm
@@ -95,6 +95,19 @@ CREATE TABLE IF NOT EXISTS complex_graphs (
UNIQUE (service_name, section_name, graph_name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
EOF
+
+ $dbh->do(<<EOF);
+CREATE TABLE IF NOT EXISTS vrules (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ graph_path VARCHAR(255) NOT NULL COLLATE utf8_bin,
+ time INT UNSIGNED NOT NULL,
+ color VARCHAR(255) NOT NULL DEFAULT '#FF0000',
+ description TEXT,
+ PRIMARY KEY (id),
+ INDEX time_graph_path (time, graph_path)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8
+EOF
+
return;
};
}
View
8 lib/GrowthForecast/RRD.pm
@@ -366,6 +366,14 @@ sub graph {
sprintf('PRINT:sumupmin:%%.8lf');
}
+ for my $vrule ($self->{data}->get_vrule($span, $period, $end, '/'.join('/',@{$datas}{qw(service_name section_name graph_name)}))) {
+ push @opt, join(":",
+ 'VRULE',
+ join("", $vrule->{time}, $vrule->{color}),
+ ($args->{vrule_legend} ? ($vrule->{description}||()) : ()),
+ );
+ }
+
my @graphv;
eval {
@graphv = RRDs::graph(map { Encode::encode_utf8($_) } @opt);
View
132 lib/GrowthForecast/Web.pm
@@ -33,6 +33,7 @@ sub rrd {
root_dir => $self->root_dir,
rrdcached => $self->rrdcached,
disable_subtract => $self->disable_subtract,
+ data => $self->data,
);
$self->{__rrd};
}
@@ -582,6 +583,12 @@ sub graph_validator {
[['CHOICE', qw/AVERAGE MAX/], 'invalid consolidation function'],
],
},
+ 'vrule_legend' => {
+ default => 1,
+ rule => [
+ [['CHOICE',qw/0 1/],'invalid vrule_legend flag'],
+ ],
+ },
];
}
@@ -675,7 +682,8 @@ get '/{method:(?:xport|graph|summary)}/:service_name/:section_name/:graph_name'
if ( $c->args->{method} eq 'graph' ) {
my ($img,$data) = $self->rrd->graph(
- $c->stash->{graph}, $result->valid->as_hashref
+ $c->stash->{graph}, $result->valid->as_hashref,
+ $self->data,
);
$c->res->content_type('image/png');
$c->res->body($img);
@@ -1155,5 +1163,127 @@ post '/json/edit/{type:(?:graph|complex)}/:id' => sub {
$c->render_json({ error => 0 });
};
+post '/vrule/api/:service_name/:section_name/:graph_name' => sub {
+ my ( $self, $c ) = @_; $self->add_vrule($c);
+};
+post '/vrule/api/:service_name/:section_name' => sub {
+ my ( $self, $c ) = @_; $self->add_vrule($c);
+};
+post '/vrule/api/:service_name' => sub {
+ my ( $self, $c ) = @_; $self->add_vrule($c);
+};
+post '/vrule/api' => sub {
+ my ( $self, $c ) = @_; $self->add_vrule($c);
+};
+
+sub add_vrule {
+ my ( $self, $c ) = @_;
+ my $result = $c->req->validator([
+ 'time' => {
+ default => time(),
+ rule => [
+ ['INT', 'a INT number is required for "time"']
+ ],
+ },
+ 'color' => {
+ default => '#FF0000',
+ rule => [
+ [sub{ length($_[1]) == 0 || $_[1] =~ m!^#[0-9A-F]{6}$!i }, 'invalid color format'],
+ ],
+ },
+ 'description' => {
+ default => '',
+ rule => [],
+ },
+ ]);
+
+ if ( $result->has_error ) {
+ my $res = $c->render_json({
+ error => 1,
+ messages => $result->messages
+ });
+ $res->status(400);
+ return $res;
+ }
+
+ my $row;
+ eval {
+ my $graph_path = '/'.join('/', $c->args->{service_name}||(), $c->args->{section_name}||(), $c->args->{graph_name}||());
+ $row = $self->data->update_vrule(
+ $graph_path,
+ $result->valid('time'),
+ $result->valid('color'),
+ $result->valid('description'),
+ );
+ };
+ if ( $@ ) {
+ die sprintf "Error:%s %s/%s/%s => %s,%s",
+ $@, $c->args->{service_name}, $c->args->{section_name}, $c->args->{graph_name},
+ $result->valid('time'), $result->valid('color');
+ }
+
+ $c->render_json({error=>0, data => $row});
+};
+
+get '/vrule/summary/:service_name/:section_name/:graph_name' => sub {
+ my ( $self, $c ) = @_; $self->summarize_vrule($c);
+};
+get '/vrule/summary/:service_name/:section_name' => sub {
+ my ( $self, $c ) = @_; $self->summarize_vrule($c);
+};
+get '/vrule/summary/:service_name' => sub {
+ my ( $self, $c ) = @_; $self->summarize_vrule($c);
+};
+get '/vrule/summary' => sub {
+ my ( $self, $c ) = @_; $self->summarize_vrule($c);
+};
+
+sub summarize_vrule {
+ my ( $self, $c ) = @_;
+ my $result = $c->req->validator([
+ 't' => {
+ default => 'all',
+ rule => [
+ [['CHOICE',qw/all y m w 3d s3d d sd 8h s8h 4h s4h h sh n sn c sc/],'invalid drawing term'],
+ ],
+ },
+ 'from' => {
+ default => localtime(time-86400*8)->strftime('%Y/%m/%d %T'),
+ rule => [
+ [sub{ HTTP::Date::str2time($_[1]) }, 'invalid From datetime'],
+ ],
+ },
+ 'to' => {
+ default => localtime()->strftime('%Y/%m/%d %T'),
+ rule => [
+ [sub{ HTTP::Date::str2time($_[1]) }, 'invalid To datetime'],
+ ],
+ },
+ ]);
+
+ if ( $result->has_error ) {
+ my $res = $c->render_json({
+ error => 1,
+ messages => $result->messages
+ });
+ $res->status(400);
+ return $res;
+ }
+
+ my $graph_path = '/'.join('/', $c->args->{service_name}||(), $c->args->{section_name}||(), $c->args->{graph_name}||());
+
+ my @vrules;
+ eval {
+ @vrules = $self->data->get_vrule($result->valid('t'), $result->valid('from'), $result->valid('to'), $graph_path);
+ };
+ if ( $@ ) {
+ die sprintf "Error:%s %s/%s/%s => %s,%s,%s",
+ $@, $c->args->{service_name}, $c->args->{section_name}, $c->args->{graph_name},
+ $result->valid('t'), $result->valid('from') , $result->valid('to');
+ }
+
+ $c->render_json(\@vrules);
+};
+
1;

0 comments on commit 348e4b9

Please sign in to comment.