1 | #!/usr/bin/env perl
|
---|
2 |
|
---|
3 | # ========================================================================
|
---|
4 | # bncLogstash.pl
|
---|
5 | # ========================================================================
|
---|
6 | #
|
---|
7 | # Purpose: Reads BNC's logfile and converts the parsed metrics to InfluxDB
|
---|
8 | # line protocol.
|
---|
9 | #
|
---|
10 | # Author : Erwin Wiesensarter, April-2016
|
---|
11 | # Revision: $Header: trunk/BNC/scripts/bncLogstash.pl 9627 2022-02-21 09:07:55Z wiese $
|
---|
12 | # ========================================================================
|
---|
13 |
|
---|
14 | # Uses
|
---|
15 | use strict;
|
---|
16 | use warnings;
|
---|
17 |
|
---|
18 | BEGIN {
|
---|
19 | use FindBin qw($Bin);
|
---|
20 | use lib "$Bin";
|
---|
21 | }
|
---|
22 |
|
---|
23 | use FindBin qw($Bin);
|
---|
24 | use Getopt::Long;
|
---|
25 | use File::Basename;
|
---|
26 | use File::Spec::Functions;
|
---|
27 | use List::MoreUtils qw(any uniq);
|
---|
28 | use Log::Log4perl qw(:easy);
|
---|
29 | use Time::Piece 1.30;
|
---|
30 | use Data::Dumper;
|
---|
31 | use POSIX qw(uname);
|
---|
32 |
|
---|
33 | # BKG Perl libs
|
---|
34 | use Bnc;
|
---|
35 | use Common;
|
---|
36 |
|
---|
37 | # Logging
|
---|
38 | Log::Log4perl->easy_init(
|
---|
39 | {
|
---|
40 | layout => '%d [%c] %p: %m%n', # '[%F{1}-%L-%M]: %m%n'
|
---|
41 | level => $DEBUG # $TRACE $INFO
|
---|
42 | }
|
---|
43 | );
|
---|
44 |
|
---|
45 | # Options
|
---|
46 | my $bncConf = {};
|
---|
47 | my ($home) = glob "~";
|
---|
48 | my $corrMount = "n/a";
|
---|
49 | my $now = Time::Piece->new;
|
---|
50 | my ($prog) = fileparse($0);
|
---|
51 | my $hostname = (uname)[1];
|
---|
52 | my $influx_db = 'realtime';
|
---|
53 |
|
---|
54 | # Args
|
---|
55 | my $help = 0;
|
---|
56 | my $fromBeginning = 0;
|
---|
57 | my $bncConfFile = "";
|
---|
58 | my $intv = 5; # each epoch (default)
|
---|
59 | my $pppScene = 0;
|
---|
60 | my $output = "influx";
|
---|
61 | my @tags = ();
|
---|
62 |
|
---|
63 | GetOptions(
|
---|
64 | 'help' => \$help,
|
---|
65 | 'from-begin' => \$fromBeginning,
|
---|
66 | 'conf=s' => \$bncConfFile,
|
---|
67 | 'intv=s' => \$intv,
|
---|
68 | 'scene=s' => \$pppScene,
|
---|
69 | 'output=s' => \$output,
|
---|
70 | 'tags=s' => \@tags,
|
---|
71 | );
|
---|
72 |
|
---|
73 | HELP_MESSAGE() if $help;
|
---|
74 |
|
---|
75 | if ( $output && !( $output =~ /influx/i ) ) { LOGDIE "Undefined output \"$output\"\n", HELP_MESSAGE() }
|
---|
76 | $output = lc $output;
|
---|
77 | $bncConfFile || LOGDIE( "Please set option \"conf\".\n", HELP_MESSAGE() );
|
---|
78 | if ( $bncConfFile && !-s $bncConfFile ) {
|
---|
79 | my $bncConfFile1 = catfile( $home, $bncConfFile );
|
---|
80 | if ( -s $bncConfFile1 ) { $bncConfFile = $bncConfFile1 }
|
---|
81 | else { LOGDIE "BNC config file \"$bncConfFile\" does not exist\n" }
|
---|
82 | }
|
---|
83 | my %tags = ();
|
---|
84 | foreach (@tags) {
|
---|
85 | s/^\s*//;
|
---|
86 | s/\s+$//;
|
---|
87 | my ( $k, $v ) = split ( /\s*=\s*/, $_, 2 );
|
---|
88 | $tags{$k} = $v;
|
---|
89 | }
|
---|
90 |
|
---|
91 | INFO ">>>>> Start $prog $bncConfFile ..";
|
---|
92 |
|
---|
93 | # Should only run once
|
---|
94 | # TODO checks args for that
|
---|
95 | Common::isAlreadyRunning() && LOGDIE "Job is already running! Exit\n";
|
---|
96 |
|
---|
97 | # -----------------------------------------------------------------------------
|
---|
98 | # Parse BNC config file
|
---|
99 | # -----------------------------------------------------------------------------
|
---|
100 | $bncConf = Bnc::parseConfig($bncConfFile); # cmbMethod dataSource ?
|
---|
101 | $corrMount = $bncConf->{'PPP'}->{'corrMount'};
|
---|
102 | my $bncLogFile = $bncConf->{'General'}->{'logFile'};
|
---|
103 | my $date = getLogFileDate($now);
|
---|
104 | $bncLogFile .= "_$date"; # -> *_160425
|
---|
105 |
|
---|
106 | -s "$bncLogFile" || LOGDIE("logfile \"$bncLogFile\" does not exist. Exit\n");
|
---|
107 | my ( $logFilName, $logFilDir ) = fileparse($bncLogFile);
|
---|
108 |
|
---|
109 | my $mpts_def = $bncConf->{'General'}->{'mountPoints_parsed'};
|
---|
110 | my %mpLookup = map { $_->{'mp'}, $_->{'caster'} } @$mpts_def;
|
---|
111 |
|
---|
112 | # -----------------------------------------------------------------------------
|
---|
113 | # Select and parse BNC logfile
|
---|
114 | # -----------------------------------------------------------------------------
|
---|
115 | my $data = Bnc::parseLogfile( $bncLogFile, $intv, !$fromBeginning );
|
---|
116 | my @EPOCHS = @{ $data->{'EPOCHS'} };
|
---|
117 | my @sites = map { $_->{'site'} } @EPOCHS;
|
---|
118 | @sites = uniq @sites;
|
---|
119 | my $nof_epochs = scalar @EPOCHS;
|
---|
120 |
|
---|
121 | my @latencies = @{ $data->{'LATENCIES'} };
|
---|
122 | my @restarts = @{ $data->{'RESTARTS'} };
|
---|
123 |
|
---|
124 | # Some output
|
---|
125 | DEBUG( "\n> output : $output\n> BNC conf : $bncConfFile"
|
---|
126 | . "\n> BNC lfile: $bncLogFile\n> sampling : $intv\n> PPP-Scene: $pppScene"
|
---|
127 | . "\n> Sites : @sites\n> #epochs : $nof_epochs\n> tags : @tags"
|
---|
128 | . "\n> Latencies: "
|
---|
129 | . scalar @latencies
|
---|
130 | . "\n> Restarts : "
|
---|
131 | . scalar @restarts );
|
---|
132 |
|
---|
133 | if ( $nof_epochs < 1 && scalar @latencies < 1 ) {
|
---|
134 | INFO "No epochs or latencies found. Do nothing";
|
---|
135 | exit 0;
|
---|
136 | }
|
---|
137 |
|
---|
138 | # -----------------------------------------------------------------------------
|
---|
139 | # Reformat data
|
---|
140 | # -----------------------------------------------------------------------------
|
---|
141 | my @data_influxFormated = ();
|
---|
142 |
|
---|
143 | # Epochs
|
---|
144 | my $rcd = {};
|
---|
145 | foreach (@EPOCHS) {
|
---|
146 | next if ( $_->{'dN'} == 0 || $_->{'dU'} == 0 );
|
---|
147 |
|
---|
148 | if ( $_->{'dN'} eq '-nan' || $_->{'dU'} eq '-nan' ) {
|
---|
149 | next;
|
---|
150 | }
|
---|
151 |
|
---|
152 | # Horizontal displacement (computation not available yet in influxDB)
|
---|
153 | # influxDB kann sowas "SELECT sum(value * value) FROM cpu" leider NOCH nicht!
|
---|
154 | # NEU in version 1.6: math functions SQRT,POW, usw. !!
|
---|
155 | my $d2d = $_->{'dN'}**2 + $_->{'dE'}**2; # Quadrat, um spaeter leichter den RMS zu berechnen
|
---|
156 | my $d3d = $d2d + $_->{'dU'}**2;
|
---|
157 |
|
---|
158 | $rcd = {
|
---|
159 | measurement => 'ppp',
|
---|
160 | tags => {
|
---|
161 | mp => $_->{'site'},
|
---|
162 | corrMount => $corrMount || "NO", # SPP, empty geht derzeit nicht -> InfluxError
|
---|
163 | caster => $mpLookup{ $_->{'site'} } || 'Unknown',
|
---|
164 | host => $hostname,
|
---|
165 | scene => $pppScene,
|
---|
166 | clientSW => 'BNC'
|
---|
167 |
|
---|
168 | #pppvers => $pppvers,
|
---|
169 | #bncvers => '2.12.0',
|
---|
170 | },
|
---|
171 | fields => {
|
---|
172 | dN => $_->{'dN'} + 0.0,
|
---|
173 | dE => $_->{'dE'} + 0.0,
|
---|
174 | dU => $_->{'dU'} + 0.0,
|
---|
175 | d2d => sprintf ( "%.5f", $d2d ),
|
---|
176 | d3d => sprintf ( "%.5f", $d3d ),
|
---|
177 | TRP => $_->{'TRP'} + 0.0,
|
---|
178 | },
|
---|
179 | time => $_->{'time'}
|
---|
180 | };
|
---|
181 | push ( @data_influxFormated, $rcd );
|
---|
182 | }
|
---|
183 |
|
---|
184 | # Latencies
|
---|
185 | my $lat_rcd = {};
|
---|
186 | foreach (@latencies) {
|
---|
187 | $lat_rcd = {
|
---|
188 | measurement => 'stream_latency',
|
---|
189 | tags => {
|
---|
190 | mp => $_->{'mp'},
|
---|
191 | type => $_->{'type'},
|
---|
192 | caster => $mpLookup{ $_->{'mp'} } || 'Unknown',
|
---|
193 | host => $hostname,
|
---|
194 | scene => $pppScene
|
---|
195 | },
|
---|
196 | fields => {
|
---|
197 | meanLat => $_->{'meanLat'},
|
---|
198 | epochs => $_->{'epochs'},
|
---|
199 | gaps => $_->{'gaps'} || 0
|
---|
200 | },
|
---|
201 | time => $_->{'time'}
|
---|
202 | };
|
---|
203 | push ( @data_influxFormated, $lat_rcd );
|
---|
204 | }
|
---|
205 |
|
---|
206 | # BNC Starts
|
---|
207 | if ($pppScene) {
|
---|
208 | my $restart_rcd = {};
|
---|
209 | foreach (@restarts) {
|
---|
210 | $restart_rcd = {
|
---|
211 | measurement => 'ppp',
|
---|
212 | tags => {
|
---|
213 | host => $hostname,
|
---|
214 | scene => $pppScene,
|
---|
215 | event => 'BNC_Start'
|
---|
216 | },
|
---|
217 | fields => { text => "\"BNC " . $_->{'bncvers'} . " started\"" },
|
---|
218 | time => $_->{'time'}
|
---|
219 | };
|
---|
220 | push ( @data_influxFormated, $restart_rcd );
|
---|
221 | }
|
---|
222 | }
|
---|
223 |
|
---|
224 | # -----------------------------------------------------------------------------
|
---|
225 | # Output
|
---|
226 | # -----------------------------------------------------------------------------
|
---|
227 | if ( scalar @data_influxFormated < 1 ) {
|
---|
228 | INFO "No metrics found";
|
---|
229 | exit 0;
|
---|
230 | }
|
---|
231 |
|
---|
232 | # add tags from arguments
|
---|
233 | foreach my $rc (@data_influxFormated) {
|
---|
234 | foreach my $k ( keys %tags ) {
|
---|
235 | $rc->{'tags'}->{$k} = $tags{$k};
|
---|
236 | }
|
---|
237 | }
|
---|
238 |
|
---|
239 | if ( $output =~ /influx/ ) {
|
---|
240 | my ( $i, $err ) = ( 0, 0 );
|
---|
241 | foreach (@data_influxFormated) {
|
---|
242 | my $l = Common::toLineProtocol($_);
|
---|
243 | if ($l) {
|
---|
244 | print STDOUT "$l\n";
|
---|
245 | $i++;
|
---|
246 | }
|
---|
247 | else { $err++ }
|
---|
248 | }
|
---|
249 | DEBUG "Lines written: $i";
|
---|
250 | DEBUG "Errorneous lines: $err";
|
---|
251 | }
|
---|
252 | else {
|
---|
253 | LOGDIE("output not supported: $output");
|
---|
254 | }
|
---|
255 |
|
---|
256 | ##########################################################################
|
---|
257 | # Select date of the logfile we want to read
|
---|
258 | sub getLogFileDate {
|
---|
259 | my ($tp) = @_;
|
---|
260 | if ( $tp->hour == 0 && $tp->min < 5 ) { # read last day
|
---|
261 | $tp -= 300;
|
---|
262 | }
|
---|
263 | return $tp->strftime('%y%m%d');
|
---|
264 | }
|
---|
265 |
|
---|
266 | sub HELP_MESSAGE {
|
---|
267 | print <<EOI_HILFE;
|
---|
268 | $prog - reads BNC's logfile and writes metrics in formats that can be easily imported
|
---|
269 | by other tools, e.g. InfluxDB.
|
---|
270 |
|
---|
271 | USAGE:
|
---|
272 | $prog [paramter]
|
---|
273 |
|
---|
274 | OPTIONS:
|
---|
275 | -c|--conf BNC config file for this job. Settings like PPP logpath
|
---|
276 | will be parsed from that config file.
|
---|
277 | Options -l and -b are not allowed together.
|
---|
278 | -f|--from-begin If set, the the logfile will be read from the beginning. Default is that the logfile is tailed.
|
---|
279 | -o|--output output format. So far only the InfluxDB line protocol (default).
|
---|
280 | -i|--intv sampling interval in seconds that shall be used in plots;
|
---|
281 | default: each epoch; for a daily logfile <30> seconds
|
---|
282 | should be usefull.
|
---|
283 | -t|--tags <tags> comma separeted list of tags in format key=value,key2=value.
|
---|
284 | -s|--scene PPP scene number or identifier.
|
---|
285 | -h|--help show help contents.
|
---|
286 |
|
---|
287 | EXAMPLES:
|
---|
288 | $prog --conf path/to/BNC.bnc -i 5 -s 24 -f 2>bnc.err
|
---|
289 | $prog --conf path/to/BNC.bnc -o influx -t proj=cost,name=Tim 2>bnc.err
|
---|
290 |
|
---|
291 | Copyright (c) 2016 BKG Frankfurt <erwin.wiesensarter\@bkg.bund.de>
|
---|
292 | EOI_HILFE
|
---|
293 | exit;
|
---|
294 | }
|
---|