2017-08-27 10:11:05 +00:00
######################################################################################################################
2018-08-01 19:20:56 +00:00
# $Id: 93_Log2Syslog.pm 16688 2018-05-04 20:09:12Z DS_Starter $
2017-08-27 10:11:05 +00:00
######################################################################################################################
2017-08-16 22:32:44 +00:00
# 93_Log2Syslog.pm
#
2018-08-01 19:20:56 +00:00
# (c) 2017-2018 by Heiko Maaz
2017-08-16 22:32:44 +00:00
# e-mail: Heiko dot Maaz at t-online dot de
#
# This script is part of fhem.
#
# Fhem is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# Fhem is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
#
2018-08-01 19:20:56 +00:00
# The module is based on idea and input from betateilchen 92_rsyslog.pm
2017-08-25 08:28:14 +00:00
#
2017-08-17 20:20:38 +00:00
# Implements the Syslog Protocol of RFC 5424 https://tools.ietf.org/html/rfc5424
2017-08-25 08:28:14 +00:00
# and RFC 3164 https://tools.ietf.org/html/rfc3164 and
# TLS Transport according to RFC5425 https://tools.ietf.org/pdf/rfc5425.pdf as well
2017-08-16 22:32:44 +00:00
#
2017-08-27 10:11:05 +00:00
######################################################################################################################
2017-08-16 22:32:44 +00:00
# Versions History:
#
2018-08-01 19:20:56 +00:00
# 4.0.0 30.07.2018 server mode
# 3.2.1 04.05.2018 fix compatibility with newer IO::Socket::SSL on debian 9, attr ssldebug for
# debugging SSL messages
# 3.2.0 22.11.2017 add NOTIFYDEV if possible
# 3.1.0 28.08.2017 get-function added, commandref revised, $readingFnAttributes deleted
2017-08-27 10:11:05 +00:00
# 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
2017-08-27 10:50:18 +00:00
# rateCalcRerun, function Log2Syslog_closesock
2017-08-25 08:28:14 +00:00
# 2.5.1 24.08.2017 some fixes
# 2.5.0 23.08.2017 TLS encryption available, new readings, $readingFnAttributes
2017-08-27 10:11:05 +00:00
# 2.4.1 21.08.2017 changes in sub 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
2017-08-19 15:09:53 +00:00
# 2.3.1 19.08.2017 commandref revised
2017-08-27 10:11:05 +00:00
# 2.3.0 18.08.2017 new parameter "ident" in DEF, sub setidex, Log2Syslog_charfilter
2017-08-17 20:20:38 +00:00
# 2.2.0 17.08.2017 set BSD data length, set only acceptable characters (USASCII) in payload
# commandref revised
2017-08-27 10:11:05 +00:00
# 2.1.0 17.08.2017 sub Log2Syslog_setsock created
2017-08-16 22:32:44 +00:00
# 2.0.0 16.08.2017 create syslog without SYS::SYSLOG
2017-08-27 10:11:05 +00:00
# 1.1.1 13.08.2017 registrate Log2Syslog_fhemlog to %loginform in case of sending fhem-log
2017-08-16 22:32:44 +00:00
# attribute timeout, commandref revised
2017-08-27 10:11:05 +00:00
# 1.1.0 26.07.2017 add regex search to sub Log2Syslog_fhemlog
2017-08-16 22:32:44 +00:00
# 1.0.0 25.07.2017 initial version
package main ;
use strict ;
use warnings ;
2018-08-01 19:20:56 +00:00
use Encode qw( encode_utf8 ) ;
2017-08-16 22:32:44 +00:00
eval "use IO::Socket::INET;1" or my $ MissModulSocket = "IO::Socket::INET" ;
2018-08-01 19:20:56 +00:00
eval "use Net::Domain qw(hostname hostfqdn hostdomain domainname);1" or my $ MissModulNDom = "Net::Domain" ;
2017-08-16 22:32:44 +00:00
2017-08-27 10:11:05 +00:00
###############################################################################
2017-08-20 08:19:32 +00:00
# Forward declarations
#
2017-08-27 10:11:05 +00:00
sub Log2Syslog_Log3slog ($$$) ;
2017-08-20 08:19:32 +00:00
2018-08-01 19:20:56 +00:00
my $ Log2SyslogVn = "4.0.0" ;
2017-08-16 22:32:44 +00:00
# Mappinghash BSD-Formatierung Monat
my % Log2Syslog_BSDMonth = (
"01" = > "Jan" ,
"02" = > "Feb" ,
"03" = > "Mar" ,
"04" = > "Apr" ,
"05" = > "May" ,
"06" = > "Jun" ,
"07" = > "Jul" ,
"08" = > "Aug" ,
"09" = > "Sep" ,
"10" = > "Oct" ,
"11" = > "Nov" ,
2018-08-01 19:20:56 +00:00
"12" = > "Dec" ,
"Jan" = > "01" ,
"Feb" = > "02" ,
"Mar" = > "03" ,
"Apr" = > "04" ,
"May" = > "05" ,
"Jun" = > "06" ,
"Jul" = > "07" ,
"Aug" = > "08" ,
"Sep" = > "09" ,
"Oct" = > "10" ,
"Nov" = > "11" ,
"Dec" = > "12" ,
2017-08-16 22:32:44 +00:00
) ;
2018-08-01 19:20:56 +00:00
# Mappinghash Severity
my % Log2Syslog_Severity = (
"0" = > "Emergency" ,
"1" = > "Alert" ,
"2" = > "Critical" ,
"3" = > "Error" ,
"4" = > "Warning" ,
"5" = > "Notice" ,
"6" = > "Informational" ,
"7" = > "Debug" ,
) ;
# Mappinghash Facility
my % Log2Syslog_Facility = (
"0" = > "kernel" ,
"1" = > "user" ,
"2" = > "mail" ,
"3" = > "system" ,
"4" = > "security" ,
"5" = > "syslog" ,
"6" = > "printer" ,
"7" = > "network" ,
"8" = > "UUCP" ,
"9" = > "clock" ,
"10" = > "security" ,
"11" = > "FTP" ,
"12" = > "NTP" ,
"13" = > "log_audit" ,
"14" = > "log_alert" ,
"15" = > "clock" ,
"16" = > "local0" ,
"17" = > "local1" ,
"18" = > "local2" ,
"19" = > "local3" ,
"20" = > "local4" ,
"21" = > "local5" ,
"22" = > "local6" ,
"23" = > "local7" ,
) ;
2017-08-17 20:20:38 +00:00
# Längenvorgaben nach RFC3164
my % RFC3164len = ( "TAG" = > 32 , # max. Länge TAG-Feld
"DL" = > 1024 # max. Lange Message insgesamt
) ;
2017-08-22 06:41:25 +00:00
# Längenvorgaben nach RFC5425
2018-08-01 19:20:56 +00:00
my % RFC5425len = ( "DL" = > 8192 , # max. Lange 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
2017-08-22 06:41:25 +00:00
) ;
2017-08-17 20:20:38 +00:00
2017-08-27 10:11:05 +00:00
###############################################################################
2017-08-16 22:32:44 +00:00
sub Log2Syslog_Initialize ($) {
my ( $ hash ) = @ _ ;
$ hash - > { DefFn } = "Log2Syslog_Define" ;
$ hash - > { UndefFn } = "Log2Syslog_Undef" ;
$ hash - > { DeleteFn } = "Log2Syslog_Delete" ;
2018-08-01 19:20:56 +00:00
$ hash - > { GetFn } = "Log2Syslog_Get" ;
2017-08-16 22:32:44 +00:00
$ hash - > { AttrFn } = "Log2Syslog_Attr" ;
2017-08-27 10:11:05 +00:00
$ hash - > { NotifyFn } = "Log2Syslog_eventlog" ;
2018-08-01 19:20:56 +00:00
$ hash - > { ReadFn } = "Log2Syslog_Read" ;
2017-08-16 22:32:44 +00:00
$ hash - > { AttrList } = "addStateEvent:1,0 " .
"disable:1,0 " .
"addTimestamp:0,1 " .
"logFormat:BSD,IETF " .
2018-08-01 19:20:56 +00:00
"parseProfile:default,raw " .
"ssldebug:0,1,2,3 " .
2017-08-25 08:28:14 +00:00
"TLS:1,0 " .
"timeout " .
2017-08-27 10:11:05 +00:00
"protocol:UDP,TCP " .
2017-08-25 08:28:14 +00:00
"port " .
2018-08-01 20:30:56 +00:00
"rateCalcRerun " .
$ readingFnAttributes
2017-08-16 22:32:44 +00:00
;
return undef ;
}
2017-08-27 10:11:05 +00:00
###############################################################################
2017-08-16 22:32:44 +00:00
sub Log2Syslog_Define ($@) {
my ( $ hash , $ def ) = @ _ ;
my @ a = split ( "[ \t][ \t]*" , $ def ) ;
2018-08-01 19:20:56 +00:00
my $ name = $ hash - > { NAME } ;
2017-08-16 22:32:44 +00:00
return "Error: Perl module " . $ MissModulSocket . " is missing. Install it on Debian with: sudo apt-get install libio-socket-multicast-perl" if ( $ MissModulSocket ) ;
return "Error: Perl module " . $ MissModulNDom . " is missing." if ( $ MissModulNDom ) ;
2018-08-01 19:20:56 +00:00
# Example Sender: define splunklog Log2Syslog splunk.myds.me ident:Prod event:.* fhem:.*
# Example Collector: define SyslogServer Log2Syslog
2017-08-16 22:32:44 +00:00
delete ( $ hash - > { HELPER } { EVNTLOG } ) ;
delete ( $ hash - > { HELPER } { FHEMLOG } ) ;
2017-08-18 19:51:33 +00:00
delete ( $ hash - > { HELPER } { IDENT } ) ;
2018-08-01 19:20:56 +00:00
$ hash - > { MYHOST } = hostfqdn ( ) ; # FQDN eigener Host
2017-08-16 22:32:44 +00:00
2018-08-01 19:20:56 +00:00
if ( int ( @ a ) - 3 < 0 ) {
# Einrichtung Servermode (Collector)
Log3 ( $ name , 3 , "Log2Syslog $name - entering Syslog servermode ..." ) ;
$ hash - > { MODEL } = "Collector" ;
Log2Syslog_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 ] ) ;
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 ( $@ ) ;
return "Bad regexp: starting with *"
if ( ( defined ( $ hash - > { HELPER } { EVNTLOG } ) && $ hash - > { HELPER } { EVNTLOG } =~ m/^\*/ ) || ( defined ( $ hash - > { HELPER } { FHEMLOG } ) && $ hash - > { HELPER } { FHEMLOG } =~ m/^\*/ ) ) ;
# nur Events dieser Devices an NotifyFn weiterleiten, NOTIFYDEV wird gesetzt wenn möglich
notifyRegexpChanged ( $ hash , $ hash - > { HELPER } { EVNTLOG } ) if ( $ hash - > { HELPER } { EVNTLOG } ) ;
2017-08-16 22:32:44 +00:00
2018-08-01 19:20:56 +00:00
$ hash - > { PEERHOST } = $ a [ 2 ] ; # Destination Host (Syslog Server)
}
2017-08-25 08:28:14 +00:00
$ hash - > { SEQNO } = 1 ; # PROCID in IETF, wird kontinuierlich hochgezählt
2017-08-16 22:32:44 +00:00
$ hash - > { VERSION } = $ Log2SyslogVn ;
2017-08-27 10:11:05 +00:00
$ logInform { $ hash - > { NAME } } = "Log2Syslog_fhemlog" ; # Funktion die in hash %loginform für $name eingetragen wird
2017-08-25 08:28:14 +00:00
$ hash - > { HELPER } { SSLVER } = "n.a." ; # Initialisierung
$ hash - > { HELPER } { SSLALGO } = "n.a." ; # Initialisierung
$ hash - > { HELPER } { LTIME } = time ( ) ; # Init Timestmp f. Ratenbestimmung
$ hash - > { HELPER } { OLDSEQNO } = $ hash - > { SEQNO } ; # Init Sequenznummer f. Ratenbestimmung
readingsBeginUpdate ( $ hash ) ;
readingsBulkUpdate ( $ hash , "SSL_Version" , "n.a." ) ;
readingsBulkUpdate ( $ hash , "SSL_Algorithm" , "n.a." ) ;
readingsBulkUpdate ( $ hash , "Transfered_logs_per_minute" , 0 ) ;
2018-08-01 19:20:56 +00:00
readingsBulkUpdate ( $ hash , "state" , "initialized" ) if ( $ hash - > { MODEL } =~ /Sender/ ) ;
2017-08-25 08:28:14 +00:00
readingsEndUpdate ( $ hash , 1 ) ;
2017-08-16 22:32:44 +00:00
2017-08-27 10:11:05 +00:00
Log2Syslog_trate ( $ hash ) ; # regelm. Berechnung Transfer Rate starten
2018-08-01 19:20:56 +00:00
2017-08-16 22:32:44 +00:00
return undef ;
}
2018-08-01 19:20:56 +00:00
#################################################################################################
# Syslog Collector (Server-Mode) initialisieren
# (im Collector Model)
#################################################################################################
sub Log2Syslog_initServer ($) {
my ( $ a ) = @ _ ;
my ( $ name , $ global ) = split ( "," , $ a ) ;
my $ hash = $ defs { $ name } ;
RemoveInternalTimer ( $ hash , "Log2Syslog_initServer" ) ;
return if ( IsDisabled ( $ name ) ) ;
if ( $ init_done != 1 ) {
InternalTimer ( gettimeofday ( ) + 5 , "Log2Syslog_initServer" , "$name,$global" , 0 ) ;
return ;
}
# Inititialisierung FHEM ist fertig -> Attribute geladen
my $ port = AttrVal ( $ name , "TLS" , 0 ) ? AttrVal ( $ name , "port" , 6514 ) : AttrVal ( $ name , "port" , 1514 ) ;
my $ protocol = lc ( AttrVal ( $ name , "protocol" , "udp" ) ) ;
my $ lf = AttrVal ( $ name , "logFormat" , "IETF" ) ;
my $ lh = $ global ? ( $ global eq "global" ? undef : $ global ) : ( $ hash - > { IPV6 } ? "::1" : "127.0.0.1" ) ;
Log3 $ hash , 3 , "Log2Syslog $name - Opening socket ..." ;
$ hash - > { SERVERSOCKET } = IO::Socket::INET - > new (
Domain = > ( $ hash - > { IPV6 } ? AF_INET6 ( ) : AF_UNSPEC ) , # Linux bug
LocalHost = > $ lh ,
Proto = > $ protocol ,
LocalPort = > $ port ,
ReuseAddr = > 1
) ;
if ( ! $ hash - > { SERVERSOCKET } ) {
my $ err = "Can't open Syslog Collector at $port: $!" ;
Log3 ( $ hash , 1 , "Log2Syslog $name - $err" ) ;
ReadingsSingleUpdateValue ( $ hash , 'state' , $ err , 1 ) ;
return ;
}
$ hash - > { FD } = $ hash - > { SERVERSOCKET } - > fileno ( ) ;
$ hash - > { PORT } = $ hash - > { SERVERSOCKET } - > sockport ( ) ;
$ hash - > { PROTOCOL } = $ protocol ;
$ hash - > { LOGFORMAT } = $ lf ;
$ hash - > { SEQNO } = 1 ; # PROCID wird kontinuierlich pro empfangenen Datensatz hochgezählt
$ hash - > { HELPER } { OLDSEQNO } = $ hash - > { SEQNO } ; # Init Sequenznummer f. Ratenbestimmung
$ hash - > { INTERFACE } = $ lh ? $ lh: "global" ;
Log3 ( $ hash , 3 , "Log2Syslog $name - port $hash->{PORT}/$protocol opened for Syslog Collector ($lf) on interface \"$hash->{INTERFACE}\"" ) ;
ReadingsSingleUpdateValue ( $ hash , "state" , "initialized" , 1 ) ;
delete ( $ readyfnlist { "$name.$port" } ) ;
$ selectlist { "$name.$port" } = $ hash ;
return ;
}
#################################################################################################
# Syslog Collector Daten empfangen
# (im Collector Model)
#################################################################################################
# called from the global loop, when the select for hash->{FD} reports data
sub Log2Syslog_Read ($) {
my ( $ hash ) = @ _ ;
my $ name = $ hash - > { NAME } ;
my $ socket = $ hash - > { SERVERSOCKET } ;
my $ st = "active" ;
my $ lf = AttrVal ( $ name , "logFormat" , "IETF" ) ;
my ( $ err , $ data , $ facility , $ severity , $ date , $ host , $ ident , $ content , $ pl , $ version , $ pid , $ mid , $ sdfield ) ;
return if ( IsDisabled ( $ name ) ) ;
if ( $ lf =~ /BSD/ ) {
# BSD-Format
unless ( $ socket - > recv ( $ data , $ RFC3164len { DL } ) ) {
# ungültige BSD-Payload
return if ( length ( $ data ) == 0 ) ;
Log2Syslog_Log3slog ( $ hash , 3 , "Log2Syslog $name - received " . length ( $ data ) . " bytes, but a BSD-message has to be 1024 bytes or less." ) ;
Log2Syslog_Log3slog ( $ hash , 3 , "Log2Syslog $name - Seq \"$hash->{SEQNO}\" invalid data: $data" ) ;
$ st = "receive error - see logfile" ;
} else {
# parse Payload
( $ err , $ pl ) = Log2Syslog_parsePayload ( $ hash , $ data ) ;
$ hash - > { SEQNO } + + ;
if ( $ err ) {
$ st = "parse error - see logfile" ;
} else {
Log2Syslog_Trigger ( $ hash , $ date , $ pl ) ;
}
}
} else {
# IETF-Format
unless ( $ socket - > recv ( $ data , $ RFC5425len { DL } ) ) {
# ungültige IETF-Payload
return if ( length ( $ data ) == 0 ) ;
Log2Syslog_Log3slog ( $ hash , 3 , "Log2Syslog $name - received " . length ( $ data ) . " bytes, but a BSD-message has to be 1024 bytes or less." ) ;
Log2Syslog_Log3slog ( $ hash , 3 , "Log2Syslog $name - Seq \"$hash->{SEQNO}\" invalid data: $data" ) ;
$ st = "receive error - see logfile" ;
} else {
# parse Payload
( $ err , $ pl ) = Log2Syslog_parsePayload ( $ hash , $ data ) ;
$ hash - > { SEQNO } + + ;
if ( $ err ) {
$ st = "parse error - see logfile" ;
} else {
Log2Syslog_Trigger ( $ hash , $ date , $ pl ) ;
}
}
}
readingsSingleUpdate ( $ hash , "state" , $ st , 1 ) if ( $ st ne OldValue ( $ name ) ) ;
return ;
}
###############################################################################
# Parsen Payload für Syslog-Server
# (im Collector Model)
###############################################################################
sub Log2Syslog_parsePayload ($$) {
my ( $ hash , $ data ) = @ _ ;
my $ name = $ hash - > { NAME } ;
my $ lf = AttrVal ( $ name , "logFormat" , "IETF" ) ;
my $ pp = AttrVal ( $ name , "parseProfile" , "default" ) ;
my ( $ prival , $ Mmm , $ dd , $ time , $ host , $ ident , $ delimiter , $ content , $ day , $ date ) ;
my ( $ severity , $ sev , $ facility , $ fac , $ version , $ pid , $ mid , $ sdfield , $ err , $ pl ) ;
Log2Syslog_Log3slog ( $ hash , 5 , "Log2Syslog $name - raw message: " . $ data ) ;
my ( $ sec , $ min , $ hour , $ mday , $ mon , $ year , $ wday , $ yday , $ isdst ) = localtime ( time ) ; # Istzeit Ableitung
$ year = $ year + 1900 ;
if ( $ lf eq "BSD" ) {
# BSD Protokollformat https://tools.ietf.org/html/rfc3164
# Beispiel data "<$prival>$month $day $time $myhost $ident: : $otp"
if ( $ pp =~ /default/ ) {
( $ prival , $ Mmm , $ dd , $ time , $ host , $ ident , $ delimiter , $ content ) = ( $ data =~ /^<(\d{1,3})>(\w{3})\s{1,2}(\d{1,2})\s(\d{2}:\d{2}:\d{2})\s(\S+)\s([a-zA-Z_0-9.]+)(\W+)(.*)$/ ) ;
if ( ! $ prival && ! $ host && ! $ ident && ! $ content ) {
$ err = 1 ;
Log2Syslog_Log3slog ( $ hash , 2 , "Log2Syslog $name - error parse msg: $data" ) ;
} else {
$ mon = $ Log2Syslog_BSDMonth { $ Mmm } ;
$ day = ( length ( $ dd ) == 1 ) ? ( "0" . $ dd ) : $ dd ;
$ date = "$year-$mon-$day $time" ;
$ fac = int ( $ prival / 8 ) ;
$ sev = $ prival - ( $ fac * 8 ) ;
$ facility = $ Log2Syslog_Facility { $ fac } ;
$ severity = $ Log2Syslog_Severity { $ sev } ;
Log2Syslog_Log3slog ( $ name , 4 , "$name - FACILITY: $fac/$facility, SEVERITY: $sev/$severity, DATE: $date, HOST: $host, ID: $ident, CONT: $content" ) ;
$ pl = "HOST: $host || FAC: $facility || SEV: $severity || ID: $ident || CONT: $content" ;
}
} elsif ( $ pp =~ /raw/ ) {
Log2Syslog_Log3slog ( $ name , 4 , "$name - $data" ) ;
$ pl = $ data ;
}
return ( $ err , $ pl ) ;
}
if ( $ lf eq "IETF" ) {
# IETF Protokollformat https://tools.ietf.org/html/rfc5424
# Beispiel data "<$prival>1 $tim $host $ident $pid $mid - : $otp";
if ( $ pp =~ /default/ ) {
( $ prival , $ version , $ date , $ time , $ host , $ ident , $ pid , $ mid , $ sdfield , $ content ) = ( $ data =~ /^<(\d{1,3})>(\d+)\s(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2})\S*\s(\S+)\s(\S+)\s(\S+)\s(\S+)\s(\[.*\]|-)\s(.*)$/ ) ;
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 - FACILITY: $fac/$facility, SEVERITY: $sev/$severity, VERSION: $version, DATE: $date, HOST: $host, ID: $ident, PID: $pid, MID: $mid, SDFIELD: $sdfield, CONT: $content" ) ;
$ pl = "HOST: $host || FAC: $facility || SEV: $severity || ID: $ident || CONT: $content" ;
}
} elsif ( $ pp =~ /raw/ ) {
Log2Syslog_Log3slog ( $ name , 4 , "$name - $data" ) ;
$ pl = $ 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
###############################################################################
2017-08-16 22:32:44 +00:00
sub Log2Syslog_Undef ($$) {
my ( $ hash , $ name ) = @ _ ;
2018-08-01 19:20:56 +00:00
2017-08-27 10:11:05 +00:00
RemoveInternalTimer ( $ hash ) ;
2018-08-01 19:20:56 +00:00
if ( $ hash - > { MODEL } =~ /Collector/ ) {
Log2Syslog_downServer ( $ hash ) ;
}
2017-08-16 22:32:44 +00:00
return undef ;
}
2018-08-01 19:20:56 +00:00
###############################################################################
# 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
###############################################################################
2017-08-16 22:32:44 +00:00
sub Log2Syslog_Delete ($$) {
my ( $ hash , $ arg ) = @ _ ;
delete $ logInform { $ hash - > { NAME } } ;
return undef ;
}
2017-08-27 10:11:05 +00:00
###############################################################################
2018-08-01 19:20:56 +00:00
# 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 ($$$$) {
2017-08-16 22:32:44 +00:00
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 ) ;
}
2017-08-25 08:28:14 +00:00
if ( $ aName eq "TLS" ) {
if ( $ cmd eq "set" ) {
2018-08-01 19:20:56 +00:00
return "\"$aName\" is only valid for model \"Sender\"" if ( $ hash - > { MODEL } =~ /Collector/ ) ;
2017-08-25 08:28:14 +00:00
$ 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 ) ;
}
}
2018-08-01 19:20:56 +00:00
if ( $ aName eq "rateCalcRerun" ) {
RemoveInternalTimer ( $ hash , "Log2Syslog_trate" ) ;
InternalTimer ( gettimeofday ( ) + 5 , "Log2Syslog_trate" , $ hash , 0 ) ;
}
2017-08-25 08:28:14 +00:00
2017-08-27 10:50:18 +00:00
if ( $ cmd eq "set" && $ aName =~ /port|timeout|rateCalcRerun/ ) {
2018-08-01 19:20:56 +00:00
return "\"$aName\" is only valid for model \"Sender\"" if ( $ hash - > { MODEL } =~ /Collector/ && $ aName =~ /timeout/ ) ;
2017-08-16 22:32:44 +00:00
if ( $ aVal !~ m/^\d+$/ ) { return " The Value of \"$aName\" is not valid. Use only figures !" ; }
2018-08-01 19:20:56 +00:00
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\"" ;
2017-08-16 22:32:44 +00:00
}
return undef ;
}
#################################################################################
# Eventlogging
#################################################################################
2017-08-27 10:11:05 +00:00
sub Log2Syslog_eventlog ($$) {
2017-08-16 22:32:44 +00:00
# $hash is my entry, $dev is the entry of the changed device
my ( $ hash , $ dev ) = @ _ ;
2017-08-18 19:51:33 +00:00
my $ name = $ hash - > { NAME } ;
my $ rex = $ hash - > { HELPER } { EVNTLOG } ;
2017-08-25 08:28:14 +00:00
my ( $ prival , $ sock , $ data , $ pid ) ;
2017-08-16 22:32:44 +00:00
2018-08-01 19:20:56 +00:00
return if ( IsDisabled ( $ name ) || ! $ rex || $ hash - > { MODEL } !~ /Sender/ ) ;
2017-08-16 22:32:44 +00:00
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 } ;
2017-08-27 10:11:05 +00:00
$ sock = Log2Syslog_setsock ( $ hash ) ;
2017-08-22 06:41:25 +00:00
2017-08-25 08:28:14 +00:00
if ( defined ( $ sock ) ) {
2017-08-22 06:41:25 +00:00
for ( my $ i = 0 ; $ i < $ max ; $ i + + ) {
my $ txt = $ events - > [ $ i ] ;
$ txt = "" if ( ! defined ( $ txt ) ) ;
2017-08-27 10:11:05 +00:00
$ txt = Log2Syslog_charfilter ( $ hash , $ txt ) ;
2017-08-17 20:20:38 +00:00
2017-08-22 06:41:25 +00:00
my $ tim = ( ( $ ct && $ ct - > [ $ i ] ) ? $ ct - > [ $ i ] : $ tn ) ;
my ( $ date , $ time ) = split ( " " , $ tim ) ;
2017-08-16 22:32:44 +00:00
2017-08-25 08:28:14 +00:00
if ( $ n =~ m/^$rex$/ || "$n:$txt" =~ m/^$rex$/ || "$tim:$n:$txt" =~ m/^$rex$/ ) {
2017-08-22 06:41:25 +00:00
my $ otp = "$n $txt" ;
$ otp = "$tim $otp" if AttrVal ( $ name , 'addTimestamp' , 0 ) ;
2017-08-27 10:11:05 +00:00
$ prival = Log2Syslog_setprival ( $ txt ) ;
2017-08-25 08:28:14 +00:00
2017-08-27 10:11:05 +00:00
( $ data , $ pid ) = Log2Syslog_setpayload ( $ hash , $ prival , $ date , $ time , $ otp , "event" ) ;
2017-08-25 08:28:14 +00:00
next if ( ! $ data ) ;
my $ ret = syswrite $ sock , $ data . "\n" ;
2017-08-27 10:11:05 +00:00
if ( $ ret && $ ret > 0 ) {
Log2Syslog_Log3slog ( $ name , 4 , "$name - Payload sequence $pid sent\n" ) ;
2017-08-22 06:41:25 +00:00
} else {
2017-08-25 08:28:14 +00:00
my $ err = $! ;
2017-08-27 10:11:05 +00:00
Log2Syslog_Log3slog ( $ name , 4 , "$name - Warning - Payload sequence $pid NOT sent: $err\n" ) ;
2017-08-25 08:28:14 +00:00
readingsSingleUpdate ( $ hash , "state" , "write error: $err" , 1 ) if ( $ err ne OldValue ( $ name ) ) ;
2017-08-22 06:41:25 +00:00
}
}
2017-08-16 22:32:44 +00:00
}
2017-08-25 08:28:14 +00:00
2017-08-27 10:11:05 +00:00
Log2Syslog_closesock ( $ hash , $ sock ) ;
2017-08-25 08:28:14 +00:00
}
2017-08-16 22:32:44 +00:00
return "" ;
}
#################################################################################
# FHEM system logging
#################################################################################
2017-08-27 10:11:05 +00:00
sub Log2Syslog_fhemlog ($$) {
2017-08-16 22:32:44 +00:00
my ( $ name , $ raw ) = @ _ ;
2017-08-18 19:51:33 +00:00
my $ hash = $ defs { $ name } ;
my $ rex = $ hash - > { HELPER } { FHEMLOG } ;
2017-08-25 08:28:14 +00:00
my ( $ prival , $ sock , $ err , $ ret , $ data , $ pid ) ;
2017-08-16 22:32:44 +00:00
2018-08-01 19:20:56 +00:00
return if ( IsDisabled ( $ name ) || ! $ rex || $ hash - > { MODEL } !~ /Sender/ ) ;
2017-08-16 22:32:44 +00:00
2017-08-18 19:51:33 +00:00
my ( $ date , $ time , $ vbose , undef , $ txt ) = split ( " " , $ raw , 5 ) ;
2017-08-27 10:11:05 +00:00
$ txt = Log2Syslog_charfilter ( $ hash , $ txt ) ;
2017-08-16 22:32:44 +00:00
$ date =~ s/\./-/g ;
my $ tim = $ date . " " . $ time ;
2017-08-17 20:20:38 +00:00
2017-08-25 08:28:14 +00:00
if ( $ txt =~ m/^$rex$/ || "$vbose: $txt" =~ m/^$rex$/ ) {
2017-08-18 19:51:33 +00:00
my $ otp = "$vbose: $txt" ;
$ otp = "$tim $otp" if AttrVal ( $ name , 'addTimestamp' , 0 ) ;
2017-08-27 10:11:05 +00:00
$ prival = Log2Syslog_setprival ( $ txt , $ vbose ) ;
2017-08-25 08:28:14 +00:00
2017-08-27 10:11:05 +00:00
( $ data , $ pid ) = Log2Syslog_setpayload ( $ hash , $ prival , $ date , $ time , $ otp , "fhem" ) ;
2017-08-25 08:28:14 +00:00
return if ( ! $ data ) ;
2017-08-20 08:19:32 +00:00
2017-08-27 10:11:05 +00:00
$ sock = Log2Syslog_setsock ( $ hash ) ;
2017-08-22 06:41:25 +00:00
2017-08-25 08:28:14 +00:00
if ( defined ( $ sock ) ) {
$ ret = syswrite $ sock , $ data . "\n" if ( $ data ) ;
2017-08-27 10:11:05 +00:00
if ( $ ret && $ ret > 0 ) {
Log2Syslog_Log3slog ( $ name , 4 , "$name - Payload sequence $pid sent\n" ) ;
2017-08-22 06:41:25 +00:00
} else {
2017-08-25 08:28:14 +00:00
my $ err = $! ;
2017-08-27 10:11:05 +00:00
Log2Syslog_Log3slog ( $ name , 4 , "$name - Warning - Payload sequence $pid NOT sent: $err\n" ) ;
2017-08-25 08:28:14 +00:00
readingsSingleUpdate ( $ hash , "state" , "write error: $err" , 1 ) if ( $ err ne OldValue ( $ name ) ) ;
}
2017-08-27 10:11:05 +00:00
Log2Syslog_closesock ( $ hash , $ sock ) ;
2017-08-17 06:52:49 +00:00
}
2017-08-16 22:32:44 +00:00
}
2017-08-22 06:41:25 +00:00
2017-08-17 20:20:38 +00:00
return ;
2017-08-17 06:52:49 +00:00
}
###############################################################################
2017-08-18 19:51:33 +00:00
# Helper für ident & Regex setzen
###############################################################################
2017-08-27 10:11:05 +00:00
sub Log2Syslog_setidrex ($$) {
2017-08-18 19:51:33 +00:00
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
###############################################################################
2017-08-27 10:11:05 +00:00
sub Log2Syslog_charfilter ($$) {
2017-08-18 19:51:33 +00:00
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 ;
2017-08-22 06:41:25 +00:00
$ txt =~ s/Ä/Ae/g ;
$ txt =~ s/Ö/Oe/g ;
$ txt =~ s/Ü/Ue/g ;
$ txt =~ s/€/EUR/g ;
2017-08-18 19:51:33 +00:00
$ txt =~ tr / A-Za-z0-9!"#$%&'()*+,-.\/:;<=>?@[\]^_`{|}~/ / cd ;
return ( $ txt ) ;
}
###############################################################################
# erstelle Socket
2017-08-17 06:52:49 +00:00
###############################################################################
2017-08-27 10:11:05 +00:00
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 ) ;
2018-08-01 19:20:56 +00:00
my $ ssldbg = AttrVal ( $ name , "ssldebug" , 0 ) ;
2017-08-25 08:28:14 +00:00
my ( $ sock , $ lo , $ sslver , $ sslalgo ) ;
2018-08-01 19:20:56 +00:00
return undef if ( $ init_done != 1 || $ hash - > { MODEL } !~ /Sender/ ) ;
2017-08-25 08:28:14 +00:00
if ( AttrVal ( $ name , "TLS" , 0 ) ) {
# TLS gesicherte Verbindung
# TLS Transport nach RFC5425 https://tools.ietf.org/pdf/rfc5425.pdf
2017-08-27 10:11:05 +00:00
$ attr { $ name } { protocol } = "TCP" if ( AttrVal ( $ name , "protocol" , "UDP" ) ne "TCP" ) ;
2017-08-25 08:28:14 +00:00
$ 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 ) {
2018-08-01 19:20:56 +00:00
$ st = "unable open socket for $host, $protocol, $port: $!" ;
2017-08-25 08:28:14 +00:00
} else {
$ sock - > blocking ( 1 ) ;
2018-08-01 19:20:56 +00:00
$ IO:: Socket:: SSL:: DEBUG = $ ssldbg ;
2017-08-25 08:28:14 +00:00
eval { IO::Socket::SSL - > start_SSL ( $ sock ,
2018-08-01 19:20:56 +00:00
SSL_verify_mode = > 0 ,
SSL_version = > "TLSv1_2:!TLSv1_1:!SSLv3:!SSLv23:!SSLv2" ,
2017-08-25 08:28:14 +00:00
SSL_hostname = > $ host ,
SSL_veriycn_scheme = > "rfc5425" ,
SSL_veriycn_publicsuffix = > '' ,
Timeout = > $ timeout
) || undef $ sock ; } ;
2018-08-01 19:20:56 +00:00
$ IO:: Socket:: SSL:: DEBUG = 0 ;
if ( $@ ) {
$ st = "SSL error: $@" ;
undef $ sock ;
} elsif ( ! $ sock ) {
2017-08-25 08:28:14 +00:00
$ st = "SSL error: " . IO::Socket::SSL:: errstr ( ) ;
2018-08-01 19:20:56 +00:00
undef $ sock ;
2017-08-25 08:28:14 +00:00
} else {
$ sslver = $ sock - > get_sslversion ( ) ;
$ sslalgo = $ sock - > get_fingerprint ( ) ;
$ sslalgo = ( split ( "\\\$" , $ sslalgo ) ) [ 0 ] ;
2017-08-27 10:11:05 +00:00
$ lo = "Socket opened for Host: $host, Protocol: $protocol, Port: $port, TLS: 0" ;
2018-08-01 19:20:56 +00:00
$ st = "active" ;
2017-08-25 08:28:14 +00:00
}
}
}
2017-08-22 06:41:25 +00:00
} else {
2017-08-25 08:28:14 +00:00
# erstellt ungesicherte Socket Verbindung
$ sslver = "n.a." ;
$ sslalgo = "n.a." ;
2017-08-27 10:11:05 +00:00
$ sock = new IO::Socket:: INET ( PeerHost = > $ host , PeerPort = > $ port , Proto = > $ protocol , Timeout = > $ timeout ) ;
2017-08-25 08:28:14 +00:00
if ( ! $ sock ) {
undef $ sock ;
2018-08-01 19:20:56 +00:00
$ st = "unable open socket for $host, $protocol, $port: $!" ;
2017-08-25 08:28:14 +00:00
} else {
$ sock - > blocking ( 0 ) ;
# Logausgabe (nur in das fhem Logfile !)
2017-08-27 10:11:05 +00:00
$ lo = "Socket opened for Host: $host, Protocol: $protocol, Port: $port, TLS: 0" ;
2017-08-25 08:28:14 +00:00
}
}
readingsSingleUpdate ( $ hash , "state" , $ st , 1 ) if ( $ st ne OldValue ( $ name ) ) ;
if ( $ sslver ne $ hash - > { HELPER } { SSLVER } ) {
readingsSingleUpdate ( $ hash , "SSL_Version" , $ sslver , 1 ) ;
$ hash - > { HELPER } { SSLVER } = $ sslver ;
2017-08-22 06:41:25 +00:00
}
2018-08-01 19:20:56 +00:00
2017-08-25 08:28:14 +00:00
if ( $ sslalgo ne $ hash - > { HELPER } { SSLALGO } ) {
readingsSingleUpdate ( $ hash , "SSL_Algorithm" , $ sslalgo , 1 ) ;
$ hash - > { HELPER } { SSLALGO } = $ sslalgo ;
}
2017-08-27 10:11:05 +00:00
Log2Syslog_Log3slog ( $ name , 5 , "$name - $lo" ) if ( $ lo ) ;
2017-08-20 08:19:32 +00:00
2017-08-17 06:52:49 +00:00
return ( $ sock ) ;
2017-08-16 22:32:44 +00:00
}
2017-08-27 10:11:05 +00:00
###############################################################################
# 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 ;
}
2017-08-16 22:32:44 +00:00
###############################################################################
# set PRIVAL (severity & facility)
###############################################################################
2017-08-27 10:11:05 +00:00
sub Log2Syslog_setprival ($;$$) {
2017-08-18 19:51:33 +00:00
my ( $ txt , $ vbose ) = @ _ ;
2017-08-16 22:32:44 +00:00
my $ prival ;
# Priority = (facility * 8) + severity
2017-08-19 15:09:53 +00:00
# https://tools.ietf.org/pdf/rfc5424.pdf
2017-08-16 22:32:44 +00:00
# determine facility
2018-08-01 19:20:56 +00:00
my $ fac = 5 ; # facility by syslogd
2017-08-16 22:32:44 +00:00
# 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 ) ;
}
2017-08-18 19:51:33 +00:00
$ sv = 3 if ( lc ( $ txt ) =~ m/error/ ) ; # error condition
$ sv = 4 if ( lc ( $ txt ) =~ m/warning/ ) ; # warning conditions
2017-08-16 22:32:44 +00:00
$ prival = ( $ fac * 8 ) + $ sv ;
return ( $ prival ) ;
}
###############################################################################
2017-08-18 19:51:33 +00:00
# erstellen Payload für Syslog
2017-08-16 22:32:44 +00:00
###############################################################################
2017-08-27 10:11:05 +00:00
sub Log2Syslog_setpayload ($$$$$$) {
2017-08-18 19:51:33 +00:00
my ( $ hash , $ prival , $ date , $ time , $ otp , $ lt ) = @ _ ;
2017-08-16 22:32:44 +00:00
my $ name = $ hash - > { NAME } ;
2017-08-18 19:51:33 +00:00
my $ ident = ( $ hash - > { HELPER } { IDENT } ? $ hash - > { HELPER } { IDENT } : $ name ) . "_" . $ lt ;
2017-08-16 22:32:44 +00:00
my $ myhost = $ hash - > { MYHOST } ? $ hash - > { MYHOST } : "0.0.0.0" ;
my $ lf = AttrVal ( $ name , "logFormat" , "IETF" ) ;
my $ data ;
2017-08-25 08:28:14 +00:00
return undef , undef if ( ! $ otp ) ;
2018-08-01 19:20:56 +00:00
my $ pid = $ hash - > { SEQNO } ; # PayloadID zur Nachverfolgung der Eventabfolge
2017-08-25 08:28:14 +00:00
$ hash - > { SEQNO } + + ;
2017-08-16 22:32:44 +00:00
my ( $ year , $ month , $ day ) = split ( "-" , $ date ) ;
if ( $ lf eq "BSD" ) {
# BSD Protokollformat https://tools.ietf.org/html/rfc3164
2017-08-27 10:11:05 +00:00
$ time = ( split ( /\./ , $ time ) ) [ 0 ] if ( $ time =~ m/\./ ) ; # msec ist nicht erlaubt
2018-08-01 19:20:56 +00:00
$ 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
2017-08-16 22:32:44 +00:00
no warnings 'uninitialized' ;
2017-08-25 08:28:14 +00:00
$ data = "<$prival>$month $day $time $myhost $ident: : $otp" ;
2017-08-16 22:32:44 +00:00
use warnings ;
2018-08-01 19:20:56 +00:00
$ data = substr ( $ data , 0 , ( $ RFC3164len { DL } - 1 ) ) ; # Länge Total begrenzen
2017-08-16 22:32:44 +00:00
}
if ( $ lf eq "IETF" ) {
2017-08-25 08:28:14 +00:00
# IETF Protokollformat https://tools.ietf.org/html/rfc5424
2018-08-01 19:20:56 +00:00
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" ;
}
2017-08-16 22:32:44 +00:00
use warnings ;
}
2017-08-27 10:11:05 +00:00
if ( $ data =~ /\s$/ ) { $ data =~ s/\s$// ; }
2018-08-01 19:20:56 +00:00
my $ dl = length ( $ data ) ; # Länge muss ! für TLS stimmen, sonst keine Ausgabe !
2017-08-25 08:28:14 +00:00
# wenn Transport Layer Security (TLS) -> Transport Mapping for Syslog https://tools.ietf.org/pdf/rfc5425.pdf
if ( AttrVal ( $ name , "TLS" , 0 ) ) {
$ data = "$dl $data" ;
2018-08-01 19:20:56 +00:00
$ 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 ) ) ;
2017-08-25 08:28:14 +00:00
}
2017-08-22 06:41:25 +00:00
my $ ldat = ( $ dl > 130 ) ? ( substr ( $ data , 0 , 130 ) . " ..." ) : $ data ;
2017-08-27 10:11:05 +00:00
Log2Syslog_Log3slog ( $ name , 4 , "$name - Payload sequence $pid created:\n$ldat" ) ;
2017-08-22 06:41:25 +00:00
2017-08-25 08:28:14 +00:00
return ( $ data , $ pid ) ;
2017-08-16 22:32:44 +00:00
}
2017-08-20 08:19:32 +00:00
###############################################################################
# eigene Log3-Ableitung - Schleife vermeiden
###############################################################################
2017-08-27 10:11:05 +00:00
sub Log2Syslog_Log3slog ($$$) {
2017-08-20 08:19:32 +00:00
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 ;
}
2017-08-25 08:28:14 +00:00
###############################################################################
# Bestimmung Übertragungsrate
###############################################################################
2017-08-27 10:11:05 +00:00
sub Log2Syslog_trate ($) {
2017-08-25 08:28:14 +00:00
my ( $ hash ) = @ _ ;
2017-08-27 10:11:05 +00:00
my $ name = $ hash - > { NAME } ;
2017-08-27 10:50:18 +00:00
my $ rerun = AttrVal ( $ name , "rateCalcRerun" , 60 ) ;
2017-08-25 08:28:14 +00:00
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 ( ) ;
2017-08-27 10:11:05 +00:00
my $ ospm = ReadingsVal ( $ name , "Transfered_logs_per_minute" , 0 ) ;
2017-08-25 08:28:14 +00:00
if ( $ spm != $ ospm ) {
readingsSingleUpdate ( $ hash , "Transfered_logs_per_minute" , $ spm , 1 ) ;
2017-08-27 10:11:05 +00:00
} else {
readingsSingleUpdate ( $ hash , "Transfered_logs_per_minute" , $ spm , 0 ) ;
}
2017-08-25 08:28:14 +00:00
}
2017-08-27 10:11:05 +00:00
RemoveInternalTimer ( $ hash , "Log2Syslog_trate" ) ;
InternalTimer ( gettimeofday ( ) + $ rerun , "Log2Syslog_trate" , $ hash , 0 ) ;
2018-08-01 19:20:56 +00:00
2017-08-25 08:28:14 +00:00
return ;
}
2017-08-16 22:32:44 +00:00
1 ;
= pod
= item helper
2018-08-01 19:20:56 +00:00
= 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
2017-08-16 22:32:44 +00:00
= begin html
< a name = "Log2Syslog" > </a>
<h3> Log2Syslog </h3>
<ul>
2017-08-25 08:28:14 +00:00
Send FHEM system log entries and / or FHEM events to an external syslog server . <br>
The syslog protocol has been implemented according the specifications of < a href = "https://tools.ietf.org/html/rfc5424" > RFC5424 ( IETF ) </a> ,
2018-08-01 19:20:56 +00:00
< a href = "https://tools.ietf.org/html/rfc3164" > RFC3164 ( BSD ) </a> and the TLS transport protocol according to
2017-08-25 08:28:14 +00:00
< a href = "https://tools.ietf.org/pdf/rfc5425.pdf" > RFC5425 </a> . <br>
<br>
2017-08-16 22:32:44 +00:00
<b> Prerequisits </b>
<ul>
<br/>
The additional perl module "IO::Socket::INET" must be installed on your system . <br>
Install this package from cpan or by <br> <br>
<code> apt - get install libio - socket - multicast - perl ( only on Debian based installations ) </code> <br>
</ul>
<br>
< a name = "Log2Syslogdefine" > </a>
<b> Define </b>
<ul>
<br>
2017-08-18 19:51:33 +00:00
<code> define & lt ; name & gt ; Log2Syslog & lt ; destination host & gt ; [ ident: & lt ; ident & gt ; ] [ event: & lt ; regexp & gt ; ] [ fhem: & lt ; regexp & gt ; ] </code> <br>
2017-08-16 22:32:44 +00:00
<br>
& lt ; destination host & gt ; = host where the syslog server is running <br>
2017-08-18 19:51:33 +00:00
[ ident: & lt ; ident & gt ; ] = optional program identifier . If not set the device name will be used as default <br>
2017-08-16 23:06:15 +00:00
[ event: & lt ; regexp & gt ; ] = optional regex to filter events for logging <br>
[ fhem: & lt ; regexp & gt ; ] = optional regex to filter fhem system log for logging <br> <br>
2017-08-16 22:32:44 +00:00
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 . <br>
2017-08-19 15:09:53 +00:00
Without setting regex no fhem system log or event log will be forwarded . <br> <br>
The verbose level of FHEM system logs will convert into equivalent syslog severity level . <br>
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 . <br> <br>
<b> Lookup table Verbose - Level to Syslog severity level: </b> <br> <br>
<ul>
<table>
<colgroup> < col width = 40 % > < col width = 60 % > < / colgroup >
2018-08-01 19:20:56 +00:00
<tr> <td> <b> verbose - Level </b> </td> <td> <b> Severity in Syslog </b> </td> </tr>
2017-08-19 15:09:53 +00:00
<tr> <td> 0 </td> <td> Critical </td> </tr>
<tr> <td> 1 </td> <td> Error </td> </tr>
<tr> <td> 2 </td> <td> Warning </td> </tr>
<tr> <td> 3 </td> <td> Notice </td> </tr>
<tr> <td> 4 </td> <td> Informational </td> </tr>
<tr> <td> 5 </td> <td> Debug </td> </tr>
</table>
</ul>
<br>
2017-08-16 22:32:44 +00:00
<br>
Example to log anything: <br>
<br/>
2017-08-18 19:51:33 +00:00
<code> define splunklog Log2Syslog fhemtest 192.168 .2 .49 ident:Test event: . * fhem: . * </code> <br>
2017-08-16 22:32:44 +00:00
<br/>
2017-08-18 19:51:33 +00:00
will produce output like this raw example of a splunk syslog server: <br/>
<pre> Aug 18 21 : 06 : 46 fhemtest . myds . me 1 2017 - 08 - 18 T21: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 - 18 T21: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 - 18 T21:06:45 fhemtest . myds . me Test_event 13339 FHEM - : LogDB CacheUsage: 21
Aug 18 21 : 08 : 27 fhemtest . myds . me 1 2017 - 08 - 18 T21: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 - 18 T21:08:27 .095 fhemtest . myds . me Test_fhem 13339 FHEM - : 4 : CamTER - CAMID already set - ignore get camid
</pre>
2017-08-27 10:11:05 +00:00
The structure of the payload differs dependent of the used logFormat . <br> <br>
<b> logFormat IETF: </b> <br> <br>
2018-08-01 19:20:56 +00:00
"<PRIVAL>VERSION TIME MYHOST IDENT PID MID [SD-FIELD] :MESSAGE" <br> <br>
2017-08-27 10:11:05 +00:00
<ul>
<table>
<colgroup> < col width = 10 % > < col width = 90 % > < / colgroup >
<tr> <td> PRIVAL </td> <td> priority value ( coded from "facility" and "severity" ) </td> </tr>
<tr> <td> TIME </td> <td> timestamp according to RFC5424 </td> </tr>
<tr> <td> MYHOST </td> <td> Internal MYHOST </td> </tr>
<tr> <td> IDENT </td> <td> 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 ) . </td> </tr>
<tr> <td> PID </td> <td> sequential Payload - ID </td> </tr>
<tr> <td> MID </td> <td> fix value "FHEM" </td> </tr>
<tr> <td> MESSAGE </td> <td> the dataset to transfer </td> </tr>
</table>
</ul>
<br>
<b> logFormat BSD: </b> <br> <br>
"<PRIVAL>MONAT TAG TIME MYHOST IDENT: : MESSAGE" <br> <br>
<ul>
<table>
<colgroup> < col width = 10 % > < col width = 90 % > < / colgroup >
<tr> <td> PRIVAL </td> <td> priority value ( coded from "facility" and "severity" ) </td> </tr>
<tr> <td> MONAT </td> <td> month according to RFC3164 </td> </tr>
<tr> <td> TAG </td> <td> day of month according to RFC3164 </td> </tr>
<tr> <td> TIME </td> <td> timestamp according to RFC3164 </td> </tr>
<tr> <td> MYHOST </td> <td> Internal MYHOST </td> </tr>
<tr> <td> IDENT </td> <td> 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 ) . </td> </tr>
<tr> <td> MESSAGE </td> <td> the dataset to transfer </td> </tr>
</table>
</ul>
<br>
2017-08-25 08:28:14 +00:00
2017-08-16 22:32:44 +00:00
</ul>
2017-08-25 08:28:14 +00:00
<br>
2017-08-16 22:32:44 +00:00
2018-08-01 19:20:56 +00:00
< a name = "Log2SyslogGet" > </a>
<b> Get </b>
<ul>
<br>
<li> <code> certinfo </code> <br>
<br>
Show informations about the server certificate if a TLS - session was created ( Reading "SSL_Version" isn ' t "n.a." ) .
</li> <br>
</ul>
<br>
2017-08-16 22:32:44 +00:00
< a name = "Log2Syslogattr" > </a>
<b> Attributes </b>
<ul>
<br/>
< a name = "addTimestamp" > </a>
<li> <code> addTimestamp [ 0 | 1 ] </code> <br>
<br/>
If set to 1 , fhem timestamps will be logged too . <br/>
Default behavior is to not log these timestamps , because syslog uses own timestamps . <br/>
Maybe useful if mseclog is activated in fhem . <br/>
<br/>
2017-08-18 19:51:33 +00:00
Example output ( raw ) of a Splunk syslog server: <br>
<pre> Aug 18 21 : 26 : 55 fhemtest . myds . me 1 2017 - 08 - 18 T21:26:55 fhemtest . myds . me Test_event 13339 FHEM - : 2017 - 08 - 18 21 : 26 : 55 USV state: OL
Aug 18 21 : 26 : 54 fhemtest . myds . me 1 2017 - 08 - 18 T21:26:54 fhemtest . myds . me Test_event 13339 FHEM - : 2017 - 08 - 18 21 : 26 : 54 Bezug state: done
Aug 18 21 : 26 : 54 fhemtest . myds . me 1 2017 - 08 - 18 T21:26:54 fhemtest . myds . me Test_event 13339 FHEM - : 2017 - 08 - 18 21 : 26 : 54 recalc_Bezug state: Next: 21 : 31 : 59
</pre>
2017-08-16 22:32:44 +00:00
</li> <br>
<li> <code> addStateEvent [ 0 | 1 ] </code> <br>
<br>
If set to 1 , events will be completed with "state" if a state - event appears . <br/>
Default behavior is without getting "state" .
</li> <br>
2017-08-18 19:51:33 +00:00
<li> <code> disable [ 0 | 1 ] </code> <br>
<br>
disables the device .
</li> <br>
2017-08-16 22:32:44 +00:00
<li> <code> logFormat [ BSD | IETF ] </code> <br>
<br>
Set the syslog protocol format . <br>
2017-08-17 20:20:38 +00:00
Default value is "IETF" if not specified .
</li> <br>
2017-08-16 22:32:44 +00:00
2017-08-27 10:11:05 +00:00
<li> <code> protocol [ TCP | UDP ] </code> <br>
2017-08-16 22:32:44 +00:00
<br>
2017-08-27 10:11:05 +00:00
Sets the socket protocol which should be used . You can choose UDP or TCP . <br>
2017-08-16 22:32:44 +00:00
Default value is "UDP" if not specified .
</li> <br>
<li> <code> port </code> <br>
<br>
2018-08-01 19:20:56 +00:00
The used port . For a Sender the default - port is 514 .
A Collector ( Syslog - Server ) uses the port 1514 per default .
2017-08-16 22:32:44 +00:00
</li> <br>
2017-08-27 10:50:18 +00:00
<li> <code> rateCalcRerun </code> <br>
2017-08-27 10:11:05 +00:00
<br>
Rerun cycle for calculation of log transfer rate ( Reading "Transfered_logs_per_minute" ) in seconds .
Default is 60 seconds .
</li> <br>
2018-08-01 19:20:56 +00:00
<li> <code> ssldebug </code> <br>
<br>
Debugging level of SSL messages . <br> <br>
<ul>
<li> 0 - No debugging ( default ) . </li>
<li> 1 - Print out errors from < a href = "http://search.cpan.org/~sullr/IO-Socket-SSL-2.056/lib/IO/Socket/SSL.pod" > IO::Socket:: SSL </a> and ciphers from < a href = "http://search.cpan.org/~mikem/Net-SSLeay-1.85/lib/Net/SSLeay.pod" > Net:: SSLeay </a> . </li>
<li> 2 - Print also information about call flow from < a href = "http://search.cpan.org/~sullr/IO-Socket-SSL-2.056/lib/IO/Socket/SSL.pod" > IO::Socket:: SSL </a> and progress information from < a href = "http://search.cpan.org/~mikem/Net-SSLeay-1.85/lib/Net/SSLeay.pod" > Net:: SSLeay </a> . </li>
<li> 3 - Print also some data dumps from < a href = "http://search.cpan.org/~sullr/IO-Socket-SSL-2.056/lib/IO/Socket/SSL.pod" > IO::Socket:: SSL </a> and from < a href = "http://search.cpan.org/~mikem/Net-SSLeay-1.85/lib/Net/SSLeay.pod" > Net:: SSLeay </a> . </li>
</ul>
</li> <br>
2017-08-27 10:11:05 +00:00
2018-08-01 19:20:56 +00:00
<li> <code> TLS </code> <br>
<br>
A secured connection to Syslog - server is used . The protocol will be switched to TCP automatically .
</li> <br>
2017-08-25 08:28:14 +00:00
<li> <code> timeout </code> <br>
<br>
2018-08-01 19:20:56 +00:00
Timeout for connection to the destination syslog server ( TCP ) . Only valid in Sender - mode . Default: 0.5 seconds .
2017-08-25 08:28:14 +00:00
</li> <br>
2017-08-22 06:41:25 +00:00
<li> <code> verbose </code> <br>
<br>
To avoid loops , the output of verbose level of the Log2Syslog - Devices will only be reported into the local FHEM Logfile and
no forwarded .
</li> <br>
2017-08-16 22:32:44 +00:00
</ul>
2017-08-27 10:38:38 +00:00
<br>
< a name = "Log2Syslogreadings" > </a>
<b> Readings </b>
<ul>
<br>
<table>
<colgroup> < col width = 40 % > < col width = 60 % > < / colgroup >
<tr> <td> <b> SSL_Algorithm </b> </td> <td> used SSL algorithm if SSL is enabled and active </td> </tr>
<tr> <td> <b> SSL_Version </b> </td> <td> the used TLS - version if encryption is enabled and is active </td> </tr>
<tr> <td> <b> Transfered_logs_per_minute </b> </td> <td> the average number of forwarded logs /events per minute </ td > </tr>
</table>
<br>
</ul>
2017-08-16 22:32:44 +00:00
</ul>
= end html
= begin html_DE
< a name = "Log2Syslog" > </a>
<h3> Log2Syslog </h3>
<ul>
2018-08-01 19:20:56 +00:00
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 . <br>
2017-08-25 08:28:14 +00:00
Die Implementierung des Syslog - Protokolls erfolgte entsprechend den Vorgaben von < a href = "https://tools.ietf.org/html/rfc5424" > RFC5424 ( IETF ) </a> ,
< a href = "https://tools.ietf.org/html/rfc3164" > RFC3164 ( BSD ) </a> sowie dem TLS Transport Protokoll nach
< a href = "https://tools.ietf.org/pdf/rfc5425.pdf" > RFC5425 </a> . <br>
<br>
2017-08-16 22:32:44 +00:00
<b> Voraussetzungen </b>
<ul>
<br/>
Es wird das Perl Modul "IO::Socket::INET" benötigt und muss installiert sein . <br>
Das Modul kann über CPAN oder mit <br> <br>
<code> apt - get install libio - socket - multicast - perl ( auf Debian Linux Systemen ) </code> <br> <br>
installiert werden .
</ul>
<br/>
< a name = "Log2Syslogdefine" > </a>
<b> Definition </b>
<ul>
<br>
2018-08-01 19:20:56 +00:00
Je nach Verwendungszweck kann ein Syslog - Server ( MODEL Collector ) oder ein Syslog - Client ( MODEL Sender ) definiert
werden . <br>
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 . <br>
<br>
<br>
<b> Definition eines Collectors </b>
<br>
<ul>
<br>
<code> define & lt ; name & gt ; Log2Syslog </code> <br>
<br>
</ul>
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 < a href = "#Log2Syslogattr" > Attribut </a> "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 < a href = "#Log2Syslogattr" > Attribut </a> "parseProfile" ) . <br> <br>
2017-08-16 22:32:44 +00:00
<br>
2018-08-01 19:20:56 +00:00
<b> Beispiel für einen Collector: </b> <br>
<ul>
<br>
<code> define SyslogServer Log2Syslog </code> <br>
<br>
</ul>
Im Eventmonitor können die generierten Events kontrolliert werden ( Beispiel mit Attribut parseProfile = default ) : <br>
<pre>
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
</pre>
Zwischen den einzelnen Feldern wird der Trenner "||" verwendet .
Die Bedeutung der Felder ist in nachfolgender Tabelle aufgeführt .
<br> <br>
<ul>
<table>
<colgroup> < col width = 20 % > < col width = 80 % > < / colgroup >
<tr> <td> <b> HOST </b> </td> <td> der Sender des Datensatzes </td> </tr>
<tr> <td> <b> FAC </b> </td> <td> Facility ( Kategorie ) nach RFC5424 </td> </tr>
<tr> <td> <b> SEV </b> </td> <td> Severity ( Schweregrad ) nach RFC5424 </td> </tr>
<tr> <td> <b> ID </b> </td> <td> Ident - Tag </td> </tr>
<tr> <td> <b> CONT </b> </td> <td> die übertragene Nachricht </td> </tr>
</table>
</ul>
<br>
<br>
<br>
<b> Definition eines Senders </b>
<br>
<ul>
<br>
<code> define & lt ; name & gt ; Log2Syslog & lt ; Zielhost & gt ; [ ident: & lt ; ident & gt ; ] [ event: & lt ; regexp & gt ; ] [ fhem: & lt ; regexp & gt ; ] </code> <br>
<br>
</ul>
<ul>
<table>
<colgroup> < col width = 20 % > < col width = 80 % > < / colgroup >
<tr> <td> <b> & lt ; Zielhost & gt ; </b> </td> <td> Host ( Name oder IP - Adresse ) auf dem der Syslog - Server läuft </td> </tr>
<tr> <td> <b> [ ident: & lt ; ident & gt ; ] </b> </td> <td> optionaler Programm Identifier . Wenn nicht gesetzt wird per default der Devicename benutzt . </td> </tr>
<tr> <td> <b> [ event: & lt ; regexp & gt ; ] </b> </td> <td> optionaler regulärer Ausdruck zur Filterung von Events zur Weiterleitung </td> </tr>
<tr> <td> <b> [ fhem: & lt ; regexp & gt ; ] </b> </td> <td> optionaler regulärer Ausdruck zur Filterung von FHEM Logs zur Weiterleitung </td> </tr>
</table>
</ul>
<br> <br>
2017-08-16 22:32:44 +00:00
Direkt nach der Definition sendet das neue Device alle neu auftretenden FHEM Systemlog Einträge und Events ohne weitere
2017-08-19 15:09:53 +00:00
Einstellungen an den Zielhost , Port = 514 /UDP Format=IETF, wenn reguläre Ausdrücke für Events/ FHEM angegeben wurden . <br>
Wurde kein Regex gesetzt , erfolgt keine Weiterleitung von Events oder FHEM Systemlogs . <br> <br>
Die Verbose - Level der FHEM Systemlogs werden in entsprechende Schweregrade der Syslog - Messages umgewandelt . <br>
Weiterhin wird der Meldungstext der FHEM Systemlogs und Events nach den Signalwörtern "warning" und "error" durchsucht
2018-08-01 19:20:56 +00:00
( Groß - / Kleinschreibung wird nicht beachtet ) . Davon abhängig wird der Schweregrad ebenfalls äquivalent gesetzt und übersteuert
2017-08-19 15:09:53 +00:00
einen eventuell bereits durch Verbose - Level gesetzten Schweregrad . <br> <br>
<b> Umsetzungstabelle Verbose - Level in Syslog - Schweregrad Stufe: </b> <br> <br>
<ul>
<table>
<colgroup> < col width = 40 % > < col width = 60 % > < / colgroup >
<tr> <td> <b> Verbose - Level </b> </td> <td> <b> Schweregrad in Syslog </b> </td> </tr>
<tr> <td> 0 </td> <td> Critical </td> </tr>
<tr> <td> 1 </td> <td> Error </td> </tr>
<tr> <td> 2 </td> <td> Warning </td> </tr>
<tr> <td> 3 </td> <td> Notice </td> </tr>
<tr> <td> 4 </td> <td> Informational </td> </tr>
<tr> <td> 5 </td> <td> Debug </td> </tr>
</table>
</ul>
<br>
2017-08-16 22:32:44 +00:00
<br>
2018-08-01 19:20:56 +00:00
<b> Beispiel für einen Sender: </b> <br>
<ul>
<br>
2017-08-18 19:51:33 +00:00
<code> define splunklog Log2Syslog fhemtest 192.168 .2 .49 ident:Test event: . * fhem: . * </code> <br/>
2018-08-01 19:20:56 +00:00
<br>
</ul>
Es werden alle Events weitergeleitet wie deses Beispiel der raw - Ausgabe eines Splunk Syslog Servers zeigt: <br/>
<pre>
Aug 18 21 : 06 : 46 fhemtest . myds . me 1 2017 - 08 - 18 T21:06:46 fhemtest . myds . me Test_event 13339 FHEM - : LogDB sql_processing_time: 0.2306
2017-08-18 19:51:33 +00:00
Aug 18 21 : 06 : 46 fhemtest . myds . me 1 2017 - 08 - 18 T21: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 - 18 T21:06:45 fhemtest . myds . me Test_event 13339 FHEM - : LogDB CacheUsage: 21
Aug 18 21 : 08 : 27 fhemtest . myds . me 1 2017 - 08 - 18 T21: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 - 18 T21:08:27 .095 fhemtest . myds . me Test_fhem 13339 FHEM - : 4 : CamTER - CAMID already set - ignore get camid
</pre>
2017-08-16 22:32:44 +00:00
2017-08-25 08:28:14 +00:00
Der Aufbau der Payload unterscheidet sich je nach verwendeten logFormat . <br> <br>
<b> logFormat IETF: </b> <br> <br>
2018-08-01 19:20:56 +00:00
"<PRIVAL>VERSION TIME MYHOST IDENT PID MID [SD-FIELD] :MESSAGE" <br> <br>
2017-08-25 08:28:14 +00:00
<ul>
<table>
<colgroup> < col width = 10 % > < col width = 90 % > < / colgroup >
<tr> <td> PRIVAL </td> <td> Priority Wert ( kodiert aus "facility" und "severity" ) </td> </tr>
<tr> <td> TIME </td> <td> Timestamp nach RFC5424 </td> </tr>
<tr> <td> MYHOST </td> <td> Internal MYHOST </td> </tr>
<tr> <td> IDENT </td> <td> Ident - Tag aus DEF wenn angegeben , sonst der eigene Devicename . Die Angabe wird mit "_fhem" ( FHEM - Log ) bzw . "_event" ( Event - Log ) ergänzt . </td> </tr>
<tr> <td> PID </td> <td> fortlaufende Payload - ID </td> </tr>
<tr> <td> MID </td> <td> fester Wert "FHEM" </td> </tr>
<tr> <td> MESSAGE </td> <td> der zu übertragende Datensatz </td> </tr>
</table>
</ul>
<br>
<b> logFormat BSD: </b> <br> <br>
"<PRIVAL>MONAT TAG TIME MYHOST IDENT: : MESSAGE" <br> <br>
<ul>
<table>
<colgroup> < col width = 10 % > < col width = 90 % > < / colgroup >
<tr> <td> PRIVAL </td> <td> Priority Wert ( kodiert aus "facility" und "severity" ) </td> </tr>
<tr> <td> MONAT </td> <td> Monatsangabe nach RFC3164 </td> </tr>
<tr> <td> TAG </td> <td> Tag des Monats nach RFC3164 </td> </tr>
<tr> <td> TIME </td> <td> Zeitangabe nach RFC3164 </td> </tr>
<tr> <td> MYHOST </td> <td> Internal MYHOST </td> </tr>
<tr> <td> IDENT </td> <td> Ident - Tag aus DEF wenn angegeben , sonst der eigene Devicename . Die Angabe wird mit "_fhem" ( FHEM - Log ) bzw . "_event" ( Event - Log ) ergänzt . </td> </tr>
<tr> <td> MESSAGE </td> <td> der zu übertragende Datensatz </td> </tr>
</table>
</ul>
<br>
</ul>
<br> <br>
2018-08-01 19:20:56 +00:00
< a name = "Log2SyslogGet" > </a>
<b> Get </b>
<ul>
<br>
<li> <code> certinfo </code> <br>
<br>
Zeigt Informationen zum Serverzertifikat wenn eine TLS - Session aufgebaut wurde ( Reading "SSL_Version" ist nicht "n.a." ) .
</li> <br>
</ul>
<br>
2017-08-16 22:32:44 +00:00
< a name = "Log2Syslogattr" > </a>
<b> Attribute </b>
<ul>
<br>
< a name = "addTimestamp" > </a>
<li> <code> addTimestamp [ 0 | 1 ] </code> <br>
<br/>
2018-08-01 19:20:56 +00:00
Das Attribut ist nur für "Sender" verwendbar . Wenn gesetzt , werden FHEM Timestamps im Datensatz mit übertragen . <br/>
2017-08-16 22:32:44 +00:00
Per default werden die Timestamps nicht mit übertragen , da der Syslog - Server eigene Timestamps verwendet . <br/>
Die Einstellung kann hilfeich sein wenn mseclog in FHEM aktiviert ist . <br/>
<br/>
2017-08-18 19:51:33 +00:00
Beispielausgabe ( raw ) eines Splunk Syslog Servers: <br/>
<pre> Aug 18 21 : 26 : 55 fhemtest . myds . me 1 2017 - 08 - 18 T21:26:55 fhemtest . myds . me Test_event 13339 FHEM - : 2017 - 08 - 18 21 : 26 : 55 USV state: OL
Aug 18 21 : 26 : 54 fhemtest . myds . me 1 2017 - 08 - 18 T21:26:54 fhemtest . myds . me Test_event 13339 FHEM - : 2017 - 08 - 18 21 : 26 : 54 Bezug state: done
Aug 18 21 : 26 : 54 fhemtest . myds . me 1 2017 - 08 - 18 T21:26:54 fhemtest . myds . me Test_event 13339 FHEM - : 2017 - 08 - 18 21 : 26 : 54 recalc_Bezug state: Next: 21 : 31 : 59
</pre>
2017-08-16 22:32:44 +00:00
</li> <br>
<li> <code> addStateEvent [ 0 | 1 ] </code> <br>
<br>
2018-08-01 19:20:56 +00:00
Das Attribut ist nur für "Sender" verwendbar . Wenn gesetzt , werden state - events mit dem Reading "state" ergänzt . <br/>
2017-08-16 22:32:44 +00:00
Die Standardeinstellung ist ohne state - Ergänzung .
</li> <br>
2017-08-18 19:51:33 +00:00
<li> <code> disable [ 0 | 1 ] </code> <br>
<br>
Das Device wird aktiviert | aktiviert .
</li> <br>
2017-08-16 22:32:44 +00:00
<li> <code> logFormat [ BSD | IETF ] </code> <br>
<br>
Stellt das Protokollformat ein . <br>
2017-08-17 20:20:38 +00:00
Der Standardwert ist "IETF" . <br>
2017-08-16 22:32:44 +00:00
</li> <br>
2018-08-01 19:20:56 +00:00
<li> <code> parseProfile [ default | raw ] </code> <br>
<br>
Auswahl eines Parsing - Profiles . Wird "raw" gewählt , erfolgt kein Parsing und die empfangenen Daten werden
unverändert in ein Event umgesetzt . <br>
Das "default" - Profil wendet ein Parsing entsprechend der RFC - Richtlinien an ( Voreinstellung ) .
</li> <br>
2017-08-16 22:32:44 +00:00
2017-08-27 10:11:05 +00:00
<li> <code> protocol [ TCP | UDP ] </code> <br>
2017-08-16 22:32:44 +00:00
<br>
2018-08-01 19:20:56 +00:00
Setzt den Protokolltyp der verwendet werden soll . Es kann UDP oder TCP gewählt werden ( MODEL Sender ) . <br>
2017-08-16 22:32:44 +00:00
Standard ist "UDP" wenn nichts spezifiziert ist .
2018-08-01 19:20:56 +00:00
Ein Syslog - Server ( MODEL Collector ) verwendet UDP .
2017-08-16 22:32:44 +00:00
</li> <br>
<li> <code> port </code> <br>
<br>
2018-08-01 19:20:56 +00:00
Der verwendete Port . Für einen Sender ist der default - Port 514 .
Ein Collector ( Syslog - Server ) verwendet den Port 1514 per default .
2017-08-16 22:32:44 +00:00
</li> <br>
2017-08-27 10:50:18 +00:00
<li> <code> rateCalcRerun </code> <br>
2017-08-27 10:11:05 +00:00
<br>
Wiederholungszyklus für die Bestimmung der Log - Transferrate ( Reading "Transfered_logs_per_minute" ) in Sekunden .
Default sind 60 Sekunden .
</li> <br>
2018-08-01 19:20:56 +00:00
<li> <code> ssldebug </code> <br>
<br>
Debugging Level von SSL Messages . <br> <br>
<ul>
<li> 0 - Kein Debugging ( default ) . </li>
<li> 1 - Ausgabe Errors von from < a href = "http://search.cpan.org/~sullr/IO-Socket-SSL-2.056/lib/IO/Socket/SSL.pod" > IO::Socket:: SSL </a> und ciphers von < a href = "http://search.cpan.org/~mikem/Net-SSLeay-1.85/lib/Net/SSLeay.pod" > Net:: SSLeay </a> . </li>
<li> 2 - zusätzliche Ausgabe von Informationen über den Protokollfluss von < a href = "http://search.cpan.org/~sullr/IO-Socket-SSL-2.056/lib/IO/Socket/SSL.pod" > IO::Socket:: SSL </a> und Fortschritinformationen von < a href = "http://search.cpan.org/~mikem/Net-SSLeay-1.85/lib/Net/SSLeay.pod" > Net:: SSLeay </a> . </li>
<li> 3 - zusätzliche Ausgabe einiger Dumps von < a href = "http://search.cpan.org/~sullr/IO-Socket-SSL-2.056/lib/IO/Socket/SSL.pod" > IO::Socket:: SSL </a> und < a href = "http://search.cpan.org/~mikem/Net-SSLeay-1.85/lib/Net/SSLeay.pod" > Net:: SSLeay </a> . </li>
</ul>
</li> <br>
2017-08-27 10:11:05 +00:00
2018-08-01 19:20:56 +00:00
<li> <code> TLS </code> <br>
<br>
Das Attribut ist nur für "Sender" verwendbar .
Es wird eine gesicherte Verbindung zum Syslog - Server aufgebaut . Das Protokoll schaltet automatisch
auf TCP um .
</li> <br>
2017-08-25 08:28:14 +00:00
<li> <code> timeout </code> <br>
<br>
2018-08-01 19:20:56 +00:00
Das Attribut ist nur für "Sender" verwendbar .
Timeout für die Verbindung zum Syslog - Server ( TCP ) . Default: 0.5 s .
2017-08-25 08:28:14 +00:00
</li> <br>
2017-08-22 06:41:25 +00:00
<li> <code> verbose </code> <br>
<br>
Die Ausgaben der Verbose - Level von Log2Syslog - Devices werden ausschließlich im lokalen FHEM Logfile ausgegeben und
nicht weitergeleitet um Schleifen zu vermeiden .
</li> <br>
2017-08-16 22:32:44 +00:00
</ul>
2017-08-27 10:38:38 +00:00
<br>
< a name = "Log2Syslogreadings" > </a>
<b> Readings </b>
<ul>
<br>
<table>
<colgroup> < col width = 35 % > < col width = 65 % > < / colgroup >
<tr> <td> <b> SSL_Algorithm </b> </td> <td> der verwendete SSL Algorithmus wenn SSL eingeschaltet und aktiv ist </td> </tr>
2018-08-01 19:20:56 +00:00
<tr> <td> <b> SSL_Version </b> </td> <td> die verwendete TLS - Version wenn die Verschlüsselung aktiv ist </td> </tr>
<tr> <td> <b> Transfered_logs_per_minute </b> </td> <td> die durchschnittliche Anzahl der übertragenen /empfangenen Logs/ Events pro Minute </td> </tr>
2017-08-27 10:38:38 +00:00
</table>
<br>
</ul>
2017-08-16 22:32:44 +00:00
</ul>
= end html_DE
2017-08-25 08:28:14 +00:00
= cut