File Coverage

blib/lib/Net/Async/Graphite/Draw.pm
Criterion Covered Total %
statement 29 67 43.2
branch 0 10 0.0
condition 0 13 0.0
subroutine 10 17 58.8
pod 2 2 100.0
total 41 109 37.6


line stmt bran cond sub pod time code
1             package Net::Async::Graphite::Draw;
2              
3             our $VERSION = '0.1_1';
4              
5             =encoding utf8
6              
7             =head1 NAME
8              
9             Net::Async::Graphite::Draw - Interpret data obtained from graphite.
10              
11             =head1 SYNOPSIS
12              
13             with 'Net::Async::Graphite::Draw';
14              
15             =head1 DESCRIPTION
16              
17             Don't use this module directly, use L and create
18             objects using its C method in the normal way. Those objects will
19             include the functionality documented here.
20              
21             This role brings the capacity to interpret and encode the data
22             obtained from graphite in various ways. Currently those various ways
23             are gnuplot, and probably using a blocking module at that (although
24             it's pretty fast).
25              
26             =head1 BUGS
27              
28             Gnuplut may be called synchronously.
29              
30             plot() is ridiculously naïve. Format and scale in particular need to
31             be dealt with, and the timestamps and step returned by graphite.
32              
33             =cut
34              
35 3     3   1575 use v5.14;
  3         11  
36 3     3   15 use strictures 2;
  3         22  
  3         107  
37 3     3   613 use Moo::Role;
  3         7  
  3         20  
38 3     3   1035 use Carp;
  3         6  
  3         169  
39              
40 3     3   1325 use Gnuplot::Builder::Dataset;
  3         13751  
  3         71  
41 3     3   1383 use Gnuplot::Builder::Script;
  3         21099  
  3         88  
42 3     3   27 use Future;
  3         8  
  3         65  
43 3     3   17 use List::Util qw(min max);
  3         5  
  3         198  
44 3     3   17 use Scalar::Util qw(looks_like_number);
  3         6  
  3         102  
45 3     3   17 use namespace::clean;
  3         6  
  3         26  
46              
47             =head1 ROLE
48              
49             =head1 METHODS
50              
51             =over
52              
53             =item last_value ($target, [%extra])
54              
55             Calls C with the same arguments but prepended by the format
56             C, and returns (a L which completes to) a list of the final
57             datum on each line in the response.
58              
59             =cut
60              
61             sub last_value {
62 0     0 1   my $self = shift;
63             $self->render(raw => @_)->then(sub {
64 0 0   0     my $response = shift or return Future->fail('no data');
65             Future->done(map {
66 0           my $result = (split /\|/)[-1];
  0            
67             # Blessed object which scalar's into this but has attributes for other data?
68 0           (split /,/, $result)[-1];
69             } split /\r?\n/, $response);
70 0           });
71             }
72              
73             =item plot ($target, [%extra])
74              
75             Return a (L which completes to) a scalar containing the result
76             of running a plot inside a child gnuplot process.
77              
78             Mostly this exists for fun so that I can get data displayed on the
79             terminal.
80              
81             =cut
82              
83             my %plots = (
84             ascii => {
85             terminal => 'dumb',
86             # Use a proper module instead of tput.
87             default_size => sub { [ map int, `tput cols`, `tput lines` ] },
88             },
89             png => {
90             terminal => 'png',
91             default_size => [ 640, 480 ],
92             }
93             );
94              
95             sub plot {
96 0     0 1   my $self = shift;
97 0           my (undef, %extra) = @_;
98 0   0       my $format = delete $extra{format} || 'ascii'; # To not confuse render()
99             return Future->fail("Invalid plot format: $format")
100 0 0         unless exists $plots{$format};
101             $self->_plot_gather_datasets(@_)->then(sub {
102 0   0 0     my @req_size = ( $extra{width} || 0, $extra{height} || 0 );
      0        
103 0           my @default_size = @{ $self->_default_plot_size($format) };
  0            
104             my @real_size = map {
105 0 0 0       $req_size[$_] < 0
  0            
106             ? $default_size[$_] + $req_size[$_]
107             : $req_size[$_] || $default_size[$_]
108             } 0..1;
109 0           my @sets = @_;
110 0   0       my $min = min (map { $_->{min} } @sets) || 0;
111 0   0       my $max = max (map { $_->{max} } @sets) || 1; # Nonsensical but better than die (maybe)
112             my $plot = Gnuplot::Builder::Script->new(
113             terminal => "$plots{$format}{terminal} size $real_size[0],$real_size[1] enhanced",
114             yrange => "[$min:$max]",
115 0           )->plot_with(dataset => [ map { $_->{dataset} } @_ ],
  0            
116             no_stderr => 1); # Would be nice to put it somewhere
117             # but it's all or nothing.
118 0           Future->done($plot);
119 0           });
120             }
121              
122             =item _plot_gather_datasets
123              
124             I can't remember.
125              
126             =cut
127              
128             sub _plot_gather_datasets {
129 0     0     my $self = shift;
130             $self->render_asperl(@_)->then(sub {
131             Future->done(map {
132 0     0     my ($min, $max) = (0,0);
  0            
133             my $dataset = Gnuplot::Builder::Dataset->new_data(join "\n",
134             map {
135 0 0         my $datum = looks_like_number $_ ? $_ : 0;
136 0           $min = min($min, $datum);
137 0           $max = max($max, $datum);
138 0           $datum;
139 0           } @{ $_->{data} });
  0            
140 0           $dataset->set(title => "\"$_->{target}\"");
141 0           +{ %$_, min => $min, max => $max, dataset => $dataset };
142             } @_);
143 0           });
144             }
145              
146             =item _default_plot_size
147              
148             I can't remember.
149              
150             =cut
151              
152             sub _default_plot_size {
153 0     0     my $self = shift;
154 0           my ($format) = @_;
155 0           my $default = $plots{$format}{default_size};
156 0 0         ref $default eq 'ARRAY' ? $default : $default->($self);
157             }
158              
159             1;
160              
161             =back
162              
163             =head1 SEE ALSO
164              
165             Gnuplot L
166              
167             L
168              
169             L
170              
171             L
172              
173             L
174              
175             =head1 AUTHOR
176              
177             Matthew King
178              
179             =cut