92_FileLog.pm: check in the readonly patch (Forum #35030)
git-svn-id: svn://svn.code.sf.net/p/fhem/code/trunk@8264 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
@@ -21,7 +21,7 @@ use vars qw($FW_wname); # Web instance
|
|||||||
use vars qw(%FW_pos); # scroll position
|
use vars qw(%FW_pos); # scroll position
|
||||||
use vars qw(%FW_webArgs); # all arguments specified in the GET
|
use vars qw(%FW_webArgs); # all arguments specified in the GET
|
||||||
|
|
||||||
sub FileLog_seekTo($$$$);
|
sub FileLog_seekTo($$$$$);
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
sub
|
sub
|
||||||
@@ -37,7 +37,7 @@ FileLog_Initialize($)
|
|||||||
$hash->{NotifyFn} = "FileLog_Log";
|
$hash->{NotifyFn} = "FileLog_Log";
|
||||||
$hash->{AttrFn} = "FileLog_Attr";
|
$hash->{AttrFn} = "FileLog_Attr";
|
||||||
# logtype is used by the frontend
|
# logtype is used by the frontend
|
||||||
$hash->{AttrList} = "disable:0,1 logtype ".
|
$hash->{AttrList} = "disable:0,1 logtype reformatFn ".
|
||||||
"nrarchive archivedir archivecmd addStateEvent:0,1";
|
"nrarchive archivedir archivecmd addStateEvent:0,1";
|
||||||
|
|
||||||
$hash->{FW_summaryFn} = "FileLog_fhemwebFn";
|
$hash->{FW_summaryFn} = "FileLog_fhemwebFn";
|
||||||
@@ -56,7 +56,12 @@ FileLog_Define($@)
|
|||||||
my @a = split("[ \t][ \t]*", $def);
|
my @a = split("[ \t][ \t]*", $def);
|
||||||
my $fh;
|
my $fh;
|
||||||
|
|
||||||
return "wrong syntax: define <name> FileLog filename regexp" if(int(@a) != 4);
|
if(@a == 5 && $a[4] eq "readonly") {
|
||||||
|
$hash->{READONLY} = 1;
|
||||||
|
pop(@a);
|
||||||
|
}
|
||||||
|
return "wrong syntax: define <name> FileLog filename regexp [readonly]"
|
||||||
|
if(int(@a) != 4);
|
||||||
|
|
||||||
return "Bad regexp: starting with *" if($a[3] =~ m/^\*/);
|
return "Bad regexp: starting with *" if($a[3] =~ m/^\*/);
|
||||||
eval { "Hallo" =~ m/^$a[3]$/ };
|
eval { "Hallo" =~ m/^$a[3]$/ };
|
||||||
@@ -64,8 +69,10 @@ FileLog_Define($@)
|
|||||||
|
|
||||||
my @t = localtime;
|
my @t = localtime;
|
||||||
my $f = ResolveDateWildcards($a[2], @t);
|
my $f = ResolveDateWildcards($a[2], @t);
|
||||||
|
if(!$hash->{READONLY}) {
|
||||||
$fh = new IO::File ">>$f";
|
$fh = new IO::File ">>$f";
|
||||||
return "Can't open $f: $!" if(!defined($fh));
|
return "Can't open $f: $!" if(!defined($fh));
|
||||||
|
}
|
||||||
|
|
||||||
$hash->{FH} = $fh;
|
$hash->{FH} = $fh;
|
||||||
$hash->{REGEXP} = $a[3];
|
$hash->{REGEXP} = $a[3];
|
||||||
@@ -127,6 +134,7 @@ FileLog_Log($$)
|
|||||||
{
|
{
|
||||||
# Log is my entry, Dev is the entry of the changed device
|
# Log is my entry, Dev is the entry of the changed device
|
||||||
my ($log, $dev) = @_;
|
my ($log, $dev) = @_;
|
||||||
|
return if($log->{READONLY});
|
||||||
|
|
||||||
my $ln = $log->{NAME};
|
my $ln = $log->{NAME};
|
||||||
return if($attr{$ln} && $attr{$ln}{disable});
|
return if($attr{$ln} && $attr{$ln}{disable});
|
||||||
@@ -531,6 +539,7 @@ FileLog_Get($@)
|
|||||||
$internal = 1;
|
$internal = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my $reformatFn = AttrVal($name, "reformatFn", "");
|
||||||
|
|
||||||
if($inf eq "-") {
|
if($inf eq "-") {
|
||||||
# In case now is after midnight, before the first event is logged.
|
# In case now is after midnight, before the first event is logged.
|
||||||
@@ -569,13 +578,14 @@ FileLog_Get($@)
|
|||||||
Log3 $name, 4, "$name get: Input file $inf, from:$from to:$to";
|
Log3 $name, 4, "$name get: Input file $inf, from:$from to:$to";
|
||||||
|
|
||||||
my $ifh = new IO::File $inf if($inf);
|
my $ifh = new IO::File $inf if($inf);
|
||||||
FileLog_seekTo($inf, $ifh, $hash, $from) if($ifh);
|
FileLog_seekTo($inf, $ifh, $hash, $from, $reformatFn) if($ifh);
|
||||||
|
|
||||||
# Return the the plain file data, $outf is ignored
|
# Return the the plain file data, $outf is ignored
|
||||||
if(!@a) {
|
if(!@a) {
|
||||||
return "" if(!$ifh);
|
return "" if(!$ifh);
|
||||||
my $out = "";
|
my $out = "";
|
||||||
while(my $l = <$ifh>) {
|
while(my $l = <$ifh>) {
|
||||||
|
if($reformatFn) { no strict; $l = &$reformatFn($l); use strict; }
|
||||||
next if($l lt $from);
|
next if($l lt $from);
|
||||||
last if($l gt $to);
|
last if($l gt $to);
|
||||||
$out .= $l;
|
$out .= $l;
|
||||||
@@ -645,6 +655,7 @@ RESCAN:
|
|||||||
} else {
|
} else {
|
||||||
$l = <$ifh> if($ifh);
|
$l = <$ifh> if($ifh);
|
||||||
last if(!$l);
|
last if(!$l);
|
||||||
|
if($reformatFn) { no strict; $l = &$reformatFn($l); use strict; }
|
||||||
}
|
}
|
||||||
|
|
||||||
next if($l lt $from && !$rescan);
|
next if($l lt $from && !$rescan);
|
||||||
@@ -844,10 +855,11 @@ seekBackOneLine($$)
|
|||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
|
#($1-40587)*86400+$2
|
||||||
sub
|
sub
|
||||||
FileLog_seekTo($$$$)
|
FileLog_seekTo($$$$$)
|
||||||
{
|
{
|
||||||
my ($fname, $fh, $hash, $ts) = @_;
|
my ($fname, $fh, $hash, $ts, $reformatFn) = @_;
|
||||||
|
|
||||||
# If its cached
|
# If its cached
|
||||||
if($hash->{pos} && $hash->{pos}{"$fname:$ts"}) {
|
if($hash->{pos} && $hash->{pos}{"$fname:$ts"}) {
|
||||||
@@ -866,6 +878,7 @@ FileLog_seekTo($$$$)
|
|||||||
$last = $next;
|
$last = $next;
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
|
if($reformatFn) { no strict; $data = &$reformatFn($data); use strict; }
|
||||||
if($data !~ m/^\d\d\d\d-\d\d-\d\d_\d\d:\d\d:\d\d /o) {
|
if($data !~ m/^\d\d\d\d-\d\d-\d\d_\d\d:\d\d:\d\d /o) {
|
||||||
$next = $fh->tell;
|
$next = $fh->tell;
|
||||||
$data = <$fh>;
|
$data = <$fh>;
|
||||||
@@ -873,6 +886,7 @@ FileLog_seekTo($$$$)
|
|||||||
$last = seekBackOneLine($fh, $next);
|
$last = seekBackOneLine($fh, $next);
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
|
if($reformatFn) { no strict; $data = &$reformatFn($data); use strict; }
|
||||||
|
|
||||||
# If the second line is longer then the first,
|
# If the second line is longer then the first,
|
||||||
# binary search will never get it:
|
# binary search will never get it:
|
||||||
@@ -894,7 +908,6 @@ FileLog_seekTo($$$$)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$hash->{pos}{"$fname:$ts"} = $last;
|
$hash->{pos}{"$fname:$ts"} = $last;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub
|
sub
|
||||||
@@ -912,6 +925,7 @@ FileLog_sampleDataFn($$$$$)
|
|||||||
my $desc = "Input:Column,Regexp,DefaultValue,Function";
|
my $desc = "Input:Column,Regexp,DefaultValue,Function";
|
||||||
|
|
||||||
my $fName = $defs{$flName}{currentlogfile};
|
my $fName = $defs{$flName}{currentlogfile};
|
||||||
|
my $reformatFn = AttrVal($flName, "reformatFn", "");
|
||||||
my $fh = new IO::File $fName;
|
my $fh = new IO::File $fName;
|
||||||
if(!$fh) {
|
if(!$fh) {
|
||||||
$fName = "<undefined>" if(!defined($fName));
|
$fName = "<undefined>" if(!defined($fName));
|
||||||
@@ -926,6 +940,7 @@ FileLog_sampleDataFn($$$$$)
|
|||||||
my $maxcols = 0;
|
my $maxcols = 0;
|
||||||
my %h;
|
my %h;
|
||||||
while($data = <$fh>) {
|
while($data = <$fh>) {
|
||||||
|
if($reformatFn) { no strict; $data = &$reformatFn($data); use strict; }
|
||||||
my @cols = split(" ", $data);
|
my @cols = split(" ", $data);
|
||||||
next if(@cols < 3);
|
next if(@cols < 3);
|
||||||
$maxcols = @cols if(@cols > $maxcols);
|
$maxcols = @cols if(@cols > $maxcols);
|
||||||
@@ -975,7 +990,7 @@ FileLog_sampleDataFn($$$$$)
|
|||||||
<a name="FileLogdefine"></a>
|
<a name="FileLogdefine"></a>
|
||||||
<b>Define</b>
|
<b>Define</b>
|
||||||
<ul>
|
<ul>
|
||||||
<code>define <name> FileLog <filename> <regexp></code>
|
<code>define <name> FileLog <filename> <regexp> [readonly]</code>
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
Log events to <code><filename></code>. The log format is
|
Log events to <code><filename></code>. The log format is
|
||||||
@@ -1005,6 +1020,9 @@ FileLog_sampleDataFn($$$$$)
|
|||||||
at the beginning of the year)
|
at the beginning of the year)
|
||||||
If you use <code>%V</code> you will also have to use %G
|
If you use <code>%V</code> you will also have to use %G
|
||||||
instead of %Y for the year!<br>
|
instead of %Y for the year!<br>
|
||||||
|
|
||||||
|
If readonly is specified, then the file is used only for visualisation, and
|
||||||
|
it is not opened for writing.
|
||||||
Examples:
|
Examples:
|
||||||
<ul>
|
<ul>
|
||||||
<code>define lamplog FileLog %L/lamp.log lamp</code><br>
|
<code>define lamplog FileLog %L/lamp.log lamp</code><br>
|
||||||
@@ -1193,6 +1211,25 @@ FileLog_sampleDataFn($$$$$)
|
|||||||
attr ks300log1 logtype temp4rain10:Temp/Rain,hum6wind8:Hum/Wind,text:Raw-data
|
attr ks300log1 logtype temp4rain10:Temp/Rain,hum6wind8:Hum/Wind,text:Raw-data
|
||||||
</li><br>
|
</li><br>
|
||||||
|
|
||||||
|
<a name="reformatFn"></a>
|
||||||
|
<li>reformatFn<br>
|
||||||
|
used to convert "foreign" logfiles for the SVG Module, contains the name(!)
|
||||||
|
of a function, which will be called with a "raw" line from the original
|
||||||
|
file, and has to return a line in "FileLog" format.<br>
|
||||||
|
E.g. to visualize the NTP loopstats, set reformatFn to ntpLoopstats, and
|
||||||
|
copy the following into your 99_myUtils.pm:
|
||||||
|
<pre><code>
|
||||||
|
sub
|
||||||
|
ntpLoopstats($)
|
||||||
|
{
|
||||||
|
my ($d) = @_;
|
||||||
|
return $d if($d !~ m/^(\d{5}) (\d+)\.(\d{3}) (.*)$/);
|
||||||
|
my ($r, $t) = ($4, FmtDateTime(($1-40587)*86400+$2));
|
||||||
|
$t =~ s/ /_/;
|
||||||
|
return "$t ntpLoopStats $r";
|
||||||
|
}</code></pre>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
@@ -1211,7 +1248,7 @@ FileLog_sampleDataFn($$$$$)
|
|||||||
<a name="FileLogdefine"></a>
|
<a name="FileLogdefine"></a>
|
||||||
<b>Define</b>
|
<b>Define</b>
|
||||||
<ul>
|
<ul>
|
||||||
<code>define <name> FileLog <filename> <regexp></code>
|
<code>define <name> FileLog <filename> <regexp> [readonly]</code>
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
Speichert Ereignisse in einer Log-Datei mit Namen <code><filename></code>. Das Log-Format ist
|
Speichert Ereignisse in einer Log-Datei mit Namen <code><filename></code>. Das Log-Format ist
|
||||||
@@ -1246,6 +1283,10 @@ FileLog_sampleDataFn($$$$$)
|
|||||||
Bei der Verwendung von <code>%V</code> muss gleichzeitig für das Jahr
|
Bei der Verwendung von <code>%V</code> muss gleichzeitig für das Jahr
|
||||||
ein <code>%G</code> anstelle von <code>%Y</code> benutzt werden.<br>
|
ein <code>%G</code> anstelle von <code>%Y</code> benutzt werden.<br>
|
||||||
|
|
||||||
|
Falls man readonly spezifiziert, dann wird die Datei nur zum visualisieren
|
||||||
|
verwendet, und nicht zum Schreiben geöffnet.
|
||||||
|
<br>
|
||||||
|
|
||||||
Beispiele:
|
Beispiele:
|
||||||
<ul>
|
<ul>
|
||||||
<code>define lamplog FileLog %L/lamp.log lamp</code><br>
|
<code>define lamplog FileLog %L/lamp.log lamp</code><br>
|
||||||
@@ -1419,8 +1460,8 @@ FileLog_sampleDataFn($$$$$)
|
|||||||
|
|
||||||
<a name="logtype"></a>
|
<a name="logtype"></a>
|
||||||
<li>logtype<br>
|
<li>logtype<br>
|
||||||
Wird vom pgm2 webfrontend benötigt, um gnuplot/SVG-Kurven aus den
|
Wird vom SVG Modul benötigt, um daten grafisch aufzubereiten.
|
||||||
Logdateien zu zeichnen. Der String wird aus komma-separierten Tokens
|
Der String wird aus komma-separierten Tokens
|
||||||
(,) erzeugt, wobei jeder Token ein eigenes gnuplot-Programm bezeichnet.
|
(,) erzeugt, wobei jeder Token ein eigenes gnuplot-Programm bezeichnet.
|
||||||
Die Token können Doppelpunkte (:) enthalten. Der Teil vor dem
|
Die Token können Doppelpunkte (:) enthalten. Der Teil vor dem
|
||||||
Doppelpunkt bezeichnet den Namen des Programms; der Teil nach dem
|
Doppelpunkt bezeichnet den Namen des Programms; der Teil nach dem
|
||||||
@@ -1455,10 +1496,32 @@ FileLog_sampleDataFn($$$$$)
|
|||||||
</li>
|
</li>
|
||||||
<li>text<br>
|
<li>text<br>
|
||||||
Zeigt das LogFile in seiner ursprünglichen Form (Nur
|
Zeigt das LogFile in seiner ursprünglichen Form (Nur
|
||||||
Text).Eine gnuplot-Definition ist nicht notwendig. </li> </ul>
|
Text).Eine gnuplot-Definition ist nicht notwendig.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
Beispiel:<br> attr ks300log1 logtype
|
Beispiel:<br> attr ks300log1 logtype
|
||||||
temp4rain10:Temp/Rain,hum6wind8:Hum/Wind,text:Raw-data </li><br>
|
temp4rain10:Temp/Rain,hum6wind8:Hum/Wind,text:Raw-data
|
||||||
|
</li><br>
|
||||||
|
|
||||||
|
<a name="reformatFn"></a>
|
||||||
|
<li>reformatFn<br>
|
||||||
|
wird verwendet, um "fremde" Dateien für die SVG-Anzeige ins
|
||||||
|
FileLog-Format zu konvertieren. Es enthält nur den Namen einer
|
||||||
|
Funktion, der mit der ursprünglichen Zeile aufgerufen wird. Z.Bsp.
|
||||||
|
um die NTP loopstats Datei zu visualisieren kann man den Wert von
|
||||||
|
reformatFn auf ntpLoopstats setzen, und folgende Funktion in
|
||||||
|
99_myUtils.pm definieren:
|
||||||
|
<pre><code>
|
||||||
|
sub
|
||||||
|
ntpLoopstats($)
|
||||||
|
{
|
||||||
|
my ($d) = @_;
|
||||||
|
return $d if($d !~ m/^(\d{5}) (\d+)\.(\d{3}) (.*)$/);
|
||||||
|
my ($r, $t) = ($4, FmtDateTime(($1-40587)*86400+$2));
|
||||||
|
$t =~ s/ /_/;
|
||||||
|
return "$t ntpLoopStats $r";
|
||||||
|
}</code></pre>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
Reference in New Issue
Block a user