summaryrefslogtreecommitdiffstats
path: root/vespalog/src/logfmt/logfmt.pl
diff options
context:
space:
mode:
Diffstat (limited to 'vespalog/src/logfmt/logfmt.pl')
-rw-r--r--vespalog/src/logfmt/logfmt.pl327
1 files changed, 327 insertions, 0 deletions
diff --git a/vespalog/src/logfmt/logfmt.pl b/vespalog/src/logfmt/logfmt.pl
new file mode 100644
index 00000000000..9152d1fcfec
--- /dev/null
+++ b/vespalog/src/logfmt/logfmt.pl
@@ -0,0 +1,327 @@
+#!/usr/local/bin/perl
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+# BEGIN perl environment bootstrap section
+# Do not edit between here and END as this section should stay identical in all scripts
+
+use File::Basename;
+use File::Path;
+
+sub findpath {
+ my $myfullname = ${0};
+ my($myname, $mypath) = fileparse($myfullname);
+
+ return $mypath if ( $mypath && -d $mypath );
+ $mypath=`pwd`;
+
+ my $pwdfullname = $mypath . "/" . $myname;
+ return $mypath if ( -f $pwdfullname );
+ return 0;
+}
+
+# Returns the argument path if it seems to point to VESPA_HOME, 0 otherwise
+sub is_vespa_home {
+ my($VESPA_HOME) = shift;
+ my $COMMON_ENV="libexec/vespa/common-env.sh";
+ if ( $VESPA_HOME && -d $VESPA_HOME ) {
+ my $common_env = $VESPA_HOME . "/" . $COMMON_ENV;
+ return $VESPA_HOME if -f $common_env;
+ }
+ return 0;
+}
+
+# Returns the home of Vespa, or dies if it cannot
+sub findhome {
+ # Try the VESPA_HOME env variable
+ return $ENV{'VESPA_HOME'} if is_vespa_home($ENV{'VESPA_HOME'});
+ if ( $ENV{'VESPA_HOME'} ) { # was set, but not correctly
+ die "FATAL: bad VESPA_HOME value '" . $ENV{'VESPA_HOME'} . "'\n";
+ }
+
+ # Try the ROOT env variable
+ $ROOT = $ENV{'ROOT'};
+ return $ROOT if is_vespa_home($ROOT);
+
+ # Try the script location or current dir
+ my $mypath = findpath();
+ if ($mypath) {
+ while ( $mypath =~ s|/[^/]*$|| ) {
+ return $mypath if is_vespa_home($mypath);
+ }
+ }
+ die "FATAL: Missing VESPA_HOME environment variable\n";
+}
+
+BEGIN {
+ my $tmp = findhome();
+ if ( $tmp !~ m{[/]$} ) { $tmp .= "/"; }
+ $ENV{'VESPA_HOME'} = $tmp;
+}
+my $VESPA_HOME = $ENV{'VESPA_HOME'};
+
+# END perl environment bootstrap section
+
+use 5.006_001;
+use strict;
+use warnings;
+
+use Getopt::Long qw(:config no_ignore_case);
+
+my %showflags = (
+ time => 1,
+ fmttime => 1,
+ msecs => 1,
+ usecs => 0,
+ host => 0,
+ level => 1,
+ pid => 0,
+ service => 1,
+ component => 1,
+ message => 1
+);
+
+my %levelflags = (
+ fatal => 1,
+ error => 1,
+ warning => 1,
+ info => 1,
+ config => 0,
+ event => 0,
+ debug => 0,
+ spam => 0
+);
+
+# Do not buffer the output
+$| = 1;
+
+my $compore;
+my $msgtxre;
+my $onlypid;
+my $onlysvc;
+my $onlyhst;
+
+my $shortsvc;
+my $shortcmp;
+
+my @optlevels;
+my @optshow;
+my $optlevels;
+my $optfollow;
+my $optnldequote;
+my $optreplication;
+my $opthelp = '';
+
+my $bad = 0;
+
+GetOptions ('level|l=s' => \@optlevels,
+ 'service|S=s' => \$onlysvc,
+ 'show|s=s' => \@optshow,
+ 'pid|p=s' => \$onlypid,
+ 'component|c=s' => \$compore,
+ 'message|m=s' => \$msgtxre,
+ 'help|h' => \$opthelp,
+ 'follow|f' => \$optfollow,
+ 'livestream|L' => \$optreplication,
+ 'nldequote|N' => \$optnldequote,
+ 'host|H=s' => \$onlyhst,
+ 'truncateservice|ts' => \$shortsvc,
+ 'truncatecomponent|tc|t' => \$shortcmp,
+) or $bad=1;
+
+if ( $optreplication ) {
+ open(STDIN, "vespa-replicate-log-stream |");
+ $showflags{'host'} = 1;
+} elsif ( @ARGV == 0 and ! -p STDIN) {
+ push(@ARGV, "$VESPA_HOME/logs/vespa/vespa.log");
+}
+
+if ( $optfollow ) {
+ my $filearg = "";
+ if ( @ARGV > 1 ) {
+ print STDERR "ERROR: Cannot follow more than one file\n\n";
+ $bad=1;
+ } else {
+ $filearg = shift @ARGV if (@ARGV > 0);
+ open(STDIN, "tail -F $filearg |")
+ or die "cannot open 'tail -F $filearg' as input pipe\n";
+ }
+}
+
+if ( $opthelp || $bad ) {
+ print STDERR "Usage: $0 [options] [inputfile ...]\n",
+ "Options:\n",
+ " -l LEVELLIST\t--level=LEVELLIST\tselect levels to include\n",
+ " -s FIELDLIST\t--show=FIELDLIST\tselect fields to print\n",
+ " -p PID\t--pid=PID\t\tselect messages from given PID\n",
+ " -S SERVICE\t--service=SERVICE\tselect messages from given SERVICE\n",
+ " -H HOST\t--host=HOST\t\tselect messages from given HOST\n",
+ " -c REGEX\t--component=REGEX\tselect components matching REGEX\n",
+ " -m REGEX\t--message=REGEX\t\tselect message text matching REGEX\n",
+ " -f\t\t--follow\t\tinvoke tail -F to follow input file\n",
+ " -L\t\t--livestream\t\tfollow log stream from logserver\n",
+ " -N\t\t--nldequote\t\tdequote newlines in message text field\n",
+ " -t\t--tc\t--truncatecomponent\tchop component to 15 chars\n",
+ " --ts\t\t--truncateservice\tchop service to 9 chars\n",
+ "\n",
+ "FIELDLIST is comma separated, available fields:\n",
+ "\t time fmttime msecs usecs host level pid service component message\n",
+ "Available levels for LEVELLIST:\n",
+ "\t fatal error warning info event debug spam\n",
+ "for both lists, use 'all' for all possible values, and -xxx to disable xxx.\n";
+ exit $bad;
+}
+
+
+$optlevels = join(",", @optlevels );
+if ( $optlevels ) {
+ my $k;
+ unless ( $optlevels =~ s/^\+// or $optlevels =~ m/^-/ ) {
+ $levelflags{$_} = 0 foreach ( keys %levelflags );
+ }
+ my @l = split(/,|(?=-)/, $optlevels);
+ my $l;
+ foreach $l ( @l ) {
+ my $v = 1;
+ my $minus = "";
+ if ( $l =~ s/^-// ) { $v = 0; $minus = "-"; }
+ if ( $l eq "all" ) {
+ foreach $k ( keys %levelflags ) {
+ $levelflags{$k} = $v;
+ }
+ } elsif ( defined $levelflags{$l} ) {
+ $levelflags{$l} = $v;
+ } else {
+ print STDERR "bad level option '$minus$l'\n";
+ exit 1;
+ }
+ }
+# print STDERR "select level $_ => $levelflags{$_}\n"
+# foreach ( keys %levelflags );
+}
+
+my $optshow;
+$optshow = join(",", @optshow );
+if ( $optshow ) {
+ my $k;
+ unless ( $optshow =~ s/^\+// or $optshow =~ m/^-/ ) {
+ $showflags{$_} = 0 foreach ( keys %showflags );
+ }
+ my @l = split(/,|(?=-)/, $optshow);
+ my $l;
+ foreach $l ( @l ) {
+ my $v = 1;
+ my $minus = "";
+ if ( $l =~ s/^-// ) { $v = 0; $minus = "-"; }
+ if ( $l eq "all" ) {
+ foreach $k ( keys %showflags ) {
+ $showflags{$k} = $v;
+ }
+ } elsif ( defined $showflags{$l} ) {
+ $showflags{$l} = $v;
+ } else {
+ print STDERR "bad show option '$minus$l'\n";
+ exit 1;
+ }
+ }
+# print STDERR "show field $_ => $showflags{$_}\n"
+# foreach ( keys %showflags ) ;
+}
+
+while (<>) {
+ chomp;
+ if ( /^
+ (\d+)\.?(\d*) # seconds, optional fractional seconds
+ \t
+ ([^\t]*) # host
+ \t
+ (\d+\/?\d*|\-\/\d+) # pid, optional tid
+ \t
+ ([^\t]*) # servicename
+ \t
+ ([^\t]*) # componentname
+ \t
+ (\w+) # level
+ \t
+ (.*) # message text
+ $/x )
+ {
+ my $secs = $1;
+ my $usec = $2 . "000000"; # make sure we have atleast 6 digits
+ my $host = $3;
+ my $pidn = $4;
+ my $svcn = $5;
+ my $comp = $6;
+ my $levl = $7;
+ my $msgt = $8;
+
+ if ( ! defined $levelflags{$levl} ) {
+ print STDERR "Warning: unknown level '$levl' in input\n";
+ $levelflags{$levl} = 1;
+ }
+ next unless ( $levelflags{$levl} );
+
+ if ($compore && $comp !~ m/$compore/o) { next; }
+ if ($msgtxre && $msgt !~ m/$msgtxre/o) { next; }
+ if ($onlypid && $pidn ne $onlypid) { next; }
+ if ($onlysvc && $svcn ne $onlysvc) { next; }
+ if ($onlyhst && $host ne $onlyhst) { next; }
+
+ $levl = "\U$levl";
+
+ my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday);
+ ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday)=localtime($secs);
+ my $datestr = sprintf("%04d-%02d-%02d",
+ 1900+$year, 1+$mon, $mday);
+ my $timestr = sprintf("%02d:%02d:%02d",
+ $hour, $min, $sec);
+
+ if ( $showflags{"time"} || $showflags{"fmttime"} ) {
+ if ($showflags{"fmttime"} ) {
+ print "[$datestr $timestr";
+ if ( $showflags{"usecs"} ) {
+ printf ".%.6s", $usec;
+ } elsif ( $showflags{"msecs"} ) {
+ printf ".%.3s", $usec;
+ }
+ print "] ";
+ } else {
+ printf "%s.%.6s ", $secs, $usec;
+ }
+ }
+ if ( $showflags{"host"} ) {
+ printf "%-8s ", $host;
+ }
+ if ( $showflags{"level"} ) {
+ printf "%-7s : ", $levl;
+ }
+ if ( $showflags{"pid"} ) {
+ printf "%5s ", $pidn;
+ }
+ if ( $showflags{"service"} ) {
+ if ( $shortsvc ) {
+ printf "%-9.9s ", $svcn;
+ } else {
+ printf "%-16s ", $svcn;
+ }
+ }
+ if ( $showflags{"component"} ) {
+ if ( $shortcmp ) {
+ printf "%-15.15s ", $comp;
+ } else {
+ printf "%s\t", $comp;
+ }
+ }
+ if ( $showflags{"message"} ) {
+ if ( $optnldequote ) {
+ my $did_dequote_1 = ( $msgt =~ s/\\n\\t/\n\t/g );
+ my $did_dequote_2 = ( $msgt =~ s/\\n/\n\t/g );
+ $msgt = "\n\t${msgt}" if ( $did_dequote_1 || $did_dequote_2 );
+ $msgt =~ s/\\t/\t/;
+ }
+ print $msgt;
+ }
+ print "\n";
+ } else {
+ print STDERR "bad log line: '$_'\n";
+ }
+}