Lots of little improvements

master
Daniel Berteaud 6 years ago
parent 66599fc380
commit a8ed673353
  1. 83
      systemd-journal-gelf

@ -5,34 +5,51 @@ use strict;
use JSON; use JSON;
use LWP::UserAgent; use LWP::UserAgent;
use Encode qw(encode); use Encode qw(encode);
use Data::Dumper;
use Compress::Zlib; use Compress::Zlib;
use Getopt::Long; use Getopt::Long;
use YAML::Tiny; use YAML::Tiny;
my $config = '/etc/systemd/journal-gelf.yml';
my $conf = {}; my $conf = {};
my $cmd = {
config => '/etc/systemd/journal-gelf.yml'
};
GetOptions (
'c|config=s' => \$cmd->{config},
'state=s' => \$cmd->{state},
'compress!' => \$cmd->{compress},
'url=s' => \$cmd->{url},
'username=s' => \$cmd->{username},
'password=s' => \$cmd->{password}
);
# Open config file
if (-e $cmd->{config}) {
print "Reading config file " . $cmd->{config} . "\n";
my $yaml = YAML::Tiny->read( $cmd->{config} )
or die "Config file " . $cmd->{config} . " is invalid\n";
if (-e $config) {
print "Reading config file $config\n";
my $yaml = YAML::Tiny->read( $config ) or die "Config file $config is invalid\n";
if ( not $yaml->[0] ) { if ( not $yaml->[0] ) {
die "Config file $config is invalid\n" die "Config file " . $cmd->{config} . " is invalid\n";
} }
# File could be parsed, lets load
# settings in $conf
$conf = $yaml->[0]; $conf = $yaml->[0];
} else {
print "Config file " . $cmd->{config} . " does not exist, ignoring it\n";
} }
GetOptions ( # Command line override config file
'state=s' => \$conf->{state}, foreach ( keys %{ $cmd } ){
'compress!' => \$conf->{compress}, $conf->{$_} = $cmd->{$_} if ( $cmd->{$_} );
'url=s' => \$conf->{url}, }
'username=s' => \$conf->{username},
'password=s' => \$conf->{password}
);
# Set some defaults is missing
$conf->{state} //= '/var/lib/systemd-journal-gelf/state'; $conf->{state} //= '/var/lib/systemd-journal-gelf/state';
$conf->{compress} //= 1; $conf->{compress} //= 1;
# Now check config makes sens
if ( if (
not $conf->{url} or not $conf->{url} or
( $conf->{username} and not $conf->{password} ) or ( $conf->{username} and not $conf->{password} ) or
@ -45,9 +62,10 @@ if (
print "Starting the Systemd Journal GELF uploader daemon\n"; print "Starting the Systemd Journal GELF uploader daemon\n";
my $ua = LWP::UserAgent->new( my $ua = LWP::UserAgent->new(
# env_proxy => 1, env_proxy => 1,
keep_alive => 1 keep_alive => 1
); );
$ua->default_header( 'Content-Type' => 'application/json' ); $ua->default_header( 'Content-Type' => 'application/json' );
if ( $conf->{compress} ){ if ( $conf->{compress} ){
$ua->default_header( 'Accept-Encoding' => HTTP::Message::decodable ); $ua->default_header( 'Accept-Encoding' => HTTP::Message::decodable );
@ -72,6 +90,15 @@ if (-e $conf->{state}){
open JOURNAL, "/usr/bin/journalctl -f -o json$cursor_arg |"; open JOURNAL, "/usr/bin/journalctl -f -o json$cursor_arg |";
while ( my $entry = <JOURNAL> ){ while ( my $entry = <JOURNAL> ){
my $msg = from_json( $entry ); my $msg = from_json( $entry );
if ( not $msg ) {
# Oups, something is obviously wrong here
# journalctl didn't sent us valid JSON ?
print "Error parsing message ($msg) \n";
next;
}
# Build a basic GELF message
my $gelf = { my $gelf = {
version => 1.1, version => 1.1,
short_message => $msg->{MESSAGE}, short_message => $msg->{MESSAGE},
@ -79,6 +106,7 @@ while (my $entry = <JOURNAL>){
timestamp => int ( $msg->{__REALTIME_TIMESTAMP} / ( 1000 * 1000 ) ), timestamp => int ( $msg->{__REALTIME_TIMESTAMP} / ( 1000 * 1000 ) ),
level => $msg->{PRIORITY} level => $msg->{PRIORITY}
}; };
# Now lets look at the message. If it starts with gelf: we can split it and have further # Now lets look at the message. If it starts with gelf: we can split it and have further
# fields to send. I use this to handle httpd or nginx logs for example # fields to send. I use this to handle httpd or nginx logs for example
if ( $msg->{MESSAGE} =~ m/^gelf:([a-zA-Z\d]+=([^\|])\|?)+/ ){ if ( $msg->{MESSAGE} =~ m/^gelf:([a-zA-Z\d]+=([^\|])\|?)+/ ){
@ -88,10 +116,13 @@ while (my $entry = <JOURNAL>){
$gelf->{'_' . lc $key} = $val; $gelf->{'_' . lc $key} = $val;
} }
} }
# Add the other attributes to the gelf message, except thos already treated
foreach ( grep !/^MESSAGE|_HOSTNAME|__REALTIME_TIMESTAMP|PRIORITY$/, keys %$msg ){ foreach ( grep !/^MESSAGE|_HOSTNAME|__REALTIME_TIMESTAMP|PRIORITY$/, keys %$msg ){
my $key = lc (($_ =~ m/^_/) ? $_ : '_' . $_); $gelf->{$_} = $msg->{$_};
$gelf->{$key} = $msg->{$_};
} }
# Now, we'll try to POST this message
my $retry = 0; my $retry = 0;
my $resp; my $resp;
do { do {
@ -100,14 +131,28 @@ while (my $entry = <JOURNAL>){
$resp->code . " (" . $resp->message . "). Tring again in $retry seconds\n"; $resp->code . " (" . $resp->message . "). Tring again in $retry seconds\n";
sleep $retry; sleep $retry;
} }
$resp = $ua->post($conf->{url}, Content => Compress::Zlib::memGzip(encode('utf-8', to_json($gelf)))); $resp = $ua->post(
$conf->{url},
Content => Compress::Zlib::memGzip(
encode(
'utf-8',
to_json($gelf)
)
)
);
$retry = ($retry > 0) ? $retry * 2 : 1; $retry = ($retry > 0) ? $retry * 2 : 1;
} while ($resp->code != 202 and $retry < 600); } while (not $resp->is_success and $retry < 600);
if ($resp->code == 202){
# The message has been accepted, we can save the current cursor and
# continue
if ($resp->is_success){
open CURSOR, ">", $conf->{state}; open CURSOR, ">", $conf->{state};
print CURSOR $msg->{__CURSOR}; print CURSOR $msg->{__CURSOR};
close CURSOR close CURSOR
} else { } else {
# We can't upload our current message for
# too much time, no much left we can do, lets die and hope
# our service manager will restart us :-)
die "Error sending data to GELF server\n"; die "Error sending data to GELF server\n";
} }
} }

Loading…
Cancel
Save