.*)$/);
if(!$prival && !$version && !$host && !$ident && !$content) {
$err = 1;
Log2Syslog_Log3slog ($hash, 2, "Log2Syslog $name - error parse msg -> $data");
} else {
$date = "$date $time";
$content =~ s/^:?(.*)$/$1/ if(lc($mid) eq "fhem"); # Modul Sender setzt vor $content ein ":" (wegen Synology Compatibilität)
$fac = int($prival/8);
$sev = $prival-($fac*8);
$facility = $Log2Syslog_Facility{$fac};
$severity = $Log2Syslog_Severity{$sev};
# Längenbegrenzung nach RFC5424
$ident = substr($ident,0, ($RFC5425len{ID}-1));
$pid = substr($pid,0, ($RFC5425len{PID}-1));
$mid = substr($mid,0, ($RFC5425len{MID}-1));
$host = substr($host,0, ($RFC5425len{HST}-1));
Log2Syslog_Log3slog($name, 4, "$name - parsed message -> FACILITY: $fac/$facility, SEVERITY: $sev/$severity, VERSION: $version, DATE: $date, HOST: $host, ID: $ident, PID: $pid, MID: $mid, SDFIELD: $sdfield, CONT: $content");
$pl = "$phost: FAC: $facility || SEV: $severity || ID: $ident || CONT: $content"; # $host wird zum Reading im Event -> positiv für Logging
}
} elsif ($pp =~ /raw/) {
Log2Syslog_Log3slog($name, 4, "$name - $data");
$pl = "$phost: $data";
}
return ($err,$pl);
}
if(AttrVal($name, "TLS", 0)) {
# wenn Transport Layer Security (TLS) -> Transport Mapping for Syslog https://tools.ietf.org/pdf/rfc5425.pdf
}
}
#################################################################################################
# Syslog Collector Events erzeugen
# (im Collector Model)
#################################################################################################
sub Log2Syslog_Trigger($$$) {
my ($hash,$date,$pl) = @_;
my $name = $hash->{NAME};
my $no_replace = 1; # Ersetzung von Events durch das Attribut eventMap verhindern
if($hash->{CHANGED}) {
push @{$hash->{CHANGED}}, $pl;
} else {
$hash->{CHANGED}[0] = $pl;
}
if($hash->{CHANGETIME}) {
push @{$hash->{CHANGETIME}}, $date;
} else {
$hash->{CHANGETIME}[0] = $date;
}
my $ret = DoTrigger($name, undef, $no_replace);
return;
}
###############################################################################
# Undef Funktion
###############################################################################
sub Log2Syslog_Undef($$) {
my ($hash, $name) = @_;
RemoveInternalTimer($hash);
if($hash->{MODEL} =~ /Collector/) {
Log2Syslog_downServer($hash);
}
return undef;
}
###############################################################################
# Collector-Socket schließen
###############################################################################
sub Log2Syslog_downServer($) {
my ($hash) = @_;
my $name = $hash->{NAME};
my $port = $hash->{PORT};
my $protocol = $hash->{PROTOCOL};
return if(!$hash->{SERVERSOCKET});
Log3 $hash, 3, "Log2Syslog $name - Closing socket $protocol/$port ...";
my $ret = $hash->{SERVERSOCKET}->close();
Log3 $hash, 1, "Log2Syslog $name - Can't close Syslog Collector at port $port: $!" if(!$ret);
delete($hash->{SERVERSOCKET});
delete($selectlist{"$name.$port"});
delete($readyfnlist{"$name.$port"});
delete($hash->{FD});
return;
}
###############################################################################
# Delete Funktion
###############################################################################
sub Log2Syslog_Delete($$) {
my ($hash, $arg) = @_;
delete $logInform{$hash->{NAME}};
return undef;
}
###############################################################################
# Get
###############################################################################
sub Log2Syslog_Get($@) {
my ($hash, @a) = @_;
return "\"get X\" needs at least an argument" if ( @a < 2 );
my $name = $a[0];
my $opt = $a[1];
my $prop = $a[2];
my $getlist = "Unknown argument $opt, choose one of ".
"certinfo:noArg "
;
return if(IsDisabled($name));
my($sock,$cert,@certs);
if ($opt =~ /certinfo/) {
if(ReadingsVal($name,"SSL_Version","n.a.") ne "n.a.") {
$sock = Log2Syslog_setsock($hash);
if(defined($sock)) {
$cert = $sock->dump_peer_certificate();
Log2Syslog_closesock($hash,$sock);
}
}
return $cert if($cert);
return "no SSL session has been created";
} else {
return "$getlist";
}
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 ($aName eq "TLS") {
if($cmd eq "set") {
return "\"$aName\" is only valid for model \"Sender\"" if($hash->{MODEL} =~ /Collector/);
$do = ($aVal) ? 1 : 0;
}
$do = 0 if($cmd eq "del");
if ($do == 0) {
$hash->{HELPER}{SSLVER} = "n.a.";
$hash->{HELPER}{SSLALGO} = "n.a.";
readingsSingleUpdate($hash, "SSL_Version", "n.a.", 1);
readingsSingleUpdate($hash, "SSL_Algorithm", "n.a.", 1);
}
}
if ($aName eq "rateCalcRerun") {
RemoveInternalTimer($hash, "Log2Syslog_trate");
InternalTimer(gettimeofday()+5, "Log2Syslog_trate", $hash, 0);
}
if ($cmd eq "set" && $aName =~ /port|timeout|rateCalcRerun/) {
return "\"$aName\" is only valid for model \"Sender\"" if($hash->{MODEL} =~ /Collector/ && $aName =~ /timeout/);
if($aVal !~ m/^\d+$/) { return " The Value of \"$aName\" is not valid. Use only figures !";}
if($aName =~ /port/ && $hash->{MODEL} =~ /Collector/ && $init_done == 1) {
return "$aName \"$aVal\" is not valid because privileged ports are only usable by super users. Use a port grater than 1023." if($aVal < 1024);
Log2Syslog_downServer($hash);
RemoveInternalTimer($hash, "Log2Syslog_initServer");
InternalTimer(gettimeofday()+1.5, "Log2Syslog_initServer", "$name,global", 0);
}
}
if ($cmd eq "set" && $hash->{MODEL} =~ /Collector/ && $aName =~ /logFormat/ && $init_done == 1) {
Log2Syslog_downServer($hash);
RemoveInternalTimer($hash, "Log2Syslog_initServer");
InternalTimer(gettimeofday()+1.5, "Log2Syslog_initServer", "$name,global", 0);
}
if ($cmd eq "set" && $hash->{MODEL} =~ /Collector/ && $aName =~ /addTimestamp|addStateEvent|protocol/) {
return "\"$aName\" is only valid for model \"Sender\"";
}
return undef;
}
#################################################################################
# Eventlogging
#################################################################################
sub Log2Syslog_eventlog($$) {
# $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,$data,$pid);
return if(IsDisabled($name) || !$rex || $hash->{MODEL} !~ /Sender/);
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};
$sock = Log2Syslog_setsock($hash);
if(defined($sock)) {
for (my $i = 0; $i < $max; $i++) {
my $txt = $events->[$i];
$txt = "" if(!defined($txt));
$txt = Log2Syslog_charfilter($hash,$txt);
my $tim = (($ct && $ct->[$i]) ? $ct->[$i] : $tn);
my ($date,$time) = split(" ",$tim);
if($n =~ m/^$rex$/ || "$n:$txt" =~ m/^$rex$/ || "$tim:$n:$txt" =~ m/^$rex$/) {
my $otp = "$n $txt";
$otp = "$tim $otp" if AttrVal($name,'addTimestamp',0);
$prival = Log2Syslog_setprival($txt);
($data,$pid) = Log2Syslog_setpayload($hash,$prival,$date,$time,$otp,"event");
next if(!$data);
my $ret = syswrite $sock, $data."\n";
if($ret && $ret > 0) {
Log2Syslog_Log3slog($name, 4, "$name - Payload sequence $pid sent\n");
} else {
my $err = $!;
Log2Syslog_Log3slog($name, 4, "$name - Warning - Payload sequence $pid NOT sent: $err\n");
my $st = "write error: $err";
my $evt = ($st eq $hash->{HELPER}{OLDSTATE})?0:1;
readingsSingleUpdate($hash, "state", $st, $evt);
$hash->{HELPER}{OLDSTATE} = $st;
}
}
}
Log2Syslog_closesock($hash,$sock);
}
return "";
}
#################################################################################
# FHEM system logging
#################################################################################
sub Log2Syslog_fhemlog($$) {
my ($name,$raw) = @_;
my $hash = $defs{$name};
my $rex = $hash->{HELPER}{FHEMLOG};
my ($prival,$sock,$err,$ret,$data,$pid);
return if(IsDisabled($name) || !$rex || $hash->{MODEL} !~ /Sender/);
my ($date,$time,$vbose,undef,$txt) = split(" ",$raw,5);
$txt = Log2Syslog_charfilter($hash,$txt);
$date =~ s/\./-/g;
my $tim = $date." ".$time;
if($txt =~ m/^$rex$/ || "$vbose: $txt" =~ m/^$rex$/) {
my $otp = "$vbose: $txt";
$otp = "$tim $otp" if AttrVal($name,'addTimestamp',0);
$prival = Log2Syslog_setprival($txt,$vbose);
($data,$pid) = Log2Syslog_setpayload($hash,$prival,$date,$time,$otp,"fhem");
return if(!$data);
$sock = Log2Syslog_setsock($hash);
if (defined($sock)) {
$ret = syswrite $sock, $data."\n" if($data);
if($ret && $ret > 0) {
Log2Syslog_Log3slog($name, 4, "$name - Payload sequence $pid sent\n");
} else {
my $err = $!;
Log2Syslog_Log3slog($name, 4, "$name - Warning - Payload sequence $pid NOT sent: $err\n");
my $st = "write error: $err";
my $evt = ($st eq $hash->{HELPER}{OLDSTATE})?0:1;
readingsSingleUpdate($hash, "state", $st, $evt);
$hash->{HELPER}{OLDSTATE} = $st;
}
Log2Syslog_closesock($hash,$sock);
}
}
return;
}
###############################################################################
# Helper für ident & Regex setzen
###############################################################################
sub Log2Syslog_setidrex ($$) {
my ($hash,$a) = @_;
$hash->{HELPER}{EVNTLOG} = (split("event:",$a))[1] if(lc($a) =~ m/^event:.*/);
$hash->{HELPER}{FHEMLOG} = (split("fhem:",$a))[1] if(lc($a) =~ m/^fhem:.*/);
$hash->{HELPER}{IDENT} = (split("ident:",$a))[1] if(lc($a) =~ m/^ident:.*/);
return;
}
###############################################################################
# Zeichencodierung für Payload filtern
###############################################################################
sub Log2Syslog_charfilter ($$) {
my ($hash,$txt) = @_;
my $name = $hash->{NAME};
# nur erwünschte Zeichen in payload, ASCII %d32-126
$txt =~ s/ß/ss/g;
$txt =~ s/ä/ae/g;
$txt =~ s/ö/oe/g;
$txt =~ s/ü/ue/g;
$txt =~ s/Ä/Ae/g;
$txt =~ s/Ö/Oe/g;
$txt =~ s/Ü/Ue/g;
$txt =~ s/€/EUR/g;
$txt =~ tr/ A-Za-z0-9!"#$%&'()*+,-.\/:;<=>?@[\]^_`{|}~//cd;
return($txt);
}
###############################################################################
# erstelle Socket
###############################################################################
sub Log2Syslog_setsock ($) {
my ($hash) = @_;
my $name = $hash->{NAME};
my $host = $hash->{PEERHOST};
my $port = AttrVal($name, "TLS", 0)?AttrVal($name, "port", 6514):AttrVal($name, "port", 514);
my $protocol = lc(AttrVal($name, "protocol", "udp"));
my $st = "active";
my $timeout = AttrVal($name, "timeout", 0.5);
my $ssldbg = AttrVal($name, "ssldebug", 0);
my ($sock,$lo,$sslver,$sslalgo);
return undef if($init_done != 1 || $hash->{MODEL} !~ /Sender/);
if(AttrVal($name, "TLS", 0)) {
# TLS gesicherte Verbindung
# TLS Transport nach RFC5425 https://tools.ietf.org/pdf/rfc5425.pdf
$attr{$name}{protocol} = "TCP" if(AttrVal($name, "protocol", "UDP") ne "TCP");
$sslver = "n.a.";
$sslalgo = "n.a.";
eval "use IO::Socket::SSL";
if($@) {
$st = "$@";
} else {
$sock = IO::Socket::INET->new(PeerHost => $host, PeerPort => $port, Proto => 'tcp', Blocking => 0);
if (!$sock) {
$st = "unable open socket for $host, $protocol, $port: $!";
} else {
$sock->blocking(1);
$IO::Socket::SSL::DEBUG = $ssldbg;
eval { IO::Socket::SSL->start_SSL($sock,
SSL_verify_mode => 0,
SSL_version => "TLSv1_2:!TLSv1_1:!SSLv3:!SSLv23:!SSLv2",
SSL_hostname => $host,
SSL_veriycn_scheme => "rfc5425",
SSL_veriycn_publicsuffix => '',
Timeout => $timeout
) || undef $sock; };
$IO::Socket::SSL::DEBUG = 0;
if($@) {
$st = "SSL error: $@";
undef $sock;
} elsif (!$sock) {
$st = "SSL error: ".IO::Socket::SSL::errstr();
undef $sock;
} else {
$sslver = $sock->get_sslversion();
$sslalgo = $sock->get_fingerprint();
$sslalgo = (split("\\\$",$sslalgo))[0];
$lo = "Socket opened for Host: $host, Protocol: $protocol, Port: $port, TLS: 0";
$st = "active";
}
}
}
} else {
# erstellt ungesicherte Socket Verbindung
$sslver = "n.a.";
$sslalgo = "n.a.";
$sock = new IO::Socket::INET (PeerHost => $host, PeerPort => $port, Proto => $protocol, Timeout => $timeout );
if (!$sock) {
undef $sock;
$st = "unable open socket for $host, $protocol, $port: $!";
} else {
$sock->blocking(0);
# Logausgabe (nur in das fhem Logfile !)
$lo = "Socket opened for Host: $host, Protocol: $protocol, Port: $port, TLS: 0";
}
}
my $evt = ($st eq $hash->{HELPER}{OLDSTATE})?0:1;
readingsSingleUpdate($hash, "state", $st, $evt);
$hash->{HELPER}{OLDSTATE} = $st;
if($sslver ne $hash->{HELPER}{SSLVER}) {
readingsSingleUpdate($hash, "SSL_Version", $sslver, 1);
$hash->{HELPER}{SSLVER} = $sslver;
}
if($sslalgo ne $hash->{HELPER}{SSLALGO}) {
readingsSingleUpdate($hash, "SSL_Algorithm", $sslalgo, 1);
$hash->{HELPER}{SSLALGO} = $sslalgo;
}
Log2Syslog_Log3slog($name, 5, "$name - $lo") if($lo);
return($sock);
}
###############################################################################
# Socket schließen
###############################################################################
sub Log2Syslog_closesock($$) {
my ($hash,$sock) = @_;
shutdown($sock, 1);
if(AttrVal($hash->{NAME}, "TLS", 0)) {
$sock->close(SSL_no_shutdown => 1);
} else {
$sock->close();
}
return;
}
###############################################################################
# set PRIVAL (severity & facility)
###############################################################################
sub Log2Syslog_setprival ($;$$) {
my ($txt,$vbose) = @_;
my $prival;
# Priority = (facility * 8) + severity
# https://tools.ietf.org/pdf/rfc5424.pdf
# 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($txt) =~ m/error/); # error condition
$sv = 4 if (lc($txt) =~ m/warning/); # warning conditions
$prival = ($fac*8)+$sv;
return($prival);
}
###############################################################################
# erstellen Payload für Syslog
###############################################################################
sub Log2Syslog_setpayload ($$$$$$) {
my ($hash,$prival,$date,$time,$otp,$lt) = @_;
my $name = $hash->{NAME};
my $ident = ($hash->{HELPER}{IDENT}?$hash->{HELPER}{IDENT}:$name)."_".$lt;
my $myhost = $hash->{MYHOST}?$hash->{MYHOST}:"0.0.0.0";
my $lf = AttrVal($name, "logFormat", "IETF");
my $data;
return undef,undef if(!$otp);
my $pid = $hash->{SEQNO}; # PayloadID zur Nachverfolgung der Eventabfolge
$hash->{SEQNO}++;
my ($year,$month,$day) = split("-",$date);
if ($lf eq "BSD") {
# BSD Protokollformat https://tools.ietf.org/html/rfc3164
$time = (split(/\./,$time))[0] if($time =~ m/\./); # msec ist nicht erlaubt
$month = $Log2Syslog_BSDMonth{$month}; # Monatsmapping, z.B. 01 -> Jan
$day =~ s/0/ / if($day =~ m/^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 $ident: : $otp";
use warnings;
$data = substr($data,0, ($RFC3164len{DL}-1)); # Länge Total begrenzen
}
if ($lf eq "IETF") {
# IETF Protokollformat https://tools.ietf.org/html/rfc5424
my $IETFver = 1; # Version von syslog Protokoll Spec RFC5424
my $mid = "FHEM"; # message ID, identify protocol of message, e.g. for firewall filter
my $tim = $date."T".$time;
my $sdfield = "[version\@Log2Syslog version=\"$hash->{VERSION}\"]";
$otp = Encode::encode_utf8($otp);
# Längenbegrenzung nach RFC5424
$ident = substr($ident,0, ($RFC5425len{ID}-1));
$pid = substr($pid,0, ($RFC5425len{PID}-1));
$mid = substr($mid,0, ($RFC5425len{MID}-1));
$myhost = substr($myhost,0, ($RFC5425len{HST}-1));
no warnings 'uninitialized';
if ($IETFver == 1) {
$data = "<$prival>$IETFver $tim $myhost $ident $pid $mid $sdfield :$otp";
}
use warnings;
}
if($data =~ /\s$/){$data =~ s/\s$//;}
my $dl = length($data); # Länge muss ! für TLS stimmen, sonst keine Ausgabe !
# wenn Transport Layer Security (TLS) -> Transport Mapping for Syslog https://tools.ietf.org/pdf/rfc5425.pdf
if(AttrVal($name, "TLS", 0)) {
$data = "$dl $data";
$data = substr($data,0, ($RFC5425len{DL}-1)); # Länge Total begrenzen
Log2Syslog_Log3slog($name, 4, "$name - SSL-Payload created with length: ".(($dl>($RFC5425len{DL}-1))?($RFC5425len{DL}-1):$dl) );
}
my $ldat = ($dl>130)?(substr($data,0, 130)." ..."):$data;
Log2Syslog_Log3slog($name, 4, "$name - Payload sequence $pid created:\n$ldat");
return($data,$pid);
}
###############################################################################
# eigene Log3-Ableitung - Schleife vermeiden
###############################################################################
sub Log2Syslog_Log3slog($$$) {
my ($dev, $loglevel, $text) = @_;
our ($logopened,$currlogfile);
$dev = $dev->{NAME} if(defined($dev) && ref($dev) eq "HASH");
if(defined($dev) &&
defined($attr{$dev}) &&
defined (my $devlevel = $attr{$dev}{verbose})) {
return if($loglevel > $devlevel);
} else {
return if($loglevel > $attr{global}{verbose});
}
my ($seconds, $microseconds) = gettimeofday();
my @t = localtime($seconds);
my $nfile = ResolveDateWildcards($attr{global}{logfile}, @t);
OpenLogfile($nfile) if(!$currlogfile || $currlogfile ne $nfile);
my $tim = sprintf("%04d.%02d.%02d %02d:%02d:%02d",
$t[5]+1900,$t[4]+1,$t[3], $t[2],$t[1],$t[0]);
if($attr{global}{mseclog}) {
$tim .= sprintf(".%03d", $microseconds/1000);
}
if($logopened) {
print LOG "$tim $loglevel: $text\n";
} else {
print "$tim $loglevel: $text\n";
}
return undef;
}
###############################################################################
# Bestimmung Übertragungsrate
###############################################################################
sub Log2Syslog_trate($) {
my ($hash) = @_;
my $name = $hash->{NAME};
my $rerun = AttrVal($name, "rateCalcRerun", 60);
if ($hash->{HELPER}{LTIME}+60 <= time()) {
my $div = (time()-$hash->{HELPER}{LTIME})/60;
my $spm = sprintf "%.0f", ($hash->{SEQNO} - $hash->{HELPER}{OLDSEQNO})/$div;
$hash->{HELPER}{OLDSEQNO} = $hash->{SEQNO};
$hash->{HELPER}{LTIME} = time();
my $ospm = ReadingsVal($name, "Transfered_logs_per_minute", 0);
if($spm != $ospm) {
readingsSingleUpdate($hash, "Transfered_logs_per_minute", $spm, 1);
} else {
readingsSingleUpdate($hash, "Transfered_logs_per_minute", $spm, 0);
}
}
RemoveInternalTimer($hash, "Log2Syslog_trate");
InternalTimer(gettimeofday()+$rerun, "Log2Syslog_trate", $hash, 0);
return;
}
###############################################################################
# Peer IP-Adresse und Host ermitteln (Sender der Message)
###############################################################################
sub Log2Syslog_evalPeer($) {
my ($hash) = @_;
my $name = $hash->{NAME};
my $socket = $hash->{SERVERSOCKET};
my($pport, $pipaddr) = sockaddr_in($socket->peername);
my $phost = gethostbyaddr($pipaddr, AF_INET);
my $paddr = inet_ntoa($pipaddr);
Log2Syslog_Log3slog ($hash, 5, "Log2Syslog $name - message peerhost: $phost, $paddr");
return ($phost,$paddr);
}
1;
=pod
=item helper
=item summary forwards FHEM system logs and/or events to a syslog server or act as an syslog server itself
=item summary_DE sendet FHEM Systemlogs und/oder Events an einen Syslog-Server bzw. agiert selbst als Syslog-Server
=begin html
Log2Syslog
Send FHEM system log entries and/or FHEM events to an external syslog server.
The syslog protocol has been implemented according the specifications of RFC5424 (IETF),
RFC3164 (BSD) and the TLS transport protocol according to
RFC5425.
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> [ident:<ident>] [event:<regexp>] [fhem:<regexp>]
<destination host> = host where the syslog server is running
[ident:<ident>] = optional program identifier. If not set the device name will be used as default
[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.
The verbose level of FHEM system logs will convert into equivalent syslog severity level.
Thurthermore the message text will be scanned for signal terms "warning" and "error" (with case insensitivity).
Dependent off the severity will be set equivalent as well. If a severity is already set by verbose level, it wil be overwritten
by the level according to the signal term found in the message text.
Lookup table Verbose-Level to Syslog severity level:
verbose-Level | Severity in Syslog |
0 | Critical |
1 | Error |
2 | Warning |
3 | Notice |
4 | Informational |
5 | Debug |
Example to log anything:
define splunklog Log2Syslog fhemtest 192.168.2.49 ident:Test event:.* fhem:.*
will produce output like this raw example of a splunk syslog server:
Aug 18 21:06:46 fhemtest.myds.me 1 2017-08-18T21:06:46 fhemtest.myds.me Test_event 13339 FHEM - : LogDB sql_processing_time: 0.2306
Aug 18 21:06:46 fhemtest.myds.me 1 2017-08-18T21:06:46 fhemtest.myds.me Test_event 13339 FHEM - : LogDB background_processing_time: 0.2397
Aug 18 21:06:45 fhemtest.myds.me 1 2017-08-18T21:06:45 fhemtest.myds.me Test_event 13339 FHEM - : LogDB CacheUsage: 21
Aug 18 21:08:27 fhemtest.myds.me 1 2017-08-18T21:08:27.760 fhemtest.myds.me Test_fhem 13339 FHEM - : 4: CamTER - Informations of camera Terrasse retrieved
Aug 18 21:08:27 fhemtest.myds.me 1 2017-08-18T21:08:27.095 fhemtest.myds.me Test_fhem 13339 FHEM - : 4: CamTER - CAMID already set - ignore get camid
The structure of the payload differs dependent of the used logFormat.
logFormat IETF:
"<PRIVAL>VERSION TIME MYHOST IDENT PID MID [SD-FIELD] :MESSAGE"
PRIVAL | priority value (coded from "facility" and "severity") |
TIME | timestamp according to RFC5424 |
MYHOST | Internal MYHOST |
IDENT | ident-Tag from DEF if set, or else the own device name. The statement will be completed by "_fhem" (FHEM-Log) respectively "_event" (Event-Log). |
PID | sequential Payload-ID |
MID | fix value "FHEM" |
MESSAGE | the dataset to transfer |
logFormat BSD:
"<PRIVAL>MONAT TAG TIME MYHOST IDENT: : MESSAGE"
PRIVAL | priority value (coded from "facility" and "severity") |
MONAT | month according to RFC3164 |
TAG | day of month according to RFC3164 |
TIME | timestamp according to RFC3164 |
MYHOST | Internal MYHOST |
IDENT | ident-Tag from DEF if set, or else the own device name. The statement will be completed by "_fhem" (FHEM-Log) respectively "_event" (Event-Log). |
MESSAGE | the dataset to transfer |
Get
certinfo
Show informations about the server certificate if a TLS-session was created (Reading "SSL_Version" isn't "n.a.").
Attributes
Readings
SSL_Algorithm | used SSL algorithm if SSL is enabled and active |
SSL_Version | the used TLS-version if encryption is enabled and is active |
Transfered_logs_per_minute | the average number of forwarded logs/events per minute |
=end html
=begin html_DE
Log2Syslog
Sendet das Modul FHEM Systemlog Einträge und/oder Events an einen externen Syslog-Server weiter oder agiert als
Syslog-Server um Syslog-Meldungen anderer Geräte zu empfangen.
Die Implementierung des Syslog-Protokolls erfolgte entsprechend den Vorgaben von RFC5424 (IETF),
RFC3164 (BSD) sowie dem TLS Transport Protokoll nach
RFC5425.
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
Je nach Verwendungszweck kann ein Syslog-Server (MODEL Collector) oder ein Syslog-Client (MODEL Sender) definiert
werden.
Der Collector empfängt Meldungen im Syslog-Format anderer Geräte und generiert daraus Events zur Weiterverarbeitung in
FHEM. Das Sender-Device leitet FHEM Systemlog Einträge und/oder Events an einen externen Syslog-Server weiter.
Definition eines Collectors
Die Definition ist sehr einfach und benötigt keine weiteren Parameter.
In der Grundeinstellung wird der Syslog-Server mit dem Port=1514/UDP Format=IETF initialisiert.
Mit dem Attribut "logFomat" kann alternativ das BSD-Format ausgewählt werden.
Der Syslog-Server ist sofort betriebsbereit und generiert aus den eingehenden Syslog-Meldungen FHEM-Events mit
entsprechender Adaption der RFC-Richtlinien (siehe dazu auch das Attribut "parseProfile").
Beispiel für einen Collector:
define SyslogServer Log2Syslog
Im Eventmonitor können die generierten Events kontrolliert werden (Beispiel mit Attribut parseProfile=default):
2018-07-31 17:07:24.382 Log2Syslog SyslogServer HOST: fhem.myds.me || FAC: syslog || SEV: Notice || ID: Prod_event || CONT: USV state: OL
2018-07-31 17:07:24.858 Log2Syslog SyslogServer HOST: fhem.myds.me || FAC: syslog || SEV: Notice || ID: Prod_event || CONT: HMLAN2 loadLvl: low
Zwischen den einzelnen Feldern wird der Trenner "||" verwendet.
Die Bedeutung der Felder ist in nachfolgender Tabelle aufgeführt.
HOST | der Sender des Datensatzes |
FAC | Facility (Kategorie) nach RFC5424 |
SEV | Severity (Schweregrad) nach RFC5424 |
ID | Ident-Tag |
CONT | die übertragene Nachricht |
Definition eines Senders
define <name> Log2Syslog <Zielhost> [ident:<ident>] [event:<regexp>] [fhem:<regexp>]
<Zielhost> | Host (Name oder IP-Adresse) auf dem der Syslog-Server läuft |
[ident:<ident>] | optionaler Programm Identifier. Wenn nicht gesetzt wird per default der Devicename benutzt. |
[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.
Die Verbose-Level der FHEM Systemlogs werden in entsprechende Schweregrade der Syslog-Messages umgewandelt.
Weiterhin wird der Meldungstext der FHEM Systemlogs und Events nach den Signalwörtern "warning" und "error" durchsucht
(Groß- /Kleinschreibung wird nicht beachtet). Davon abhängig wird der Schweregrad ebenfalls äquivalent gesetzt und übersteuert
einen eventuell bereits durch Verbose-Level gesetzten Schweregrad.
Umsetzungstabelle Verbose-Level in Syslog-Schweregrad Stufe:
Verbose-Level | Schweregrad in Syslog |
0 | Critical |
1 | Error |
2 | Warning |
3 | Notice |
4 | Informational |
5 | Debug |
Beispiel für einen Sender:
define splunklog Log2Syslog fhemtest 192.168.2.49 ident:Test event:.* fhem:.*
Es werden alle Events weitergeleitet wie deses Beispiel der raw-Ausgabe eines Splunk Syslog Servers zeigt:
Aug 18 21:06:46 fhemtest.myds.me 1 2017-08-18T21:06:46 fhemtest.myds.me Test_event 13339 FHEM - : LogDB sql_processing_time: 0.2306
Aug 18 21:06:46 fhemtest.myds.me 1 2017-08-18T21:06:46 fhemtest.myds.me Test_event 13339 FHEM - : LogDB background_processing_time: 0.2397
Aug 18 21:06:45 fhemtest.myds.me 1 2017-08-18T21:06:45 fhemtest.myds.me Test_event 13339 FHEM - : LogDB CacheUsage: 21
Aug 18 21:08:27 fhemtest.myds.me 1 2017-08-18T21:08:27.760 fhemtest.myds.me Test_fhem 13339 FHEM - : 4: CamTER - Informations of camera Terrasse retrieved
Aug 18 21:08:27 fhemtest.myds.me 1 2017-08-18T21:08:27.095 fhemtest.myds.me Test_fhem 13339 FHEM - : 4: CamTER - CAMID already set - ignore get camid
Der Aufbau der Payload unterscheidet sich je nach verwendeten logFormat.
logFormat IETF:
"<PRIVAL>VERSION TIME MYHOST IDENT PID MID [SD-FIELD] :MESSAGE"
PRIVAL | Priority Wert (kodiert aus "facility" und "severity") |
TIME | Timestamp nach RFC5424 |
MYHOST | Internal MYHOST |
IDENT | Ident-Tag aus DEF wenn angegeben, sonst der eigene Devicename. Die Angabe wird mit "_fhem" (FHEM-Log) bzw. "_event" (Event-Log) ergänzt. |
PID | fortlaufende Payload-ID |
MID | fester Wert "FHEM" |
MESSAGE | der zu übertragende Datensatz |
logFormat BSD:
"<PRIVAL>MONAT TAG TIME MYHOST IDENT: : MESSAGE"
PRIVAL | Priority Wert (kodiert aus "facility" und "severity") |
MONAT | Monatsangabe nach RFC3164 |
TAG | Tag des Monats nach RFC3164 |
TIME | Zeitangabe nach RFC3164 |
MYHOST | Internal MYHOST |
IDENT | Ident-Tag aus DEF wenn angegeben, sonst der eigene Devicename. Die Angabe wird mit "_fhem" (FHEM-Log) bzw. "_event" (Event-Log) ergänzt. |
MESSAGE | der zu übertragende Datensatz |
Get
certinfo
Zeigt Informationen zum Serverzertifikat wenn eine TLS-Session aufgebaut wurde (Reading "SSL_Version" ist nicht "n.a.").
Attribute
Readings
SSL_Algorithm | der verwendete SSL Algorithmus wenn SSL eingeschaltet und aktiv ist |
SSL_Version | die verwendete TLS-Version wenn die Verschlüsselung aktiv ist |
Transfered_logs_per_minute | die durchschnittliche Anzahl der übertragenen/empfangenen Logs/Events pro Minute |
=end html_DE
=cut