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