Filename | /opt/flows/lib/lib/perl5/InfluxDB/LineProtocol.pm |
Statements | Executed 25 statements in 2.21ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 692µs | 1.15ms | BEGIN@10 | InfluxDB::LineProtocol::
1 | 1 | 1 | 20µs | 20µs | import | InfluxDB::LineProtocol::
1 | 1 | 1 | 15µs | 30µs | BEGIN@2 | InfluxDB::LineProtocol::
1 | 1 | 1 | 9µs | 14µs | BEGIN@3 | InfluxDB::LineProtocol::
1 | 1 | 1 | 8µs | 54µs | BEGIN@9 | InfluxDB::LineProtocol::
1 | 1 | 1 | 8µs | 21µs | BEGIN@37 | InfluxDB::LineProtocol::
1 | 1 | 1 | 1µs | 1µs | CORE:match (opcode) | InfluxDB::LineProtocol::
0 | 0 | 0 | 0s | 0s | _data2line_0_9_2 | InfluxDB::LineProtocol::
0 | 0 | 0 | 0s | 0s | _format_key | InfluxDB::LineProtocol::
0 | 0 | 0 | 0s | 0s | _format_value | InfluxDB::LineProtocol::
0 | 0 | 0 | 0s | 0s | _line2data_0_9_2 | InfluxDB::LineProtocol::
0 | 0 | 0 | 0s | 0s | data2line | InfluxDB::LineProtocol::
0 | 0 | 0 | 0s | 0s | line2data | InfluxDB::LineProtocol::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package InfluxDB::LineProtocol; | ||||
2 | 2 | 34µs | 2 | 44µs | # spent 30µs (15+15) within InfluxDB::LineProtocol::BEGIN@2 which was called:
# once (15µs+15µs) by main::BEGIN@207 at line 2 # spent 30µs making 1 call to InfluxDB::LineProtocol::BEGIN@2
# spent 15µs making 1 call to strict::import |
3 | 2 | 46µs | 2 | 19µs | # spent 14µs (9+5) within InfluxDB::LineProtocol::BEGIN@3 which was called:
# once (9µs+5µs) by main::BEGIN@207 at line 3 # spent 14µs making 1 call to InfluxDB::LineProtocol::BEGIN@3
# spent 5µs making 1 call to warnings::import |
4 | |||||
5 | 1 | 700ns | our $VERSION = '1.007'; | ||
6 | |||||
7 | # ABSTRACT: Write and read InfluxDB LineProtocol | ||||
8 | |||||
9 | 2 | 33µs | 2 | 100µs | # spent 54µs (8+46) within InfluxDB::LineProtocol::BEGIN@9 which was called:
# once (8µs+46µs) by main::BEGIN@207 at line 9 # spent 54µs making 1 call to InfluxDB::LineProtocol::BEGIN@9
# spent 46µs making 1 call to Exporter::import |
10 | 2 | 250µs | 2 | 1.33ms | # spent 1.15ms (692µs+454µs) within InfluxDB::LineProtocol::BEGIN@10 which was called:
# once (692µs+454µs) by main::BEGIN@207 at line 10 # spent 1.15ms making 1 call to InfluxDB::LineProtocol::BEGIN@10
# spent 179µs making 1 call to Time::HiRes::import |
11 | |||||
12 | 1 | 2µs | my %versions = ( | ||
13 | 'v0.9.2' => '_0_9_2', | ||||
14 | ); | ||||
15 | |||||
16 | # spent 20µs (20+1) within InfluxDB::LineProtocol::import which was called:
# once (20µs+1µs) by main::BEGIN@207 at line 207 of flows_to_es.pl | ||||
17 | 1 | 600ns | my $class = shift; | ||
18 | 1 | 700ns | my $caller = caller(); | ||
19 | |||||
20 | |||||
21 | 1 | 100ns | my @to_export; | ||
22 | 1 | 100ns | my $version; | ||
23 | 1 | 1µs | foreach my $param (@_) { | ||
24 | 1 | 1µs | if ($param eq 'data2line' || $param eq 'line2data') { | ||
25 | push(@to_export,$param); | ||||
26 | } | ||||
27 | 1 | 9µs | 1 | 1µs | if ($param =~ /^v[\d\.]+$/ && $versions{$param}) { # spent 1µs making 1 call to InfluxDB::LineProtocol::CORE:match |
28 | $version = $versions{$param}; | ||||
29 | } | ||||
30 | } | ||||
31 | |||||
32 | 1 | 4µs | foreach my $function (@to_export) { | ||
33 | 1 | 300ns | my $target = $function; | ||
34 | 1 | 100ns | $function = '_'.$function.$version if $version; | ||
35 | |||||
36 | { | ||||
37 | 3 | 1.82ms | 2 | 34µs | # spent 21µs (8+13) within InfluxDB::LineProtocol::BEGIN@37 which was called:
# once (8µs+13µs) by main::BEGIN@207 at line 37 # spent 21µs making 1 call to InfluxDB::LineProtocol::BEGIN@37
# spent 13µs making 1 call to strict::unimport |
38 | 1 | 4µs | *{"$caller\::$target"} = \&$function; | ||
39 | } | ||||
40 | } | ||||
41 | |||||
42 | } | ||||
43 | |||||
44 | sub _format_key { | ||||
45 | my $k = shift; | ||||
46 | |||||
47 | $k =~ s/([, ])/\\$1/g; | ||||
48 | |||||
49 | return $k; | ||||
50 | } | ||||
51 | |||||
52 | sub _format_value { | ||||
53 | my $k = shift; | ||||
54 | my $v = shift; | ||||
55 | |||||
56 | if ( $v =~ /^(-?\d+)(?:i?)$/ ) { | ||||
57 | $v = $1 . 'i'; | ||||
58 | } | ||||
59 | elsif ( $v =~ /^[Ff](?:ALSE|alse)?$/ ) { | ||||
60 | $v = 'FALSE'; | ||||
61 | } | ||||
62 | elsif ( $v =~ /^[Tt](?:RUE|rue)?$/ ) { | ||||
63 | $v = 'TRUE'; | ||||
64 | } | ||||
65 | elsif ( $v =~ /^-?\d+(?:\.\d+)?(?:e-?\d+)?$/ ) { | ||||
66 | # pass it on, no mod | ||||
67 | } | ||||
68 | else { | ||||
69 | # string actually, but this should be quoted differently? | ||||
70 | $v =~ s/"/\\"/g; | ||||
71 | $v = '"' . $v . '"'; | ||||
72 | } | ||||
73 | |||||
74 | return $v; | ||||
75 | } | ||||
76 | |||||
77 | sub data2line { | ||||
78 | my ( $measurement, $values, $tags, $timestamp ) = @_; | ||||
79 | |||||
80 | if ( @_ == 1 ) { | ||||
81 | # no $fields, so assume we already got a line | ||||
82 | return $measurement; | ||||
83 | } | ||||
84 | |||||
85 | my $key = $measurement; | ||||
86 | $key =~ s/([, ])/\\$1/g; | ||||
87 | |||||
88 | # $tags has to be a hashref, if it's not, we dont have tags, so it's the timestamp | ||||
89 | if ( defined $tags ) { | ||||
90 | if ( ref($tags) eq 'HASH' ) { | ||||
91 | my @tags; | ||||
92 | foreach my $k ( sort keys %$tags ) | ||||
93 | { # Influx wants the tags presorted | ||||
94 | # TODO check if sorting algorithm matches | ||||
95 | # http://golang.org/pkg/bytes/#Compare | ||||
96 | my $v = $tags->{$k}; | ||||
97 | next unless defined $v; | ||||
98 | $k =~ s/([, ])/\\$1/g; | ||||
99 | $v =~ s/([, ])/\\$1/g; | ||||
100 | push( @tags, $k . '=' . $v ); | ||||
101 | } | ||||
102 | $key .= join( ',', '', @tags ) if @tags; | ||||
103 | } | ||||
104 | elsif ( !ref($tags) ) { | ||||
105 | $timestamp = $tags; | ||||
106 | } | ||||
107 | } | ||||
108 | |||||
109 | if ($timestamp) { | ||||
110 | croak("$timestamp does not look like an epoch timestamp") | ||||
111 | unless $timestamp =~ /^\d+$/; | ||||
112 | if ( length($timestamp) < 19 ) { | ||||
113 | my $missing = 19 - length($timestamp); | ||||
114 | my $zeros = 0 x $missing; | ||||
115 | $timestamp .= $zeros; | ||||
116 | } | ||||
117 | } | ||||
118 | else { | ||||
119 | # Get time of day returns (seconds, microseconds) | ||||
120 | # $timestamp needs to be nanoseconds | ||||
121 | # it must also be a string to avoid conversion to sci notations | ||||
122 | $timestamp = sprintf "%s%06d000", gettimeofday(); | ||||
123 | } | ||||
124 | |||||
125 | # If values is not a hashref, convert it into one | ||||
126 | $values = { value => $values } if (not ref($values)); | ||||
127 | |||||
128 | my @fields; | ||||
129 | foreach my $k ( sort keys %$values ) { | ||||
130 | my $v = $values->{$k}; | ||||
131 | |||||
132 | my $esc_k = _format_key($k); | ||||
133 | my $esc_v = _format_value($k, $v); | ||||
134 | |||||
135 | push( @fields, $esc_k . '=' . $esc_v ); | ||||
136 | } | ||||
137 | my $fields = join( ',', @fields ); | ||||
138 | |||||
139 | return sprintf( "%s %s %s", $key, $fields, $timestamp ); | ||||
140 | } | ||||
141 | |||||
142 | sub line2data { | ||||
143 | my $line = shift; | ||||
144 | chomp($line); | ||||
145 | |||||
146 | $line =~ s/\\ /ESCAPEDSPACE/g; | ||||
147 | $line =~ s/\\,/ESCAPEDCOMMA/g; | ||||
148 | $line =~ s/\\"/ESCAPEDDBLQUOTE/g; | ||||
149 | |||||
150 | $line=~/^(.*?) (.*) (.*)$/; | ||||
151 | my ($key, $fields, $timestamp) = ( $1, $2, $3); | ||||
152 | |||||
153 | my ( $measurement, @taglist ) = split( /,/, $key ); | ||||
154 | $measurement =~ s/ESCAPEDSPACE/ /g; | ||||
155 | $measurement =~ s/ESCAPEDCOMMA/,/g; | ||||
156 | |||||
157 | my $tags; | ||||
158 | foreach my $tagset (@taglist) { | ||||
159 | $tagset =~ s/ESCAPEDSPACE/ /g; | ||||
160 | $tagset =~ s/ESCAPEDCOMMA/,/g; | ||||
161 | my ( $k, $v ) = split( /=/, $tagset ); | ||||
162 | $tags->{$k} = $v; | ||||
163 | } | ||||
164 | |||||
165 | my $values; | ||||
166 | my @strings; | ||||
167 | if ($fields =~ /"/) { | ||||
168 | my $cnt=0; | ||||
169 | $fields=~s/"(.*?)"/push(@strings, $1); 'ESCAPEDSTRING_'.$cnt++;/ge; | ||||
170 | } | ||||
171 | foreach my $valset ( split( /,/, $fields ) ) { | ||||
172 | $valset =~ s/ESCAPEDSPACE/ /g; | ||||
173 | $valset =~ s/ESCAPEDCOMMA/,/g; | ||||
174 | my ( $k, $v ) = split( /=/, $valset ); | ||||
175 | $v =~ s/ESCAPEDSTRING_(\d+)/$strings[$1]/ge; | ||||
176 | $v =~ s/ESCAPEDDBLQUOTE/"/g; | ||||
177 | $v =~ s/^(-?\d+)i$/$1/; | ||||
178 | $values->{$k} = $v; | ||||
179 | } | ||||
180 | |||||
181 | return ( $measurement, $values, $tags, $timestamp ); | ||||
182 | } | ||||
183 | |||||
184 | sub _data2line_0_9_2 { | ||||
185 | my ( $measurement, $values, $tags, $timestamp ) = @_; | ||||
186 | |||||
187 | if ( @_ == 1 ) { | ||||
188 | # no $fields, so assume we already got a line | ||||
189 | return $measurement; | ||||
190 | } | ||||
191 | |||||
192 | my $key = $measurement; | ||||
193 | $key =~ s/([, ])/\\$1/g; | ||||
194 | |||||
195 | # $tags has to be a hashref, if it's not, we dont have tags, so it's the timestamp | ||||
196 | if ( defined $tags ) { | ||||
197 | if ( ref($tags) eq 'HASH' ) { | ||||
198 | my @tags; | ||||
199 | foreach my $k ( sort keys %$tags ) | ||||
200 | { # Influx wants the tags presorted | ||||
201 | # TODO check if sorting algorithm matches | ||||
202 | # http://golang.org/pkg/bytes/#Compare | ||||
203 | my $v = $tags->{$k}; | ||||
204 | next unless defined $v; | ||||
205 | $k =~ s/([, ])/\\$1/g; | ||||
206 | $v =~ s/([, ])/\\$1/g; | ||||
207 | push( @tags, $k . '=' . $v ); | ||||
208 | } | ||||
209 | $key .= join( ',', '', @tags ) if @tags; | ||||
210 | } | ||||
211 | elsif ( !ref($tags) ) { | ||||
212 | $timestamp = $tags; | ||||
213 | } | ||||
214 | } | ||||
215 | |||||
216 | if ($timestamp) { | ||||
217 | croak("$timestamp does not look like an epoch timestamp") | ||||
218 | unless $timestamp =~ /^\d+$/; | ||||
219 | if ( length($timestamp) < 19 ) { | ||||
220 | my $missing = 19 - length($timestamp); | ||||
221 | my $zeros = 0 x $missing; | ||||
222 | $timestamp .= $zeros; | ||||
223 | } | ||||
224 | } | ||||
225 | else { | ||||
226 | $timestamp = join( '', gettimeofday(), '000' ); | ||||
227 | $timestamp .= '0' if length($timestamp) < 19; | ||||
228 | } | ||||
229 | |||||
230 | # If values is not a hashref, convert it into one | ||||
231 | $values = { value => $values } if (not ref($values)); | ||||
232 | |||||
233 | my @fields; | ||||
234 | foreach my $k ( sort keys %$values ) { | ||||
235 | my $v = $values->{$k}; | ||||
236 | $k =~ s/([, ])/\\$1/g; | ||||
237 | |||||
238 | if ( | ||||
239 | # positive & negativ ints, exponentials, use Regexp::Common? | ||||
240 | $v !~ /^-?\d+(?:\.\d+)?(?:e-?\d+)?$/ | ||||
241 | && | ||||
242 | # perl 5.12 Regexp::Assemble->new->add(qw(t T true TRUE f F false FALSE))->re; | ||||
243 | $v !~ /^(?:F(?:ALSE)?|f(?:alse)?|T(?:RUE)?|t(?:rue)?)$/ | ||||
244 | ) | ||||
245 | { | ||||
246 | $v =~ s/"/\\"/g; | ||||
247 | $v = '"' . $v . '"'; | ||||
248 | } | ||||
249 | push( @fields, $k . '=' . $v ); | ||||
250 | } | ||||
251 | my $fields = join( ',', @fields ); | ||||
252 | |||||
253 | return sprintf( "%s %s %s", $key, $fields, $timestamp ); | ||||
254 | } | ||||
255 | |||||
256 | sub _line2data_0_9_2 { | ||||
257 | my $line = shift; | ||||
258 | chomp($line); | ||||
259 | |||||
260 | $line =~ s/\\ /ESCAPEDSPACE/g; | ||||
261 | $line =~ s/\\,/ESCAPEDCOMMA/g; | ||||
262 | $line =~ s/\\"/ESCAPEDDBLQUOTE/g; | ||||
263 | |||||
264 | $line=~/^(.*?) (.*) (.*)$/; | ||||
265 | my ($key, $fields, $timestamp) = ( $1, $2, $3); | ||||
266 | |||||
267 | my ( $measurement, @taglist ) = split( /,/, $key ); | ||||
268 | $measurement =~ s/ESCAPEDSPACE/ /g; | ||||
269 | $measurement =~ s/ESCAPEDCOMMA/,/g; | ||||
270 | |||||
271 | my $tags; | ||||
272 | foreach my $tagset (@taglist) { | ||||
273 | $tagset =~ s/ESCAPEDSPACE/ /g; | ||||
274 | $tagset =~ s/ESCAPEDCOMMA/,/g; | ||||
275 | my ( $k, $v ) = split( /=/, $tagset ); | ||||
276 | $tags->{$k} = $v; | ||||
277 | } | ||||
278 | |||||
279 | my $values; | ||||
280 | my @strings; | ||||
281 | if ($fields =~ /"/) { | ||||
282 | my $cnt=0; | ||||
283 | $fields=~s/"(.*?)"/push(@strings, $1); 'ESCAPEDSTRING_'.$cnt++;/ge; | ||||
284 | } | ||||
285 | foreach my $valset ( split( /,/, $fields ) ) { | ||||
286 | $valset =~ s/ESCAPEDSPACE/ /g; | ||||
287 | $valset =~ s/ESCAPEDCOMMA/,/g; | ||||
288 | my ( $k, $v ) = split( /=/, $valset ); | ||||
289 | $v =~ s/ESCAPEDSTRING_(\d+)/$strings[$1]/ge; | ||||
290 | $v =~ s/ESCAPEDDBLQUOTE/"/g; | ||||
291 | $values->{$k} = $v; | ||||
292 | } | ||||
293 | |||||
294 | return ( $measurement, $values, $tags, $timestamp ); | ||||
295 | } | ||||
296 | |||||
297 | 1 | 4µs | 1; | ||
298 | |||||
299 | __END__ | ||||
# spent 1µs within InfluxDB::LineProtocol::CORE:match which was called:
# once (1µs+0s) by InfluxDB::LineProtocol::import at line 27 |