############################################## # $Id$ package main; use strict; use warnings; use IO::File; use Blocking; ##################################### sub SingleFileLog_Initialize($) { my ($hash) = @_; $hash->{DefFn} = "SingleFileLog_Define"; $hash->{NotifyFn} = "SingleFileLog_Log"; $hash->{AttrFn} = "SingleFileLog_Attr"; no warnings 'qw'; my @attrList = qw( addStateEvent:1,0 disable:1,0 disabledForIntervals dosLineEnding:1,0 numberFormat readySuffix syncAfterWrite:1,0 template:textField-long writeInBackground:1,0 ); use warnings 'qw'; $hash->{AttrList} = join(" ", @attrList); } ##################################### sub SingleFileLog_Define($@) { my ($hash, $def) = @_; my @a = split("[ \t][ \t]*", $def); my $fh; return "wrong syntax: define SingleFileLog filename regexp" if(int(@a) != 4); return "Bad regexp: starting with *" if($a[3] =~ m/^\*/); eval { "Hallo" =~ m/^$a[3]$/ }; return "Bad regexp: $@" if($@); $hash->{FH} = $fh; $hash->{REGEXP} = $a[3]; $hash->{LOGFILE} = ($a[2] =~ m/^{.*}$/ ? AnalyzePerlCommand(undef, $a[2]) : $a[2]); $hash->{STATE} = "active"; readingsSingleUpdate($hash, "filecount", 0, 0); notifyRegexpChanged($hash, $a[3]); return undef; } ##################################### sub SingleFileLog_Log($$) { # Log is my entry, Dev is the entry of the changed device my ($log, $dev) = @_; return if($log->{READONLY}); my $ln = $log->{NAME}; return if(IsDisabled($ln)); my $events = deviceEvents($dev, AttrVal($ln, "addStateEvent", 0)); return if(!$events); my $n = $dev->{NAME}; my $re = $log->{REGEXP}; my $max = int(@{$events}); my $tn = $dev->{NTFY_TRIGGERTIME}; my $ct = $dev->{CHANGETIME}; for (my $i = 0; $i < $max; $i++) { my $s = $events->[$i]; $s = "" if(!defined($s)); my $t = (($ct && $ct->[$i]) ? $ct->[$i] : $tn); if($n =~ m/^$re$/ || "$n:$s" =~ m/^$re$/ || "$t:$n:$s" =~ m/^$re$/) { my $fc = ReadingsVal($ln,"filecount",0)+1; readingsSingleUpdate($log, "filecount", $fc, 0); my %arg = (log=>$log, dev=>$dev, evt=>$s); if(AttrVal($ln, "writeInBackground",0)) { BlockingCall("SingleFileLog_Write", \%arg); } else { SingleFileLog_Write(\%arg); } } } return ""; } ################################### sub SingleFileLog_Write($) { my ($ptr) = @_; my ($log, $dev, $EVENT) = ($ptr->{log}, $ptr->{dev}, $ptr->{evt}); my $NAME = $dev->{NAME}; my $ln = $log->{NAME}; my ($seconds, $microseconds) = gettimeofday(); my @time = localtime($seconds); my $f = $log->{LOGFILE}; my $fc = ReadingsVal($ln,"filecount",0); $f =~ s/%Q/$fc/g; $f = ResolveDateWildcards($f, @time); Log3 $ln, 4, "$ln: Writing $f"; my $time = $dev->{NTFY_TRIGGERTIME}; my $time14 = sprintf("%04d%02d%02d%02d%02d%02d", $time[5]+1900,$time[4]+1,$time[3],$time[2],$time[1],$time[0]); my $time16 = $time14.sprintf("%02d", $microseconds/100000); my ($decl,$idx) = ("",0); my $nf = AttrVal($ln, "numberFormat", "%1.6E"); foreach my $part (split(" ", $EVENT)) { $decl .= "my \$EVTPART$idx='$part';"; $decl .= "my \$EVTNUM$idx='".sprintf($nf,$part)."';" if(looks_like_number($part)); $idx++; } my $template = AttrVal($ln, "template", '$time $NAME $EVENT\n'); $template = "\"$template\"" if($template !~ m/^{.*}$/); my $data = eval "$decl $template"; if($@) { Log3 $ln, 1, "$ln: error evaluating template: $@"; return; } $data =~ s/\n/\r\n/mg if(AttrVal($ln, "dosLineEnding", 0)); my $fh = new IO::File ">>$f.tmp"; if(!defined($fh)) { Log3 $ln, 1, "$ln: Can't open $f.tmp: $!"; return; } print $fh $data; $fh->sync if($^O ne 'MSWin32' && AttrVal($ln, "syncAfterWrite", 0)); close($fh); my $sfx = AttrVal($ln, "readySuffix", ".rdy"); $sfx = "" if(lc($sfx) eq "none"); if($sfx ne ".tmp") { Log3 $ln, 1, "Cannot rename $f.tmp to $f$sfx" if(!rename "$f.tmp","$f$sfx"); } } ################################### sub SingleFileLog_Attr(@) { my @a = @_; my $do = 0; if($a[0] eq "set" && $a[2] eq "disable") { $do = (!defined($a[3]) || $a[3]) ? 1 : 2; } $do = 2 if($a[0] eq "del" && (!$a[2] || $a[2] eq "disable")); return if(!$do); $defs{$a[1]}{STATE} = ($do == 1 ? "disabled" : "active"); return undef; } 1; =pod =item helper =item summary write single events to a separate file each, using templates =item summary_DE schreibt einzelne Events in separate Dateien via templates =begin html

SingleFileLog

=end html =begin html_DE

SingleFileLog

=end html_DE =cut