2
0
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:
rapster 2016-04-28 08:03:50 +00:00
parent 3c8ada5597
commit 5325c1ea21

View File

@ -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,6 +569,21 @@ 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};
$dbh->{RaiseError} = 1;
$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') { if ($hash->{DBMODEL} ne 'SQLITE') {
# Daten auf maximale laenge beschneiden # Daten auf maximale laenge beschneiden
@ -475,9 +595,6 @@ sub DbLog_Push(@) {
$unit = substr($unit,0, $columns{UNIT}); $unit = substr($unit,0, $columns{UNIT});
} }
$dbh->{RaiseError} = 1;
$dbh->{PrintError} = 0;
$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") {
@ -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