] "
if(int(@a)-3 < 0);
delete($hash->{HELPER}{EVNTLOG});
delete($hash->{HELPER}{FHEMLOG});
if ($a[3]) {
$hash->{HELPER}{EVNTLOG} = (split("event:",$a[3]))[1] if(lc($a[3]) =~ m/^event:.*/);
$hash->{HELPER}{FHEMLOG} = (split("fhem:",$a[3]))[1] if(lc($a[3]) =~ m/^fhem:.*/);
}
if ($a[4]) {
$hash->{HELPER}{EVNTLOG} = (split("event:",$a[4]))[1] if(lc($a[4]) =~ m/^event:.*/);
$hash->{HELPER}{FHEMLOG} = (split("fhem:",$a[4]))[1] if(lc($a[4]) =~ m/^fhem:.*/);
}
return "Bad regexp: starting with *"
if((defined($hash->{HELPER}{EVNTLOG}) && $hash->{HELPER}{EVNTLOG} =~ m/^\*/) || (defined($hash->{HELPER}{FHEMLOG}) && $hash->{HELPER}{FHEMLOG} =~ m/^\*/));
eval { "Hallo" =~ m/^$hash->{HELPER}{EVNTLOG}$/ } if($hash->{HELPER}{EVNTLOG});
return "Bad regexp: $@" if($@);
eval { "Hallo" =~ m/^$hash->{HELPER}{FHEMLOG}$/ } if($hash->{HELPER}{FHEMLOG});
return "Bad regexp: $@" if($@);
$hash->{PEERHOST} = $a[2]; # Destination Host (Syslog Server)
$hash->{MYHOST} = hostfqdn (); # FQDN eigener Host
$hash->{HELPER}{PID} = $$; # PROCID in IETF
$hash->{VERSION} = $Log2SyslogVn;
$logInform{$hash->{NAME}} = "fhemlog_Log"; # Funktion die in hash %loginform für $name eingetragen wird
readingsSingleUpdate($hash, "state", "initialized", 1);
return undef;
}
sub Log2Syslog_Undef($$) {
my ($hash, $name) = @_;
return undef;
}
sub Log2Syslog_Delete($$) {
my ($hash, $arg) = @_;
delete $logInform{$hash->{NAME}};
return undef;
}
################################################################
sub Log2Syslog_Attr {
my ($cmd,$name,$aName,$aVal) = @_;
my $hash = $defs{$name};
my $do;
# $cmd can be "del" or "set"
# $name is device name
# aName and aVal are Attribute name and value
if ($aName eq "disable") {
if($cmd eq "set") {
$do = ($aVal) ? 1 : 0;
}
$do = 0 if($cmd eq "del");
my $val = ($do == 1 ? "disabled" : "active");
readingsSingleUpdate($hash, "state", $val, 1);
}
if ($cmd eq "set" && $aName eq "port") {
if($aVal !~ m/^\d+$/) { return " The Value of \"$aName\" is not valid. Use only figures !";}
}
return undef;
}
#################################################################################
# Eventlogging
#################################################################################
sub event_Log($$) {
# $hash is my entry, $dev is the entry of the changed device
my ($hash,$dev) = @_;
my $name = $hash->{NAME};
my $rex = $hash->{HELPER}{EVNTLOG};
my ($prival,$sock);
return if(IsDisabled($name) || !$rex);
my $events = deviceEvents($dev, AttrVal($name, "addStateEvent", 0));
return if(!$events);
my $n = $dev->{NAME};
my $max = int(@{$events});
my $tn = $dev->{NTFY_TRIGGERTIME};
my $ct = $dev->{CHANGETIME};
for (my $i = 0; $i < $max; $i++) {
my $s = $events->[$i];
$s = "" if(!defined($s));
$s =~ tr/ A-Za-z0-9!"#$%&'()*+,-.\/:;<=>?@[\]^_`{|}~//cd; # nur erlaubte Zeichen in payload, ASCII %d32-126
my $tim = (($ct && $ct->[$i]) ? $ct->[$i] : $tn);
my ($date,$time) = split(" ",$tim);
if($n =~ m/^$rex$/ || "$n:$s" =~ m/^$rex$/ || "$tim:$n:$s" =~ m/^$rex$/) {
my $otp = "$n $s";
$otp = "$tim $otp" if AttrVal($name,'addTimestamp',0);
$prival = setprival($s);
my $data = setpayload($hash,$prival,$date,$time,$otp,"event");
$sock = setsock($hash);
if ($sock) {
eval {$sock->send($data);};
$sock->close();
}
}
}
return "";
}
#################################################################################
# FHEM system logging
#################################################################################
sub fhemlog_Log($$) {
my ($name,$raw) = @_;
my $hash = $defs{$name};
my $rex = $hash->{HELPER}{FHEMLOG};
my ($prival,$sock);
return if(IsDisabled($name) || !$rex);
my ($date,$time,$vbose,undef,$text) = split(" ",$raw,5);
$text =~ tr/ A-Za-z0-9!"#$%&'()*+,-.\/:;<=>?@[\]^_`{|}~//cd; # nur erlaubte Zeichen in payload, ASCII %d32-126
$date =~ s/\./-/g;
my $tim = $date." ".$time;
if($text =~ m/^$rex$/ || "$vbose: $text" =~ m/^$rex$/) {
my $otp = "$vbose: $text";
$otp = "$tim $otp" if AttrVal($name,'addTimestamp',0);
$prival = setprival($text,$vbose);
my $data = setpayload($hash,$prival,$date,$time,$otp,"fhem");
$sock = setsock($hash);
if ($sock) {
eval {$sock->send($data);};
$sock->close();
}
}
return;
}
###############################################################################
# create Socket
###############################################################################
sub setsock ($) {
my ($hash) = @_;
my $name = $hash->{NAME};
my $host = $hash->{PEERHOST};
my $port = AttrVal($name, "port", 514);
my $type = lc(AttrVal($name, "type", "udp"));
my $st = "active";
# Create Socket and check if successful
my $sock = new IO::Socket::INET (PeerHost => $host, PeerPort => $port, Proto => $type);
$st = "unable for open socket for $host, $type, $port" if (!$sock);
readingsSingleUpdate($hash, "state", $st, 1) if($st ne OldValue($name));
return($sock);
}
###############################################################################
# set PRIVAL (severity & facility)
###############################################################################
sub setprival ($;$$) {
my ($text,$vbose)= @_;
my $prival;
# Priority = (facility * 8) + severity
# https://tools.ietf.org/html/rfc5424
# determine facility
my $fac = 5; # facility by syslogd
# calculate severity
# mapping verbose level to severity
# 0: Critical -> 2
# 1: Error -> 3
# 2: Warning -> 4
# 3: Notice -> 5
# 4: Informational -> 6
# 5: Debug -> 7
my $sv = 5; # notice (default)
if ($vbose) {
# map verbose to severity
$sv = 2 if ($vbose == 0);
$sv = 3 if ($vbose == 1);
$sv = 4 if ($vbose == 2);
$sv = 5 if ($vbose == 3);
$sv = 6 if ($vbose == 4);
$sv = 7 if ($vbose == 5);
}
$sv = 3 if (lc($text) =~ m/error/); # error condition
$sv = 4 if (lc($text) =~ m/warning/); # warning conditions
$prival = ($fac*8)+$sv;
return($prival);
}
###############################################################################
# create Payload for Syslog
###############################################################################
sub setpayload ($$$$$$) {
my ($hash,$prival,$date,$time,$otp,$lt)= @_;
my $name = $hash->{NAME};
my $ident = $name."_".$lt;
my $myhost = $hash->{MYHOST}?$hash->{MYHOST}:"0.0.0.0";
my $lf = AttrVal($name, "logFormat", "IETF");
my $data;
my ($year,$month,$day) = split("-",$date);
if ($lf eq "BSD") {
# BSD Protokollformat https://tools.ietf.org/html/rfc3164
$time = (split(".",$time))[0]; # msec ist nicht erlaubt
$month = $Log2Syslog_BSDMonth{$month}; # Monatsmapping z.B. 01 -> Jan
$day =~ s/0/ /; # in Tagen < 10 muss 0 durch Space ersetzt werden
$ident = substr($ident,0, $RFC3164len{TAG}); # Länge TAG Feld begrenzen
no warnings 'uninitialized';
$data = "<$prival>$month $day $time $myhost TAG$ident: $otp";
use warnings;
$data = substr($data,0, $RFC3164len{DL}); # Länge Total begrenzen
}
if ($lf eq "IETF") {
# IETF Protokollformat https://tools.ietf.org/html/rfc5424
my $pid = $hash->{HELPER}{PID};
my $mid = "FHEM"; # message ID, identify type of message, e.g. for firewalls
my $tim = $date."T".$time;
no warnings 'uninitialized';
$data = "<$prival>1 $tim $myhost $ident $pid $mid - :$otp";
use warnings;
}
return($data);
}
1;
=pod
=item helper
=item summary send FHEM system logs and/or events to a syslog server.
=item summary_DE leitet FHEM Systemlogs und/oder Events an einen Syslog-Server weiter
=begin html
Log2Syslog
Send FHEM system log entries and/or FHEM events to an external syslog server.
Prerequisits
The additional perl module "IO::Socket::INET" must be installed on your system.
Install this package from cpan or by
apt-get install libio-socket-multicast-perl (only on Debian based installations)
Define
define <name> Log2Syslog <destination host> [event:<regexp>] [fhem:<regexp>]
<destination host> = host where the syslog server is running
[event:<regexp>] = optional regex to filter events for logging
[fhem:<regexp>] = optional regex to filter fhem system log for logging
After definition the new device sends all new appearing fhem systemlog entries and events to the destination host,
port=514/UDP format:IETF, immediately without further settings if the regex for fhem or event were set.
Without setting regex no fhem system log or event log will be forwarded.
Example to log anything:
define splunklog Log2Syslog fhemtest 192.168.2.49 event:.* fhem:.*
will produce output like:
Mar 20 15:25:22 fhem-vm-8 fhem: global: SAVE
Mar 20 15:25:44 fhem-vm-8 fhem: global: SHUTDOWN
Mar 20 15:25:57 fhem-vm-8 fhem: global: INITIALIZED
Mar 20 15:26:05 fhem-vm-8 fhem: PegelCux: Niedrigwasser-1: 20.03.2016 18:03
Mar 20 15:26:05 fhem-vm-8 fhem: PegelCux: Hochwasser-1: 20.03.2016 23:45
Attributes
=end html
=begin html_DE
Log2Syslog
Sendet FHEM Systemlog Einträge und/oder Events an einen externen Syslog-Server weiter.
Voraussetzungen
Es wird das Perl Modul "IO::Socket::INET" benötigt und muss installiert sein.
Das Modul kann über CPAN oder mit
apt-get install libio-socket-multicast-perl (auf Debian Linux Systemen)
installiert werden.
Definition
define <name> Log2Syslog <destination host> [event:<regexp>] [fhem:<regexp>]
<Zielhost> = Host (Name oder IP-Adresse) auf dem der Syslog-Server läuft
[event:<regexp>] = optionaler regulärer Ausdruck zur Filterung von Events zur Weiterleitung
[fhem:<regexp>] = optionaler regulärer Ausdruck zur Filterung von FHEM Logs zur Weiterleitung
Direkt nach der Definition sendet das neue Device alle neu auftretenden FHEM Systemlog Einträge und Events ohne weitere
Einstellungen an den Zielhost, Port=514/UDP Format:IETF, wenn reguläre Ausdrücke für Events/FHEM angegeben wurden.
Wurde kein Regex gesetzt, erfolgt keine Weiterleitung von Events oder FHEM Systemlogs.
Beispiel:
define splunklog Log2Syslog fhemtest 192.168.2.49
Es werden alle Events weitergeleitet:
Mar 20 15:25:22 fhem-vm-8 fhem: global: SAVE
Mar 20 15:25:44 fhem-vm-8 fhem: global: SHUTDOWN
Mar 20 15:25:57 fhem-vm-8 fhem: global: INITIALIZED
Mar 20 15:26:05 fhem-vm-8 fhem: PegelCux: Niedrigwasser-1: 20.03.2016 18:03
Mar 20 15:26:05 fhem-vm-8 fhem: PegelCux: Hochwasser-1: 20.03.2016 23:45
Attribute
=end html_DE
=cut