source: ntrip/trunk/BNC/scripts/Common.pm@ 9737

Last change on this file since 9737 was 9627, checked in by wiese, 3 years ago

add bncLogstash script

  • Property svn:keywords set to Header
File size: 8.4 KB
Line 
1package Common;
2
3#
4# Some common functions
5#
6# Revision: $Header: trunk/BNC/scripts/Common.pm 9627 2022-02-21 09:07:55Z wiese $
7#
8
9use strict;
10use warnings;
11use Exporter;
12use Data::Dumper;
13use Log::Log4perl qw(:easy);
14use File::Temp;
15use File::Basename;
16use File::Spec::Functions;
17
18#$| = 1; # Buffer off (print)
19
20sub trim {
21 my ($text) = @_;
22 $text =~ s/^[\s]*//g;
23 $text =~ s/[\s]*$//g;
24 return $text;
25}
26
27# run a command in the shell.
28sub runCmd {
29 my ($cmd) = shift;
30
31 DEBUG("run cmd: \"$cmd\"");
32
33 my $tmpfh = File::Temp->new( UNLINK => 1, SUFFIX => '.dat' );
34 my $tmpfile = $tmpfh->filename();
35
36 $cmd = "$cmd 2>$tmpfile |";
37 my $PIPE;
38 unless ( open $PIPE, $cmd ) {
39 ERROR("open $cmd | failed ($!)");
40 return ( -1, "", "" );
41 }
42 my $stdout = join '', <$PIPE>;
43 close $PIPE;
44 my $exit_code = $?;
45
46 my $stderr = getContent($tmpfile);
47 return ( $exit_code, $stdout, $stderr );
48}
49
50#** @function amInteractiv ()
51# @brief Checks if a program runs interactivly, or e.g. was invoked by cron.
52# @see Perl Cookbook Kap. 15.2
53# @return true if interactive, else false.
54#*
55sub amInteractiv {
56 use POSIX qw(getpgrp tcgetpgrp);
57 my $tty;
58 open ( $tty, "<", "/dev/tty" ) || LOGDIE "Could not open /dev/tty: $!";
59 my $tpgrp = tcgetpgrp( fileno ($tty) ); # get terminal foreground process group
60 my $pgrp = getpgrp (); # get the current process group
61 close $tty;
62 return ( $tpgrp == $pgrp );
63}
64
65#** @function printData ($data)
66# @brief Prints perl data structures. Uses Data::Dumper.
67# @param $data [required] Daten
68# @return -
69#*
70sub printData {
71 my $data = shift;
72 my $d = Data::Dumper->new($data);
73 $d->Indent(3); # pretty print with array indices
74 print $d->Dump;
75}
76
77sub getContent {
78 my ($fileName) = @_;
79 my $errmsg = "";
80 if ( -f $fileName ) {
81 my $readMode = $/;
82 undef $/;
83 open ( FILE, "<", $fileName )
84 or ERROR("Kann Datei nicht zum lesen oeffnen");
85 $errmsg = <FILE>;
86 close (FILE);
87 $/ = $readMode;
88 }
89 return $errmsg;
90}
91
92#** @function filePosition ($file, $filePos)
93# @brief Save position of a file in an idxfile.
94#
95# Especially for logfiles. For performance reasons, logfiles should not parsed always from the
96# beginning, the next read access should start at the pos of the last read.
97# Saves the position of the last read in a help-file ".filePos" in
98# the directory of the logfile. If the param $filePos is set, then this position will be saved (Write).
99# Otherwise the current position will be returned (Read).
100# @param $file [required] File of interest
101# @param $filePos [optional] if given, this position ()in Bytes) will be saved, else return current position
102# @return file position in Bytes from beginning of the file
103#*
104sub filePosition {
105 my ( $file, $filePos ) = @_;
106
107 my ( $filName, $filDir ) = fileparse($file);
108 my $idxFil = catfile( $filDir, ".filePos" );
109
110 if ($filePos) {
111
112 # Save this position in idxfile
113 my $newPos = "$filName $filePos";
114 if ( -e $idxFil ) {
115 unless ( replace( $idxFil, "^${filName} \\d+", $newPos ) ) {
116
117 # could not replace -> append
118 blurt( "$newPos\n", $idxFil, { append => 1 } );
119# my $INP;
120# if ( !open ( $INP, ">>", $idxFil ) ) {
121# ERROR("Could not append file [$idxFil]: $!");
122# return 0;
123# }
124# print $INP "$newPos\n";
125# close ($INP);
126 }
127 }
128 else {
129 # initial write
130 blurt( "$newPos\n", $idxFil );
131 #writeTextInFile( $idxFil, "$newPos\n" );
132 }
133 }
134 else {
135
136 # Read current position from idxfile
137 # ----------------------------------
138 if ( !-e $idxFil ) {
139 return 0;
140 }
141 my $line = "";
142 my $idx_fh;
143 if ( !open ( $idx_fh, "<", $idxFil ) ) {
144 ERROR("Could not open for read $idxFil: $!");
145 return 0;
146 }
147 while (<$idx_fh>) {
148 if ( $_ =~ /^$filName (\d+)/ ) { # RegEx problematic with getContentFiltered()
149 $line .= $_;
150 $filePos = $1;
151 last;
152 }
153 }
154 close ($idx_fh);
155
156 if ( $line && !$filePos ) {
157 ERROR("Could not read file position in idxfile $idxFil. Weired line \"$line\"");
158 $filePos = 0;
159 }
160
161 if ($filePos) {
162
163 # If the file was meanwhile newly created, e.g. after restart from BNC
164 my $fileSize = -s $file;
165 if ( $filePos > $fileSize ) {
166 WARN "file $file seams to be newly created";
167 DEBUG("size:$fileSize pos:$filePos");
168 $filePos = 0;
169 }
170 }
171 else {
172 WARN("No position entry found in idxfile for \"$filName\"");
173 $filePos = 0;
174 }
175 }
176
177 return $filePos;
178}
179
180#** @function isAlreadyRunning ()
181# @brief Check if this program is already running.
182# @details Usage: isAlreadyRunning() && die "Same job is already running!\n";@n
183# Purpose: e.g. to avoid a program running twice
184# @see bernese gpsutil::check_job()
185# @return pid of already running job else false
186#*
187sub isAlreadyRunning {
188 my ($scriptName) = fileparse($0);
189
190 use Proc::ProcessTable;
191 my $pt = new Proc::ProcessTable;
192 my $pid_found = 0; # from already running job
193 foreach my $p ( @{ $pt->table } ) {
194 my $cmd = $p->cmndline;
195 if ( $cmd =~ /$scriptName/ && $p->pid != $$ ) {
196 next if ( $p->pid == getppid () ); # when started from cron!
197 DEBUG( "Found: " . $p->pid . ", myself: $$" );
198 $pid_found = $p->pid;
199 DEBUG "Process $cmd is running";
200 last;
201 }
202 }
203
204 return $pid_found;
205}
206
207# toLineProtocol($rcd)
208# @brief converts $rcd to InfluxDB line protocol
209# @see https://docs.influxdata.com/influxdb/v2.1/reference/syntax/line-protocol/
210sub toLineProtocol {
211 my ($rcd) = @_;
212
213 my $err = 0;
214 my $str = $rcd->{'measurement'} . ',';
215
216 # Tags (sort by key (in lexicographic order) for performance reasons)
217 foreach ( sort { lc ($a) cmp lc ($b) } keys %{ $rcd->{'tags'} } ) {
218 if ( !exists $rcd->{'tags'}->{$_} ) {
219 $err++;
220 #next; # ?
221 }
222 $str .= $_ . "=" . $rcd->{'tags'}->{$_} . ",";
223 }
224 chop $str;
225 $str .= " ";
226
227 # Fields
228 while ( my ( $k, $v ) = each %{ $rcd->{'fields'} } ) {
229 if ( !defined $v ) {
230 $err++;
231 }
232 $str .= $k . "=" . $v . ",";
233 }
234 chop $str;
235 $str .= " " . $rcd->{'time'}; # prec=s
236 if ($err) {
237 return 0;
238 }
239 return $str;
240}
241
242#** @function rms ($numbers)
243# @brief Compute the Root mean square.
244# @param $numbers [required] List with your numbers
245# @return RMS value
246# @note use PDL stats() if installed!
247# @see http://rosettacode.org/wiki/Averages/Root_mean_square#Perl
248#*
249sub rms {
250 my $r = 0;
251 $r += $_**2 for @_;
252 return sqrt ( $r / @_ );
253}
254
255#** @function avg ($numbers)
256# @brief Compute the arithmetic mean value.
257# @param $numbers [required] List with your numbers
258# @note use PDL stats() if installed!
259# @return mean value
260# @see http://rosettacode.org/wiki/Average/Arithmetic_mean#Perl
261#*
262sub avg {
263 @_ or return 0;
264 my $sum = 0;
265 $sum += $_ foreach @_;
266 return $sum / @_;
267}
268
269#** @function sigma ($numbers)
270# @brief Compute the STDDEV of the arithmetic mean.
271# @param $numbers [required] List with your numbers
272# @return Sigma value
273# @note use use PDL::Primitive qw(stats) if installed!
274#*
275sub sigma {
276 my $n = scalar (@_);
277
278 if ( $n == 1 ) {
279 WARN "Could not compute sigma for only one sample";
280 return;
281 }
282
283 my $e = 0; # arithm. Mittel
284 $e += $_ for @_;
285 $e = $e / $n;
286
287 my @v = map { $e - $_ } @_;
288 my $vv = 0;
289 $vv += $_**2 for @v;
290 return sqrt ( $vv / ( $n * ( $n - 1 ) ) );
291}
292
293#** @function median (@numbers)
294# @brief Compute the median of a list of numbers.
295# @param @numbers [required] List with your numbers
296# @see https://en.wikipedia.org/wiki/Median
297# @note use PDL stats() if installed!
298# @return median
299#*
300sub median {
301 my $mid = int ( @_ / 2 );
302 my @sorted = sort { $a <=> $b } (@_);
303 if ( @sorted % 2 ) {
304 return $sorted[$mid];
305 }
306 else {
307 return ( $sorted[ $mid - 1 ] + $sorted[$mid] ) / 2;
308 }
309
310 return; # undef
311}
312
3131; # End of Common
314
Note: See TracBrowser for help on using the repository browser.