mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-04 05:16:45 +00:00
93_DbLog.pm: Performance Logging, MYSQL crash fix, by DS_Starter (Forum #42976)
git-svn-id: https://svn.fhem.de/fhem/trunk@11335 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
3c8ada5597
commit
5325c1ea21
@ -1,4 +1,4 @@
|
|||||||
##############################################
|
################################################################
|
||||||
# $Id$
|
# $Id$
|
||||||
#
|
#
|
||||||
# 93_DbLog.pm
|
# 93_DbLog.pm
|
||||||
@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# reduceLog() created by Claudiu Schuster (rapster)
|
# reduceLog() created by Claudiu Schuster (rapster)
|
||||||
#
|
#
|
||||||
##############################################
|
################################################################
|
||||||
|
|
||||||
package main;
|
package main;
|
||||||
use strict;
|
use strict;
|
||||||
@ -97,7 +97,7 @@ sub DbLog_Define($@)
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
#####################################
|
################################################################
|
||||||
sub DbLog_Undef($$) {
|
sub DbLog_Undef($$) {
|
||||||
my ($hash, $name) = @_;
|
my ($hash, $name) = @_;
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ sub DbLog_Undef($$) {
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
#####################################
|
################################################################
|
||||||
sub DbLog_Shutdown($) {
|
sub DbLog_Shutdown($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
|
||||||
@ -144,6 +144,110 @@ sub DbLog_Attr(@)
|
|||||||
}
|
}
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
|
sub DbLog_Set($@) {
|
||||||
|
my ($hash, @a) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
my $usage = "Unknown argument, choose one of reduceLog reopen:noArg rereadcfg:noArg count:noArg deleteOldDays userCommand";
|
||||||
|
return $usage if(int(@a) < 2);
|
||||||
|
my $dbh = $hash->{DBH};
|
||||||
|
my $ret;
|
||||||
|
|
||||||
|
if ($a[1] eq 'reduceLog') {
|
||||||
|
if ( !$dbh || not $dbh->ping ) {
|
||||||
|
Log3($name, 1, "DbLog $name: DBLog_Set - reduceLog - DB Session dead, try to reopen now !");
|
||||||
|
DbLog_Connect($hash);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (defined $a[2] && $a[2] =~ /^\d+$/) {
|
||||||
|
$ret = DbLog_reduceLog($hash,@a);
|
||||||
|
} else {
|
||||||
|
Log3($name, 1, "DbLog $name: reduceLog error, no <days> given.");
|
||||||
|
$ret = "reduceLog error, no <days> given.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elsif ($a[1] eq 'reopen') {
|
||||||
|
Log3($name, 4, "DbLog $name: Reopen requested.");
|
||||||
|
|
||||||
|
if ($dbh) {
|
||||||
|
$dbh->commit() if(!$dbh->{AutoCommit});
|
||||||
|
$dbh->disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
DbLog_Connect($hash);
|
||||||
|
$ret = "Reopen executed.";
|
||||||
|
}
|
||||||
|
elsif ($a[1] eq 'rereadcfg') {
|
||||||
|
Log3($name, 4, "DbLog $name: Rereadcfg requested.");
|
||||||
|
|
||||||
|
if ($dbh) {
|
||||||
|
$dbh->commit() if(!$dbh->{AutoCommit});
|
||||||
|
$dbh->disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
$ret = _DbLog_readCfg($hash);
|
||||||
|
return $ret if $ret;
|
||||||
|
DbLog_Connect($hash);
|
||||||
|
$ret = "Rereadcfg executed.";
|
||||||
|
}
|
||||||
|
elsif ($a[1] eq 'count') {
|
||||||
|
if ( !$dbh || not $dbh->ping ) {
|
||||||
|
Log3($name, 1, "DbLog $name: DBLog_Set - count - DB Session dead, try to reopen now !");
|
||||||
|
DbLog_Connect($hash);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log3($name, 4, "DbLog $name: Records count requested.");
|
||||||
|
my $c = $dbh->selectrow_array('SELECT count(*) FROM history');
|
||||||
|
readingsSingleUpdate($hash, 'countHistory', $c ,1);
|
||||||
|
$c = $dbh->selectrow_array('SELECT count(*) FROM current');
|
||||||
|
readingsSingleUpdate($hash, 'countCurrent', $c ,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elsif ($a[1] eq 'deleteOldDays') {
|
||||||
|
Log3($name, 4, "DbLog $name: Deletion of old records requested.");
|
||||||
|
my ($c, $cmd);
|
||||||
|
|
||||||
|
if ( !$dbh || not $dbh->ping ) {
|
||||||
|
Log3($name, 1, "DbLog $name: DBLog_Set - deleteOldDays - DB Session dead, try to reopen now !");
|
||||||
|
DbLog_Connect($hash);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$cmd = "delete from history where TIMESTAMP < ";
|
||||||
|
|
||||||
|
if ($hash->{DBMODEL} eq 'SQLITE') { $cmd .= "datetime('now', '-$a[2] days')"; }
|
||||||
|
elsif ($hash->{DBMODEL} eq 'MYSQL') { $cmd .= "DATE_SUB(CURDATE(),INTERVAL $a[2] DAY)"; }
|
||||||
|
elsif ($hash->{DBMODEL} eq 'POSTGRESQL') { $cmd .= "NOW() - INTERVAL '$a[2]' DAY"; }
|
||||||
|
else { $cmd = undef; $ret = 'Unknown database type. Maybe you can try userCommand anyway.'; }
|
||||||
|
|
||||||
|
if(defined($cmd)) {
|
||||||
|
$c = $dbh->do($cmd);
|
||||||
|
readingsSingleUpdate($hash, 'lastRowsDeleted', $c ,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elsif ($a[1] eq 'userCommand') {
|
||||||
|
if ( !$dbh || not $dbh->ping ) {
|
||||||
|
Log3($name, 1, "DbLog $name: DBLog_Set - userCommand - DB Session dead, try to reopen now !");
|
||||||
|
DbLog_Connect($hash);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log3($name, 4, "DbLog $name: userCommand execution requested.");
|
||||||
|
my ($c, @cmd, $sql);
|
||||||
|
@cmd = @a;
|
||||||
|
shift(@cmd); shift(@cmd);
|
||||||
|
$sql = join(" ",@cmd);
|
||||||
|
readingsSingleUpdate($hash, 'userCommand', $sql, 1);
|
||||||
|
$c = $dbh->selectrow_array($sql);
|
||||||
|
readingsSingleUpdate($hash, 'userCommandResult', $c ,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { $ret = $usage; }
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
###############################################################################################
|
||||||
#
|
#
|
||||||
# Exrahieren des Filters aus der ColumnsSpec (gplot-Datei)
|
# Exrahieren des Filters aus der ColumnsSpec (gplot-Datei)
|
||||||
#
|
#
|
||||||
@ -153,7 +257,7 @@ sub DbLog_Attr(@)
|
|||||||
#
|
#
|
||||||
# Parameter: Quell-Instanz-Name, und alle FileLog-Parameter, die diese Instanz betreffen.
|
# Parameter: Quell-Instanz-Name, und alle FileLog-Parameter, die diese Instanz betreffen.
|
||||||
# Quelle: http://forum.fhem.de/index.php/topic,40176.msg325200.html#msg325200
|
# Quelle: http://forum.fhem.de/index.php/topic,40176.msg325200.html#msg325200
|
||||||
################################################################
|
###############################################################################################
|
||||||
sub DbLog_regexpFn($$) {
|
sub DbLog_regexpFn($$) {
|
||||||
my ($name, $filter) = @_;
|
my ($name, $filter) = @_;
|
||||||
my $ret;
|
my $ret;
|
||||||
@ -449,6 +553,7 @@ sub DbLog_ParseEvent($$$)
|
|||||||
}
|
}
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
|
# Schreibroutine Einfügen Werte in DB
|
||||||
#
|
#
|
||||||
# param1: hash
|
# param1: hash
|
||||||
# param2: DbLogType -> Current oder History oder Current/History
|
# param2: DbLogType -> Current oder History oder Current/History
|
||||||
@ -464,20 +569,32 @@ sub DbLog_ParseEvent($$$)
|
|||||||
sub DbLog_Push(@) {
|
sub DbLog_Push(@) {
|
||||||
my ($hash, $DbLogType, $timestamp, $device, $type, $event, $reading, $value, $unit) = @_;
|
my ($hash, $DbLogType, $timestamp, $device, $type, $event, $reading, $value, $unit) = @_;
|
||||||
my $dbh= $hash->{DBH};
|
my $dbh= $hash->{DBH};
|
||||||
|
my $name = $hash->{NAME};
|
||||||
if ($hash->{DBMODEL} ne 'SQLITE') {
|
|
||||||
# Daten auf maximale laenge beschneiden
|
|
||||||
$device = substr($device,0, $columns{DEVICE});
|
|
||||||
$type = substr($type,0, $columns{TYPE});
|
|
||||||
$event = substr($event,0, $columns{EVENT});
|
|
||||||
$reading = substr($reading,0, $columns{READING});
|
|
||||||
$value = substr($value,0, $columns{VALUE});
|
|
||||||
$unit = substr($unit,0, $columns{UNIT});
|
|
||||||
}
|
|
||||||
|
|
||||||
$dbh->{RaiseError} = 1;
|
$dbh->{RaiseError} = 1;
|
||||||
$dbh->{PrintError} = 0;
|
$dbh->{PrintError} = 0;
|
||||||
|
|
||||||
|
eval {
|
||||||
|
if ( !$dbh || not $dbh->ping ) {
|
||||||
|
#### DB Session dead, try to reopen now !
|
||||||
|
DbLog_Connect($hash);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if ($@) {
|
||||||
|
Log3($name, 1, "DbLog $name: DBLog_Push - DB Session dead! - $@");
|
||||||
|
return $dbh->{RaiseError};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($hash->{DBMODEL} ne 'SQLITE') {
|
||||||
|
# Daten auf maximale laenge beschneiden
|
||||||
|
$device = substr($device,0, $columns{DEVICE});
|
||||||
|
$type = substr($type,0, $columns{TYPE});
|
||||||
|
$event = substr($event,0, $columns{EVENT});
|
||||||
|
$reading = substr($reading,0, $columns{READING});
|
||||||
|
$value = substr($value,0, $columns{VALUE});
|
||||||
|
$unit = substr($unit,0, $columns{UNIT});
|
||||||
|
}
|
||||||
|
|
||||||
$dbh->begin_work();
|
$dbh->begin_work();
|
||||||
|
|
||||||
my $sth_ih = $dbh->prepare_cached("INSERT INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)") if (lc($DbLogType) =~ m(history) );
|
my $sth_ih = $dbh->prepare_cached("INSERT INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)") if (lc($DbLogType) =~ m(history) );
|
||||||
@ -515,7 +632,7 @@ sub DbLog_Push(@) {
|
|||||||
$dbh->{PrintError} = 1;
|
$dbh->{PrintError} = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $dbh->{RaiseError};
|
return $dbh->{RaiseError};
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
@ -719,9 +836,11 @@ sub DbLog_Connect($)
|
|||||||
|
|
||||||
Log3 $hash->{NAME}, 3, "Connecting to database $dbconn with user $dbuser";
|
Log3 $hash->{NAME}, 3, "Connecting to database $dbconn with user $dbuser";
|
||||||
my $dbh = DBI->connect_cached("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0 });
|
my $dbh = DBI->connect_cached("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0 });
|
||||||
|
|
||||||
if(!$dbh) {
|
if(!$dbh) {
|
||||||
RemoveInternalTimer($hash);
|
RemoveInternalTimer($hash);
|
||||||
Log3 $hash->{NAME}, 4, 'DbLog: Trying to connect to database';
|
Log3 $hash->{NAME}, 4, 'DbLog: Trying to connect to database';
|
||||||
|
readingsSingleUpdate($hash, 'state', 'disconnected', 1);
|
||||||
InternalTimer(time+5, 'DbLog_Connect', $hash, 0);
|
InternalTimer(time+5, 'DbLog_Connect', $hash, 0);
|
||||||
Log3 $hash->{NAME}, 4, 'Waiting for database connection';
|
Log3 $hash->{NAME}, 4, 'Waiting for database connection';
|
||||||
return 0;
|
return 0;
|
||||||
@ -748,6 +867,7 @@ sub DbLog_Connect($)
|
|||||||
# creating an own connection for the webfrontend, saved as DBHF in Hash
|
# creating an own connection for the webfrontend, saved as DBHF in Hash
|
||||||
# this makes sure that the connection doesnt get lost due to other modules
|
# this makes sure that the connection doesnt get lost due to other modules
|
||||||
my $dbhf = DBI->connect_cached("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0 });
|
my $dbhf = DBI->connect_cached("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0 });
|
||||||
|
|
||||||
if(!$dbh) {
|
if(!$dbh) {
|
||||||
RemoveInternalTimer($hash);
|
RemoveInternalTimer($hash);
|
||||||
Log3 $hash->{NAME}, 4, 'DbLog: Trying to connect to database';
|
Log3 $hash->{NAME}, 4, 'DbLog: Trying to connect to database';
|
||||||
@ -822,6 +942,7 @@ sub
|
|||||||
DbLog_Get($@)
|
DbLog_Get($@)
|
||||||
{
|
{
|
||||||
my ($hash, @a) = @_;
|
my ($hash, @a) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
return dbReadings($hash,@a) if $a[1] =~ m/^Readings/;
|
return dbReadings($hash,@a) if $a[1] =~ m/^Readings/;
|
||||||
|
|
||||||
@ -894,7 +1015,13 @@ DbLog_Get($@)
|
|||||||
return "Can't connect to database." if(!DbLog_Connect($hash));
|
return "Can't connect to database." if(!DbLog_Connect($hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
my $dbh= $hash->{DBH};
|
my $dbh = $hash->{DBH};
|
||||||
|
|
||||||
|
if ( !$dbh || not $dbh->ping ) {
|
||||||
|
Log3($name, 1, "DbLog $name: DBLog_Get - DB Session dead, try to reopen now !");
|
||||||
|
DbLog_Connect($hash);
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
#vorbereiten der DB-Abfrage, DB-Modell-abhaengig
|
#vorbereiten der DB-Abfrage, DB-Modell-abhaengig
|
||||||
if ($hash->{DBMODEL} eq "POSTGRESQL") {
|
if ($hash->{DBMODEL} eq "POSTGRESQL") {
|
||||||
@ -1315,7 +1442,7 @@ DbLog_Get($@)
|
|||||||
|
|
||||||
### DBLog - Historische Werte ausduennen > Forum #41089
|
### DBLog - Historische Werte ausduennen > Forum #41089
|
||||||
sub DbLog_reduceLog($@) {
|
sub DbLog_reduceLog($@) {
|
||||||
my ($hash,@a) = @_;
|
my ($hash,@a) = @_;
|
||||||
my ($ret,$cmd,$row,$filter,$exclude,$c,$day,$hour,$lastHour,$updDate,$updHour,$average,$processingDay,$lastUpdH,%hourlyKnown,%averageHash,@excludeRegex,@dayRows,@averageUpd,@averageUpdD);
|
my ($ret,$cmd,$row,$filter,$exclude,$c,$day,$hour,$lastHour,$updDate,$updHour,$average,$processingDay,$lastUpdH,%hourlyKnown,%averageHash,@excludeRegex,@dayRows,@averageUpd,@averageUpdD);
|
||||||
my ($dbh,$name,$startTime,$currentHour,$currentDay,$deletedCount,$updateCount,$sum,$rowCount,$excludeCount) = ($hash->{DBH},$hash->{NAME},time(),99,0,0,0,0,0,0);
|
my ($dbh,$name,$startTime,$currentHour,$currentDay,$deletedCount,$updateCount,$sum,$rowCount,$excludeCount) = ($hash->{DBH},$hash->{NAME},time(),99,0,0,0,0,0,0);
|
||||||
|
|
||||||
@ -1526,76 +1653,6 @@ sub DbLog_reduceLog($@) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub DbLog_Set($@) {
|
|
||||||
my ($hash, @a) = @_;
|
|
||||||
my $name = $hash->{NAME};
|
|
||||||
my $usage = "Unknown argument, choose one of reduceLog reopen:noArg rereadcfg:noArg count:noArg deleteOldDays userCommand";
|
|
||||||
return $usage if(int(@a) < 2);
|
|
||||||
my $dbh = $hash->{DBH};
|
|
||||||
my $ret;
|
|
||||||
|
|
||||||
if ($a[1] eq 'reduceLog') {
|
|
||||||
if (defined $a[2] && $a[2] =~ /^\d+$/) {
|
|
||||||
$ret = DbLog_reduceLog($hash,@a);
|
|
||||||
} else {
|
|
||||||
Log3($name, 1, "DbLog $name: reduceLog error, no <days> given.");
|
|
||||||
$ret = "reduceLog error, no <days> given.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elsif ($a[1] eq 'reopen') {
|
|
||||||
Log3($name, 4, "DbLog $name: Reopen requested.");
|
|
||||||
$dbh->commit() if(! $dbh->{AutoCommit});
|
|
||||||
$dbh->disconnect();
|
|
||||||
DbLog_Connect($hash);
|
|
||||||
$ret = "Reopen executed.";
|
|
||||||
}
|
|
||||||
elsif ($a[1] eq 'rereadcfg') {
|
|
||||||
Log3($name, 4, "DbLog $name: Rereadcfg requested.");
|
|
||||||
$dbh->commit() if(! $dbh->{AutoCommit});
|
|
||||||
$dbh->disconnect();
|
|
||||||
$ret = _DbLog_readCfg($hash);
|
|
||||||
return $ret if $ret;
|
|
||||||
DbLog_Connect($hash);
|
|
||||||
$ret = "Rereadcfg executed.";
|
|
||||||
}
|
|
||||||
elsif ($a[1] eq 'count') {
|
|
||||||
Log3($name, 4, "DbLog $name: Records count requested.");
|
|
||||||
my $c = $dbh->selectrow_array('SELECT count(*) FROM history');
|
|
||||||
readingsSingleUpdate($hash, 'countHistory', $c ,1);
|
|
||||||
$c = $dbh->selectrow_array('SELECT count(*) FROM current');
|
|
||||||
readingsSingleUpdate($hash, 'countCurrent', $c ,1);
|
|
||||||
}
|
|
||||||
elsif ($a[1] eq 'deleteOldDays') {
|
|
||||||
Log3($name, 4, "DbLog $name: Deletion of old records requested.");
|
|
||||||
my ($c, $cmd);
|
|
||||||
$cmd = "delete from history where TIMESTAMP < ";
|
|
||||||
|
|
||||||
if ($hash->{DBMODEL} eq 'SQLITE') { $cmd .= "datetime('now', '-$a[2] days')"; }
|
|
||||||
elsif ($hash->{DBMODEL} eq 'MYSQL') { $cmd .= "DATE_SUB(CURDATE(),INTERVAL $a[2] DAY)"; }
|
|
||||||
elsif ($hash->{DBMODEL} eq 'POSTGRESQL') { $cmd .= "NOW() - INTERVAL '$a[2]' DAY"; }
|
|
||||||
else { $cmd = undef; $ret = 'Unknown database type. Maybe you can try userCommand anyway.'; }
|
|
||||||
|
|
||||||
if(defined($cmd)) {
|
|
||||||
$c = $dbh->do($cmd);
|
|
||||||
readingsSingleUpdate($hash, 'lastRowsDeleted', $c ,1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elsif ($a[1] eq 'userCommand') {
|
|
||||||
Log3($name, 4, "DbLog $name: userCommand execution requested.");
|
|
||||||
my ($c, @cmd, $sql);
|
|
||||||
@cmd = @a;
|
|
||||||
shift(@cmd); shift(@cmd);
|
|
||||||
$sql = join(" ",@cmd);
|
|
||||||
readingsSingleUpdate($hash, 'userCommand', $sql, 1);
|
|
||||||
$c = $dbh->selectrow_array($sql);
|
|
||||||
readingsSingleUpdate($hash, 'userCommandResult', $c ,1);
|
|
||||||
}
|
|
||||||
else { $ret = $usage; }
|
|
||||||
|
|
||||||
return $ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
#
|
#
|
||||||
# Charting Specific functions start here
|
# Charting Specific functions start here
|
||||||
|
Loading…
x
Reference in New Issue
Block a user