From de337dcba28ed7934b3da02cf1e22348d14dba5c Mon Sep 17 00:00:00 2001 From: nasseeder1 Date: Fri, 15 May 2020 15:55:36 +0000 Subject: [PATCH] 93_Log2Syslog: contrib git-svn-id: https://svn.fhem.de/fhem/trunk@21945 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/contrib/DS_Starter/93_Log2Syslog.pm | 914 +++++++++++++---------- 1 file changed, 518 insertions(+), 396 deletions(-) diff --git a/fhem/contrib/DS_Starter/93_Log2Syslog.pm b/fhem/contrib/DS_Starter/93_Log2Syslog.pm index c72ad5e69..b43c9a970 100644 --- a/fhem/contrib/DS_Starter/93_Log2Syslog.pm +++ b/fhem/contrib/DS_Starter/93_Log2Syslog.pm @@ -1,5 +1,5 @@ ########################################################################################################################## -# $Id: 93_Log2Syslog.pm 21611 2020-04-05 21:00:33Z DS_Starter $ +# $Id: 93_Log2Syslog.pm 21923 2020-05-12 20:00:24Z DS_Starter $ ########################################################################################################################## # 93_Log2Syslog.pm # @@ -31,19 +31,87 @@ # RFC 6587 Transmission of Syslog Messages over TCP # ########################################################################################################################## -package main; +package FHEM::Log2Syslog; ## no critic 'package' use strict; use warnings; use TcpServerUtils; +use POSIX; use Scalar::Util qw(looks_like_number); +use Time::HiRes qw(gettimeofday); use Encode qw(encode_utf8 decode_utf8); -eval "use IO::Socket::INET;1" or my $MissModulSocket = "IO::Socket::INET"; ## no critic -eval "use Net::Domain qw(hostname hostfqdn hostdomain domainname);1" or my $MissModulNDom = "Net::Domain"; ## no critic -eval "use FHEM::Meta;1" or my $modMetaAbsent = 1; ## no critic +eval "use IO::Socket::INET;1" or my $MissModulSocket = "IO::Socket::INET"; ## no critic 'eval' +eval "use Net::Domain qw(hostname hostfqdn hostdomain domainname);1" or my $MissModulNDom = "Net::Domain"; ## no critic 'eval' +eval "use FHEM::Meta;1" or my $modMetaAbsent = 1; ## no critic 'eval' +use GPUtils qw(GP_Import GP_Export); + +# Run before module compilation +BEGIN { + # Import from main:: + GP_Import( + qw( + attr + AttrVal + currlogfile + CommandDelete + defs + deviceEvents + devspec2array + DoTrigger + fhemTimeLocal + fhemTzOffset + init_done + InternalTimer + IsDisabled + logInform + logopened + Log3 + modules + notifyRegexpChanged + OpenLogfile + perlSyntaxCheck + readyfnlist + readingFnAttributes + RemoveInternalTimer + readingsBeginUpdate + readingsBulkUpdate + readingsEndUpdate + readingsSingleUpdate + ReadingsVal + ResolveDateWildcards + selectlist + sortTopicNum + TcpServer_Open + TcpServer_Accept + TcpServer_Close + TcpServer_SetSSL + TimeNow + ) + ); + + # Export to main context with different name + # my $pkg = caller(0); + # my $main = $pkg; + # $main =~ s/^(?:.+::)?([^:]+)$/main::$1\_/g; + # foreach (@_) { + # *{ $main . $_ } = *{ $pkg . '::' . $_ }; + # } + GP_Export( + qw( + Initialize + ) + ); + +} # Versions History intern: -my %Log2Syslog_vNotesIntern = ( +my %vNotesIntern = ( + "5.12.2" => "15.05.2020 permit content of 'exclErrCond' to fhemLog strings ", + "5.12.1" => "12.05.2020 add dev to check regex of 'exclErrCond' ", + "5.12.0" => "16.04.2020 improve IETF octet count again, internal code changes for PBP ", + "5.11.0" => "14.04.2020 switch to packages, improve IETF octet count ", + "5.10.3" => "11.04.2020 new reading 'Parse_Err_LastData', change octet count read ", + "5.10.2" => "08.04.2020 code changes to stabilize send process, minor fixes ", "5.10.1" => "06.04.2020 support time-secfrac of RFC 3339, minor fix ", "5.10.0" => "04.04.2020 new attribute 'timeSpec', send and parse messages according to UTC or Local time, some minor fixes (e.g. for Octet Count) ", "5.9.0" => "01.04.2020 Parser UniFi Controller Syslog (BSD Format) and Netconsole messages, more code review (e.g. remove prototypes) ", @@ -53,7 +121,7 @@ my %Log2Syslog_vNotesIntern = ( "5.8.0" => "20.07.2019 attribute waitForEOF, solution for Forum: https://forum.fhem.de/index.php/topic,75426.msg958836.html#msg958836 ", "5.7.0" => "20.07.2019 change logging and chomp received data, use raw parse format if automatic mode don't detect a valid format, ". "change getifdata tcp stack error handling (if sysread undef)", - "5.6.5" => "19.07.2019 bugfix parse BSD if ID (TAG) is used, function DbLog_splitFn -> Log2Syslog_DbLogSplit, new attribute useParsefilter ", + "5.6.5" => "19.07.2019 bugfix parse BSD if ID (TAG) is used, function DbLog_splitFn -> DbLogSplit, new attribute useParsefilter ", "5.6.4" => "19.07.2019 minor changes and fixes (max. lenth read to 16384, code && logging) ", "5.6.3" => "18.07.2019 fix state reading if changed disabled attribute ", "5.6.2" => "17.07.2019 Forum: https://forum.fhem.de/index.php/topic,75426.msg958836.html#msg958836 first try", @@ -67,7 +135,7 @@ my %Log2Syslog_vNotesIntern = ( "5.2.1" => "08.10.2018 setpayload of BSD-format changed, commandref revised ", "5.2.0" => "02.10.2018 added direct help for attributes", "5.1.0" => "01.10.2018 new get versionNotes command", - "5.0.1" => "27.09.2018 Log2Syslog_closesock if write error:.* , delete readings code changed", + "5.0.1" => "27.09.2018 closeSocket if write error:.* , delete readings code changed", "5.0.0" => "26.09.2018 TCP-Server in Collector-mode, HIPCACHE added, PROFILE as Internal, Parse_Err_No as reading ". "octetCount attribute, TCP-SSL-support, set 'reopen' command, code fixes", "4.8.5" => "20.08.2018 BSD/parseFn parsing changed, BSD setpayload changed, new variable \$IGNORE in parseFn", @@ -93,27 +161,27 @@ my %Log2Syslog_vNotesIntern = ( "3.1.0" => "28.08.2017 get-function added, commandref revised, \$readingFnAttributes deleted", "3.0.0" => "27.08.2017 change attr type to protocol, ready to check in", "2.6.0" => "26.08.2017 more than one Log2Syslog device can be created", - "2.5.2" => "26.08.2018 fix in splitting timestamp, change Log2Syslog_trate using internaltimer with attr ". - "rateCalcRerun, function Log2Syslog_closesock", + "2.5.2" => "26.08.2018 fix in splitting timestamp, change calcTrate using internaltimer with attr ". + "rateCalcRerun, function closeSocket", "2.5.1" => "24.08.2017 some fixes", "2.5.0" => "23.08.2017 TLS encryption available, new readings, \$readingFnAttributes", - "2.4.1" => "21.08.2017 changes in Log2Syslog_charfilter, change PROCID to \$hash->{SEQNO} ". - "switch to non-blocking in subs event/Log2Syslog_fhemlog", - "2.4.0" => "20.08.2017 new sub Log2Syslog_Log3slog for entries in local fhemlog only -> verbose support", + "2.4.1" => "21.08.2017 changes in charFilter, change PROCID to \$hash->{SEQNO} ". + "switch to non-blocking in subs event/fhemLog", + "2.4.0" => "20.08.2017 new sub Log3slog for entries in local fhemlog only -> verbose support", "2.3.1" => "19.08.2017 commandref revised ", - "2.3.0" => "18.08.2017 new parameter 'ident' in DEF, sub setidex, Log2Syslog_charfilter", + "2.3.0" => "18.08.2017 new parameter 'ident' in DEF, sub setidex, charFilter", "2.2.0" => "17.08.2017 set BSD data length, set only acceptable characters (USASCII) in payload ". "commandref revised ", - "2.1.0" => "17.08.2017 sub Log2Syslog_opensock created", + "2.1.0" => "17.08.2017 sub openSocket created", "2.0.0" => "16.08.2017 create syslog without SYS::SYSLOG", - "1.1.1" => "13.08.2017 registrate Log2Syslog_fhemlog to %loginform in case of sending fhem-log ". + "1.1.1" => "13.08.2017 registrate fhemLog to %loginform in case of sending fhem-log ". "attribute timeout, commandref revised", - "1.1.0" => "26.07.2017 add regex search to sub Log2Syslog_fhemlog", + "1.1.0" => "26.07.2017 add regex search to sub fhemLog", "1.0.0" => "25.07.2017 initial version" ); # Versions History extern: -my %Log2Syslog_vNotesExtern = ( +my %vNotesExtern = ( "5.10.0" => "04.04.2020 The new attribute 'timeSpec' can be set to send and receive/parse messages according to UTC or Local time format. ". "Please refer to Date and Time on the Internet: Timestamps for further information ", "5.9.0" => "01.04.2020 The new option \"UniFi\" of attribute \"parseProfil\" provedes a new Parser for UniFi Controller Syslog messages ". @@ -162,7 +230,7 @@ my %Log2Syslog_vNotesExtern = ( "2.3.0" => "18.08.2017 new parameter 'ident' in Define to indentify sylog source ", "2.2.0" => "17.08.2017 set BSD data length, set only acceptable characters (USASCII) in payload ", "2.0.0" => "16.08.2017 create syslog without perl module SYS::SYSLOG ", - "1.1.0" => "26.07.2017 add regex search to sub Log2Syslog_fhemlog ", + "1.1.0" => "26.07.2017 add regex search to sub fhemLog ", "1.0.0" => "25.07.2017 initial version " ); @@ -244,49 +312,44 @@ my %Log2Syslog_Facility = ( # Längenvorgaben nach RFC3164 my %RFC3164len = ("TAG" => 32, # max. Länge TAG-Feld - "DL" => 1024 # max. Lange Message insgesamt + "DL" => 1024 # max. Länge Message insgesamt ); # Längenvorgaben nach RFC5425 -my %RFC5425len = ("DL" => 8192, # max. Lange Message insgesamt mit TLS +my %RFC5425len = ("DL" => 8192, # max. Länge Message insgesamt mit TLS "HST" => 255, # max. Länge Hostname "ID" => 48, # max. Länge APP-NAME bzw. Ident "PID" => 128, # max. Länge Proc-ID "MID" => 32 # max. Länge MSGID ); -my %Log2Syslog_vHintsExt_en = ( +my %vHintsExt_en = ( "4" => "The guidelines for usage of RFC5425 Date and Time on the Internet: Timestamps", "3" => "The RFC5425 TLS Transport Protocol", "2" => "The basics of RFC3164 (BSD) protocol", "1" => "Informations about RFC5424 (IETF) syslog protocol" ); -my %Log2Syslog_vHintsExt_de = ( +my %vHintsExt_de = ( "4" => "Die Richtlinien zur Verwendung von RFC5425 Datum und Zeit im Internet: Timestamps", "3" => "Die Beschreibung des RFC5425 TLS Transport Protokoll", "2" => "Die Grundlagen des RFC3164 (BSD) Protokolls", "1" => "Informationen über das RFC5424 (IETF) Syslog Protokoll" ); - -############################################################################### -# Forward declarations -# -sub Log2Syslog_Log3slog; ############################################################################### -sub Log2Syslog_Initialize { +sub Initialize { my ($hash) = @_; - $hash->{DefFn} = "Log2Syslog_Define"; - $hash->{UndefFn} = "Log2Syslog_Undef"; - $hash->{DeleteFn} = "Log2Syslog_Delete"; - $hash->{SetFn} = "Log2Syslog_Set"; - $hash->{GetFn} = "Log2Syslog_Get"; - $hash->{AttrFn} = "Log2Syslog_Attr"; - $hash->{NotifyFn} = "Log2Syslog_eventlog"; - $hash->{DbLog_splitFn} = "Log2Syslog_DbLogSplit"; - $hash->{ReadFn} = "Log2Syslog_Read"; + $hash->{DefFn} = \&Define; + $hash->{UndefFn} = \&Undef; + $hash->{DeleteFn} = \&Delete; + $hash->{SetFn} = \&Set; + $hash->{GetFn} = \&Get; + $hash->{AttrFn} = \&Attr; + $hash->{NotifyFn} = \&eventLog; + $hash->{DbLog_splitFn} = \&DbLogSplit; + $hash->{ReadFn} = \&Read; $hash->{AttrList} = "addStateEvent:1,0 ". "disable:1,0,maintenance ". @@ -319,7 +382,7 @@ return; } ############################################################################### -sub Log2Syslog_Define { +sub Define { my ($hash, $def) = @_; my @a = split("[ \t][ \t]*", $def); my $name = $hash->{NAME}; @@ -335,31 +398,31 @@ sub Log2Syslog_Define { delete($hash->{HELPER}{IDENT}); $hash->{MYHOST} = hostname(); # eigener Host (lt. RFC nur Hostname f. BSD) - my $myfqdn = hostfqdn(); # MYFQDN eigener Host (f. IETF) - $myfqdn =~ s/\.$//x if($myfqdn); - + my $myfqdn = hostfqdn(); # MYFQDN eigener Host (f. IETF) + $myfqdn =~ s/\.$//x if($myfqdn); $hash->{MYFQDN} = $myfqdn // $hash->{MYHOST}; if(int(@a)-3 < 0){ # Einrichtung Servermode (Collector) $hash->{MODEL} = "Collector"; $hash->{PROFILE} = "Automatic"; readingsSingleUpdate ($hash, 'Parse_Err_No', 0, 1); # Fehlerzähler für Parse-Errors auf 0 - Log2Syslog_Log3slog ($hash, 3, "Log2Syslog $name - entering Syslog servermode ..."); - Log2Syslog_initServer("$name,global"); + readingsSingleUpdate ($hash, 'Parse_Err_LastData', 'n.a.', 0); + Log3slog ($hash, 3, "Log2Syslog $name - entering Syslog servermode ..."); + initServer ("$name,global"); } else { # Sendermode $hash->{MODEL} = "Sender"; - Log2Syslog_setidrex($hash,$a[3]) if($a[3]); - Log2Syslog_setidrex($hash,$a[4]) if($a[4]); - Log2Syslog_setidrex($hash,$a[5]) if($a[5]); + setidrex($hash,$a[3]) if($a[3]); + setidrex($hash,$a[4]) if($a[4]); + setidrex($hash,$a[5]) if($a[5]); - eval { "Hallo" =~ m/^$hash->{HELPER}{EVNTLOG}$/ } if($hash->{HELPER}{EVNTLOG}); + eval { "Hallo" =~ m/^$hash->{HELPER}{EVNTLOG}$/x } if($hash->{HELPER}{EVNTLOG}); return "Bad regexp: $@" if($@); - eval { "Hallo" =~ m/^$hash->{HELPER}{FHEMLOG}$/ } if($hash->{HELPER}{FHEMLOG}); + eval { "Hallo" =~ m/^$hash->{HELPER}{FHEMLOG}$/x } if($hash->{HELPER}{FHEMLOG}); return "Bad regexp: $@" if($@); return "Bad regexp: starting with *" - if((defined($hash->{HELPER}{EVNTLOG}) && $hash->{HELPER}{EVNTLOG} =~ m/^\*/) || (defined($hash->{HELPER}{FHEMLOG}) && $hash->{HELPER}{FHEMLOG} =~ m/^\*/)); + if((defined($hash->{HELPER}{EVNTLOG}) && $hash->{HELPER}{EVNTLOG} =~ m/^\*/x) || (defined($hash->{HELPER}{FHEMLOG}) && $hash->{HELPER}{FHEMLOG} =~ m/^\*/x)); # nur Events dieser Devices an NotifyFn weiterleiten, NOTIFYDEV wird gesetzt wenn möglich notifyRegexpChanged($hash, $hash->{HELPER}{EVNTLOG}) if($hash->{HELPER}{EVNTLOG}); @@ -368,7 +431,7 @@ sub Log2Syslog_Define { } $hash->{SEQNO} = 1; # PROCID in IETF, wird kontinuierlich hochgezählt - $logInform{$hash->{NAME}} = "Log2Syslog_fhemlog"; # Funktion die in hash %loginform für $name eingetragen wird + $logInform{$hash->{NAME}} = \&fhemLog; # Funktion die in hash %loginform für $name eingetragen wird $hash->{HELPER}{SSLVER} = "n.a."; # Initialisierung $hash->{HELPER}{SSLALGO} = "n.a."; # Initialisierung $hash->{HELPER}{LTIME} = time(); # Init Timestmp f. Ratenbestimmung @@ -377,7 +440,7 @@ sub Log2Syslog_Define { $hash->{HELPER}{MODMETAABSENT} = 1 if($modMetaAbsent); # Modul Meta.pm nicht vorhanden # Versionsinformationen setzen - Log2Syslog_setVersionInfo($hash); + setVersionInfo($hash); readingsBeginUpdate($hash); readingsBulkUpdate ($hash, "SSL_Version", "n.a."); @@ -386,7 +449,7 @@ sub Log2Syslog_Define { readingsBulkUpdate ($hash, "state", "initialized") if($hash->{MODEL}=~/Sender/); readingsEndUpdate ($hash,1); - Log2Syslog_trate($hash); # regelm. Berechnung Transfer Rate starten + calcTrate($hash); # regelm. Berechnung Transfer Rate starten return; } @@ -395,17 +458,17 @@ return; # Syslog Collector (Server-Mode) initialisieren # (im Collector Model) ################################################################################################# -sub Log2Syslog_initServer { +sub initServer { my ($a) = @_; my ($name,$global) = split(",",$a); my $hash = $defs{$name}; my $err; - RemoveInternalTimer($hash, "Log2Syslog_initServer"); + RemoveInternalTimer($hash, "FHEM::Log2Syslog::initServer"); return if(IsDisabled($name) || $hash->{SERVERSOCKET}); - if($init_done != 1 || Log2Syslog_IsMemLock($hash)) { - InternalTimer(gettimeofday()+1, "Log2Syslog_initServer", "$name,$global", 0); + if($init_done != 1 || isMemLock($hash)) { + InternalTimer(gettimeofday()+1, "FHEM::Log2Syslog::initServer", "$name,$global", 0); return; } @@ -414,11 +477,11 @@ sub Log2Syslog_initServer { my $protocol = lc(AttrVal($name, "protocol", "udp")); my $lh = ($global ? ($global eq "global" ? undef : $global) : ($hash->{IPV6} ? "::1" : "127.0.0.1")); - Log2Syslog_Log3slog ($hash, 3, "Log2Syslog $name - Opening socket on interface \"$global\" ..."); + Log3slog ($hash, 3, "Log2Syslog $name - Opening socket on interface \"$global\" ..."); if($protocol =~ /udp/) { $hash->{SERVERSOCKET} = IO::Socket::INET->new( - Domain => ($hash->{IPV6} ? AF_INET6() : AF_UNSPEC), # Linux bug + Domain => ($hash->{IPV6} ? AF_INET6() : AF_UNSPEC()), # Linux bug LocalHost => $lh, Proto => $protocol, LocalPort => $port, @@ -426,18 +489,18 @@ sub Log2Syslog_initServer { ); if(!$hash->{SERVERSOCKET}) { $err = "Can't open Syslog Collector at $port: $!"; - Log2Syslog_Log3slog ($hash, 1, "Log2Syslog $name - $err"); + Log3slog ($hash, 1, "Log2Syslog $name - $err"); readingsSingleUpdate ($hash, 'state', $err, 1); return; } $hash->{FD} = $hash->{SERVERSOCKET}->fileno(); $hash->{PORT} = $hash->{SERVERSOCKET}->sockport(); } else { - $lh = "global" if(!$lh); + $lh = "global" if(!$lh); my $ret = TcpServer_Open($hash,$port,$lh); if($ret) { $err = "Can't open Syslog TCP Collector at $port: $ret"; - Log2Syslog_Log3slog ($hash, 1, "Log2Syslog $name - $err"); + Log3slog ($hash, 1, "Log2Syslog $name - $err"); readingsSingleUpdate ($hash, 'state', $err, 1); return; } @@ -448,7 +511,7 @@ sub Log2Syslog_initServer { $hash->{HELPER}{OLDSEQNO} = $hash->{SEQNO}; # Init Sequenznummer f. Ratenbestimmung $hash->{INTERFACE} = $lh // "global"; - Log2Syslog_Log3slog ($hash, 3, "Log2Syslog $name - port $hash->{PORT}/$protocol opened for Syslog Collector on interface \"$hash->{INTERFACE}\""); + Log3slog ($hash, 3, "Log2Syslog $name - port $hash->{PORT}/$protocol opened for Syslog Collector on interface \"$hash->{INTERFACE}\""); readingsSingleUpdate ($hash, "state", "initialized", 1); delete($readyfnlist{"$name.$port"}); $selectlist{"$name.$port"} = $hash; @@ -464,7 +527,7 @@ return; # ######################################################################################################## # called from the global loop, when the select for hash->{FD} reports data -sub Log2Syslog_Read { +sub Read { ## no critic 'complexity' my ($hash,$reread) = @_; my $socket = $hash->{SERVERSOCKET}; @@ -492,24 +555,23 @@ sub Log2Syslog_Read { $len = $RFC5425len{DL}; } - if($hash->{TEMPORARY}) { - # temporäre Instanz angelegt durch TcpServer_Accept - ($st,$data,$hash) = Log2Syslog_getifdata($hash,$len,$mlen,$reread); + if($hash->{TEMPORARY}) { # temporäre Instanz angelegt durch TcpServer_Accept + ($st,$data,$hash) = getIfData($hash,$len,$mlen,$reread); } my $name = $hash->{NAME}; - return if(IsDisabled($name) || Log2Syslog_IsMemLock($hash)); + return if(IsDisabled($name) || isMemLock($hash)); my $mevt = AttrVal($name, "makeEvent", "intern"); # wie soll Reading/Event erstellt werden my $sevevt = AttrVal($name, "respectSeverity", ""); # welcher Schweregrad soll berücksichtigt werden (default: alle) if($socket) { - ($st,$data,$hash) = Log2Syslog_getifdata($hash,$len,$mlen,$reread); + ($st,$data,$hash) = getIfData($hash,$len,$mlen,$reread); } if($data) { # parse Payload my (@load,$ocount,$msg,$tail); - if($data =~ /^(?(\d+))\s(?.*)/s) { # Syslog Sätze mit Octet Count -> Transmission of Syslog Messages over TCP https://tools.ietf.org/html/rfc6587 - Log2Syslog_Log3slog ($hash, 4, "Log2Syslog $name - Datagramm with Octet Count detected - prepare message for Parsing ... \n"); + if($data =~ /^(?(\d+))\s(?(.*))/sx) { # Syslog Sätze mit Octet Count -> Transmission of Syslog Messages over TCP https://tools.ietf.org/html/rfc6587 + Log3slog ($hash, 4, "Log2Syslog $name - Datagramm with Octet Count detected - prepare message for Parsing ... \n"); use bytes; my $i = 0; $ocount = $+{ocount}; @@ -519,35 +581,40 @@ sub Log2Syslog_Read { if(length($tail) >= $ocount) { $tail = substr($tail,$ocount); } else { - $tail = ""; + $tail = substr($tail,length($msg)); } - Log2Syslog_Log3slog ($hash, 5, "Log2Syslog $name -> OCTETCOUNT$i: $ocount"); - Log2Syslog_Log3slog ($hash, 5, "Log2Syslog $name -> MSG$i : $msg"); - Log2Syslog_Log3slog ($hash, 5, "Log2Syslog $name -> LENGTH_MSG$i: ".length($msg)); - Log2Syslog_Log3slog ($hash, 5, "Log2Syslog $name -> TAIL$i : $tail"); + Log3slog ($hash, 5, "Log2Syslog $name -> OCTETCOUNT$i: $ocount"); + Log3slog ($hash, 5, "Log2Syslog $name -> MSG$i : $msg"); + Log3slog ($hash, 5, "Log2Syslog $name -> LENGTH_MSG$i: ".length($msg)); + Log3slog ($hash, 5, "Log2Syslog $name -> TAIL$i : $tail"); - while($tail && $tail =~ /^(?(\d+))\s(?.*)/s) { + while($tail && $tail =~ /^(?(\d+))\s(?(.*))/sx) { $i++; $ocount = $+{ocount}; $tail = $+{tail}; + next if(!$tail); $msg = substr($tail,0,$ocount); push @load, $msg; - next if(!$tail); - $tail = substr($tail,$ocount); + if(length($tail) >= $ocount) { + $tail = substr($tail,$ocount); + } else { + $tail = substr($tail,length($msg)); + } - Log2Syslog_Log3slog ($hash, 5, "Log2Syslog $name -> OCTETCOUNT$i: $ocount"); - Log2Syslog_Log3slog ($hash, 5, "Log2Syslog $name -> MSG$i : $msg"); - Log2Syslog_Log3slog ($hash, 5, "Log2Syslog $name -> LENGTH_MSG$i: ".length($msg)); - Log2Syslog_Log3slog ($hash, 5, "Log2Syslog $name -> TAIL$i : $tail"); + Log3slog ($hash, 5, "Log2Syslog $name -> OCTETCOUNT$i: $ocount"); + Log3slog ($hash, 5, "Log2Syslog $name -> MSG$i : $msg"); + Log3slog ($hash, 5, "Log2Syslog $name -> LENGTH_MSG$i: ".length($msg)); + Log3slog ($hash, 5, "Log2Syslog $name -> TAIL$i : $tail"); } + } else { @load = split("[\r\n]",$data); } - + for my $line (@load) { next if(!$line); - ($err,$ignore,$sev,$phost,$ts,$pl) = Log2Syslog_parsePayload($hash,$line); + ($err,$ignore,$sev,$phost,$ts,$pl) = parsePayload($hash,$line); $hash->{SEQNO}++; if($err) { $pen = ReadingsVal($name, "Parse_Err_No", 0); @@ -555,14 +622,14 @@ sub Log2Syslog_Read { readingsSingleUpdate($hash, 'Parse_Err_No', $pen, 1); $st = "parse error - see logfile"; } elsif ($ignore) { - Log2Syslog_Log3slog ($hash, 5, "Log2Syslog $name -> dataset was ignored by parseFn"); + Log3slog ($hash, 5, "Log2Syslog $name -> dataset was ignored by parseFn"); } else { - return if($sevevt && $sevevt !~ m/$sev/); # Message nicht berücksichtigen + return if($sevevt && $sevevt !~ m/$sev/x); # Message nicht berücksichtigen $st = "active"; if($mevt =~ /intern/) { # kein Reading, nur Event $pl = "$phost: $pl"; - Log2Syslog_Trigger($hash,$ts,$pl); - } elsif ($mevt =~ /reading/) { # Reading, Event abhängig von event-on-.* + Trigger($hash,$ts,$pl); + } elsif ($mevt =~ /reading/x) { # Reading, Event abhängig von event-on-.* readingsSingleUpdate($hash, "MSG_$phost", $pl, 1); } else { # Reading ohne Event readingsSingleUpdate($hash, "MSG_$phost", $pl, 0); @@ -596,7 +663,7 @@ return; # (sSiehe auch "list TYPE=FHEMWEB", bzw. "man -s2 accept") # ############################################################################### -sub Log2Syslog_getifdata { +sub getIfData { ## no critic 'complexity' my ($hash,$len,$mlen,$reread) = @_; my $name = $hash->{NAME}; my $socket = $hash->{SERVERSOCKET}; @@ -613,17 +680,17 @@ sub Log2Syslog_getifdata { if(!$reread) { if($socket && $protocol =~ /udp/) { # UDP Datagramm empfangen - Log2Syslog_Log3slog ($hash, 4, "Log2Syslog $name - ####################################################### "); - Log2Syslog_Log3slog ($hash, 4, "Log2Syslog $name - ######### new Syslog UDP Receive ######### "); - Log2Syslog_Log3slog ($hash, 4, "Log2Syslog $name - ####################################################### "); + Log3slog ($hash, 4, "Log2Syslog $name - ####################################################### "); + Log3slog ($hash, 4, "Log2Syslog $name - ######### new Syslog UDP Receive ######### "); + Log3slog ($hash, 4, "Log2Syslog $name - ####################################################### "); unless($socket->recv($data, $len)) { - Log2Syslog_Log3slog ($hash, 3, "Log2Syslog $name - Seq \"$hash->{SEQNO}\" invalid data: $data"); + Log3slog ($hash, 3, "Log2Syslog $name - Seq \"$hash->{SEQNO}\" invalid data: $data"); $data = '' if(length($data) == 0); $st = "receive error - see logfile"; } else { my $dl = length($data); - Log2Syslog_Log3slog ($hash, 5, "Log2Syslog $name - Buffer ".$dl." chars ready to parse:\n$data"); + Log3slog ($hash, 5, "Log2Syslog $name - Buffer ".$dl." chars ready to parse:\n$data"); } return ($st,$data,$hash); @@ -648,11 +715,11 @@ sub Log2Syslog_getifdata { my $uef = AttrVal($sname, "useEOF", 0); my $tlsv = ReadingsVal($sname,"SSL_Version",''); - Log2Syslog_Log3slog ($shash, 4, "Log2Syslog $sname - ####################################################### "); - Log2Syslog_Log3slog ($shash, 4, "Log2Syslog $sname - ######### new Syslog TCP Receive ######### "); - Log2Syslog_Log3slog ($shash, 4, "Log2Syslog $sname - ####################################################### "); - Log2Syslog_Log3slog ($shash, 4, "Log2Syslog $sname - await EOF: $uef, SSL: $tlsv"); - Log2Syslog_Log3slog ($shash, 4, "Log2Syslog $sname - childname: $cname"); + Log3slog ($shash, 4, "Log2Syslog $sname - ####################################################### "); + Log3slog ($shash, 4, "Log2Syslog $sname - ######### new Syslog TCP Receive ######### "); + Log3slog ($shash, 4, "Log2Syslog $sname - ####################################################### "); + Log3slog ($shash, 4, "Log2Syslog $sname - await EOF: $uef, SSL: $tlsv"); + Log3slog ($shash, 4, "Log2Syslog $sname - childname: $cname"); $st = ReadingsVal($sname,"state","active"); my $c = $hash->{CD}; @@ -662,14 +729,14 @@ sub Log2Syslog_getifdata { my $off = 0; $ret = sysread($c, $buf, $len); # returns undef on error, 0 at end of file and Integer, number of bytes read on success. - if(!defined($ret) && $! == EWOULDBLOCK){ # error + if(!defined($ret) && $! == EWOULDBLOCK()){ # error $hash->{wantWrite} = 1 if(TcpServer_WantWrite($hash)); $hash = $shash; - Log2Syslog_Log3slog ($hash, 2, "Log2Syslog $sname - ERROR - TCP stack error: $!"); + Log3slog ($hash, 2, "Log2Syslog $sname - ERROR - TCP stack error: $!"); return ($st,undef,$hash); } elsif (!$ret) { # EOF or error - Log2Syslog_Log3slog ($shash, 4, "Log2Syslog $sname - Connection closed for $cname: ".(defined($ret) ? 'EOF' : $!)); + Log3slog ($shash, 4, "Log2Syslog $sname - Connection closed for $cname: ".(defined($ret) ? 'EOF' : $!)); if(!defined($ret)) { # error CommandDelete(undef, $cname); $hash = $shash; @@ -683,7 +750,7 @@ sub Log2Syslog_getifdata { if(!$eof) { $hash->{BUF} .= $buf; - Log2Syslog_Log3slog ($shash, 5, "Log2Syslog $sname - Add $ret chars to buffer:\n$buf") if($uef && !$hash->{SSL}); + Log3slog ($shash, 5, "Log2Syslog $sname - Add $ret chars to buffer:\n$buf") if($uef && !$hash->{SSL}); } if($hash->{SSL} && $c->can('pending')) { @@ -701,8 +768,8 @@ sub Log2Syslog_getifdata { $hash = $shash; if($data) { my $dl = length($data); - Log2Syslog_Log3slog ($shash, 2, "Log2Syslog $sname - WARNING - Buffer overrun ! Enforce parse data.") if($buforun); - Log2Syslog_Log3slog ($shash, 5, "Log2Syslog $sname - Buffer $dl chars ready to parse:\n$data"); + Log3slog ($shash, 2, "Log2Syslog $sname - WARNING - Buffer overrun ! Enforce parse data.") if($buforun); + Log3slog ($shash, 5, "Log2Syslog $sname - Buffer $dl chars ready to parse:\n$data"); } return ($st,$data,$hash); @@ -710,7 +777,7 @@ sub Log2Syslog_getifdata { if($eof) { $hash = $shash; my $dl = length($data); - Log2Syslog_Log3slog ($shash, 5, "Log2Syslog $sname - Buffer $dl chars after EOF ready to parse:\n$data") if($data); + Log3slog ($shash, 5, "Log2Syslog $sname - Buffer $dl chars after EOF ready to parse:\n$data") if($data); return ($st,$data,$hash); } } @@ -730,23 +797,23 @@ return ($st,undef,$hash); # Parsen Payload für Syslog-Server # (im Collector Model) ############################################################################### -sub Log2Syslog_parsePayload { +sub parsePayload { ## no critic 'complexity' my ($hash,$data) = @_; my $name = $hash->{NAME}; my $pp = AttrVal($name, "parseProfile", $hash->{PROFILE}); my $severity = ""; my $facility = ""; - my @evf = split(",",AttrVal($name, "outputFields", "FAC,SEV,ID,CONT")); # auszugebene Felder im Event/Reading + my @evf = split q{,},AttrVal($name, "outputFields", "FAC,SEV,ID,CONT"); # auszugebene Felder im Event/Reading my $ignore = 0; my ($to,$Mmm,$dd,$day,$ietf,$err,$pl,$tail); - $data = Log2Syslog_parsefilter($data) if(AttrVal($name,"useParsefilter",0)); # Steuerzeichen werden entfernt (Achtung auch CR/LF) + $data = parseFilter($data) if(AttrVal($name,"useParsefilter",0)); # Steuerzeichen werden entfernt (Achtung auch CR/LF) - Log2Syslog_Log3slog ($hash, 4, "Log2Syslog $name - ######### Parse Message ######### "); - Log2Syslog_Log3slog ($hash, 5, "Log2Syslog $name - parse profile: $pp"); + Log3slog ($hash, 4, "Log2Syslog $name - ######### Parse Message ######### "); + Log3slog ($hash, 5, "Log2Syslog $name - parse profile: $pp"); # Hash zur Umwandlung Felder in deren Variablen - my ($prival,$ts,$host,$date,$time,$id,$pid,$mid,$sdfield,$cont); + my ($ocount,$prival,$ts,$host,$date,$time,$id,$pid,$mid,$sdfield,$cont); my ($fac,$sev,$msec) = ("","",""); my %fh = (PRIVAL => \$prival, @@ -764,23 +831,25 @@ sub Log2Syslog_parsePayload { DATA => \$data ); - my ($phost) = Log2Syslog_evalPeer($hash); # Sender Host / IP-Adresse ermitteln, $phost wird Reading im Event + my ($phost) = evalPeer($hash); # Sender Host / IP-Adresse ermitteln, $phost wird Reading im Event - Log2Syslog_Log3slog ($hash, 4, "Log2Syslog $name - raw message -> $data"); + Log3slog ($hash, 4, "Log2Syslog $name - raw message -> $data"); my $year = strftime "%Y", localtime; # aktuelles Jahr - if($pp =~ /^Automatic/) { - Log2Syslog_Log3slog($name, 4, "Log2Syslog $name - Analyze message format automatically ..."); - $pp = "raw"; - $data =~ /^<(?\d{1,3})>(?\w{3}).*$/; - $tail = $+{tail}; + if($pp =~ /^Automatic/x) { + Log3slog($name, 4, "Log2Syslog $name - Analyze message format automatically ..."); + $pp = "raw"; + $data =~ /^<(?\d{1,3})>(?\w{3}).*$/x; + $prival = $+{prival}; + $tail = $+{tail}; # Test auf BSD-Format - if($tail && " Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec " =~ /\s$tail\s/) { + if($tail && " Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec " =~ /\s$tail\s/x) { $pp = "BSD"; } else { # Test auf IETF-Format - $data =~ /^<(?\d{1,3})>(?\d{0,2})\s?(?\d{4}-\d{2}-\d{2})T(?