diff --git a/fhem/CHANGED b/fhem/CHANGED
index ec88343b4..83ce99d24 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -1,5 +1,8 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it.
+ - feature: 93_DbLog: add-on parameter "force" for MinInterval- Forum: #97148,
+ new attribute traceHandles, show DB driver versions in
+ configCheck
- new: 98_readinsWatcher: new modul
- change: 72_TA_CMI_JSON: adding model attribute
- feature: 93_DbLog: attr global logdir is considered by set exportCache
diff --git a/fhem/FHEM/93_DbLog.pm b/fhem/FHEM/93_DbLog.pm
index 628c02a8e..f3f63d3e9 100644
--- a/fhem/FHEM/93_DbLog.pm
+++ b/fhem/FHEM/93_DbLog.pm
@@ -30,6 +30,8 @@ no if $] >= 5.017011, warnings => 'experimental::smartmatch';
# Version History intern by DS_Starter:
our %DbLog_vNotesIntern = (
+ "4.7.0" => "04.09.2019 attribute traceHandles, extract db driver versions in configCheck ",
+ "4.6.0" => "03.09.2019 add-on parameter \"force\" for MinInterval, Forum: #97148 ",
"4.5.0" => "28.08.2019 consider attr global logdir in set exportCache ",
"4.4.0" => "21.08.2019 configCheck changed: check if new DbLog version is available or the local one is modified ",
"4.3.0" => "14.08.2019 new attribute dbSchema, add database schema to subroutines ",
@@ -219,6 +221,7 @@ my %columns = ("DEVICE" => 64,
);
sub DbLog_dbReadings($@);
+sub DbLog_showChildHandles($$$$);
################################################################
sub DbLog_Initialize($)
@@ -252,6 +255,7 @@ sub DbLog_Initialize($)
"suppressAddLogV3:1,0 ".
"traceFlag:SQL,CON,ENC,DBD,TXN,ALL ".
"traceLevel:0,1,2,3,4,5,6,7 ".
+ "traceHandles ".
"asyncMode:1,0 ".
"cacheEvents:2,1,0 ".
"cacheLimit ".
@@ -480,6 +484,20 @@ sub DbLog_Attr(@) {
}
}
+ if ($aName eq "traceHandles") {
+ if($cmd eq "set") {
+ unless ($aVal =~ /^[0-9]+$/) {return " The Value of $aName is not valid. Use only figures 0-9 without decimal places !";}
+ }
+ RemoveInternalTimer($hash, "DbLog_startShowChildhandles");
+ if($cmd eq "set") {
+ $do = ($aVal) ? 1 : 0;
+ }
+ $do = 0 if($cmd eq "del");
+ if($do) {
+ InternalTimer(gettimeofday()+5, "DbLog_startShowChildhandles", "$name:Main", 0);
+ }
+ }
+
if ($aName eq "dbSchema") {
if($cmd eq "set") {
$do = ($aVal) ? 1 : 0;
@@ -1228,7 +1246,7 @@ sub DbLog_Log($$) {
my $async = AttrVal($name, "asyncMode", undef);
my $clim = AttrVal($name, "cacheLimit", 500);
my $ce = AttrVal($name, "cacheEvents", 0);
- my $net;
+ my ($net,$force);
return if(IsDisabled($name) || !$hash->{HELPER}{COLSET} || $init_done != 1);
@@ -1362,11 +1380,11 @@ sub DbLog_Log($$) {
#Regexp matcht und MinIntervall ist angegeben
my $lt = $defs{$dev_hash->{NAME}}{Helper}{DBLOG}{$reading}{$hash->{NAME}}{TIME};
my $lv = $defs{$dev_hash->{NAME}}{Helper}{DBLOG}{$reading}{$hash->{NAME}}{VALUE};
- $lt = 0 if(!$lt);
- # $lv = "" if(!$lv);
- $lv = "" if(!defined $lv); # Forum: #100344
+ $lt = 0 if(!$lt);
+ $lv = "" if(!defined $lv); # Forum: #100344
+ $force = ($v2[2] && $v2[2] =~ /force/i)?1:0; # Forum: #97148
- if(($now-$lt < $v2[1]) && ($lv eq $value)) {
+ if(($now-$lt < $v2[1]) && ($lv eq $value || $force)) {
# innerhalb MinIntervall und LastValue=Value
$DoIt = 0;
}
@@ -1388,11 +1406,11 @@ sub DbLog_Log($$) {
#Regexp matcht und MinIntervall ist angegeben
my $lt = $defs{$dev_hash->{NAME}}{Helper}{DBLOG}{$reading}{$hash->{NAME}}{TIME};
my $lv = $defs{$dev_hash->{NAME}}{Helper}{DBLOG}{$reading}{$hash->{NAME}}{VALUE};
- $lt = 0 if(!$lt);
- # $lv = "" if(!$lv);
- $lv = "" if(!defined $lv); # Forum: #100344
+ $lt = 0 if(!$lt);
+ $lv = "" if(!defined $lv); # Forum: #100344
+ $force = ($v2[2] && $v2[2] =~ /force/i)?1:0; # Forum: #97148
- if(($now-$lt < $v2[1]) && ($lv eq $value)) {
+ if(($now-$lt < $v2[1]) && ($lv eq $value || $force)) {
# innerhalb MinIntervall und LastValue=Value
$DoIt = 0;
}
@@ -2132,8 +2150,6 @@ sub DbLog_execmemcache ($) {
}
}
- # $memcount = scalar(keys%{$hash->{cache}{".memcache"}});
-
my $nextsync = gettimeofday()+$syncival;
my $nsdt = FmtDateTime($nextsync);
@@ -2902,8 +2918,8 @@ sub DbLog_ConnectPush($;$$) {
sub DbLog_ConnectNewDBH($) {
# new dbh for common use (except DbLog_Push and get-function)
- my ($hash)= @_;
- my $name = $hash->{NAME};
+ my ($hash) = @_;
+ my $name = $hash->{NAME};
my $dbconn = $hash->{dbconn};
my $dbuser = $hash->{dbuser};
my $dbpassword = $attr{"sec$name"}{secret};
@@ -2921,7 +2937,7 @@ sub DbLog_ConnectNewDBH($) {
$dbh = DBI->connect("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0, RaiseError => 1, mysql_enable_utf8 => $utf8 });
}
};
-
+
if($@) {
Log3($name, 2, "DbLog $name - $@");
my $state = $@?$@:(IsDisabled($name))?"disabled":"disconnected";
@@ -3575,12 +3591,28 @@ sub DbLog_configcheck($) {
my $current = $hash->{HELPER}{TC};
my ($check, $rec,%dbconfig);
- ### Start
+ ### Version check
#######################################################################
- my ($errcm,$supd,$uptb) = DbLog_checkModVer($name);
+ my $pv = sprintf("%vd",$^V); # Perl Version
+ my $dbi = $DBI::VERSION; # DBI Version
+ my %drivers = DBI->installed_drivers();
+ my $dv = "";
+ if($dbmodel =~ /MYSQL/i) {
+ for (keys %drivers) {
+ $dv = $_ if($_ =~ /mysql|mariadb/);
+ }
+ }
+ my $dbd = ($dbmodel =~ /POSTGRESQL/i)?"Pg: ".$DBD::Pg::VERSION: # DBD Version
+ ($dbmodel =~ /MYSQL/i && $dv)?"$dv: ".$DBD::mysql::VERSION:
+ ($dbmodel =~ /SQLITE/i)?"SQLite: ".$DBD::SQLite::VERSION:"Undefined";
+
+ my ($errcm,$supd,$uptb) = DbLog_checkModVer($name); # DbLog Version
$check = "";
- $check .= "Result of DbLog version check
";
+ $check .= "Result of version check
";
+ $check .= "Used Perl version: $pv
";
+ $check .= "Used DBI (Database independent interface) version: $dbi
";
+ $check .= "Used DBD (Database driver) version $dbd
";
if($errcm) {
$check .= "Recommendation: ERROR - $errcm
";
}
@@ -3722,12 +3754,24 @@ sub DbLog_configcheck($) {
@sr_unt = DbLog_sqlget($hash,"SHOW FIELDS FROM $history where FIELD='UNIT'");
}
if($dbmodel =~ /POSTGRESQL/) {
- @sr_dev = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$history' and column_name='device'");
- @sr_typ = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$history' and column_name='type'");
- @sr_evt = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$history' and column_name='event'");
- @sr_rdg = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$history' and column_name='reading'");
- @sr_val = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$history' and column_name='value'");
- @sr_unt = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$history' and column_name='unit'");
+ my $sch = AttrVal($name, "dbSchema", "");
+ my $h = "history";
+ if($sch) {
+ @sr_dev = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$h' and table_schema='$sch' and column_name='device'");
+ @sr_typ = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$h' and table_schema='$sch' and column_name='type'");
+ @sr_evt = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$h' and table_schema='$sch' and column_name='event'");
+ @sr_rdg = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$h' and table_schema='$sch' and column_name='reading'");
+ @sr_val = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$h' and table_schema='$sch' and column_name='value'");
+ @sr_unt = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$h' and table_schema='$sch' and column_name='unit'");
+ } else {
+ @sr_dev = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$h' and column_name='device'");
+ @sr_typ = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$h' and column_name='type'");
+ @sr_evt = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$h' and column_name='event'");
+ @sr_rdg = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$h' and column_name='reading'");
+ @sr_val = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$h' and column_name='value'");
+ @sr_unt = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$h' and column_name='unit'");
+
+ }
}
if($dbmodel =~ /SQLITE/) {
my $dev = (DbLog_sqlget($hash,"SELECT sql FROM sqlite_master WHERE name = '$history'"))[0];
@@ -3801,12 +3845,24 @@ sub DbLog_configcheck($) {
}
if($dbmodel =~ /POSTGRESQL/) {
- @sr_dev = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$current' and column_name='device'");
- @sr_typ = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$current' and column_name='type'");
- @sr_evt = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$current' and column_name='event'");
- @sr_rdg = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$current' and column_name='reading'");
- @sr_val = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$current' and column_name='value'");
- @sr_unt = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$current' and column_name='unit'");
+ my $sch = AttrVal($name, "dbSchema", "");
+ my $c = "current";
+ if($sch) {
+ @sr_dev = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$c' and table_schema='$sch' and column_name='device'");
+ @sr_typ = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$c' and table_schema='$sch' and column_name='type'");
+ @sr_evt = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$c' and table_schema='$sch' and column_name='event'");
+ @sr_rdg = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$c' and table_schema='$sch' and column_name='reading'");
+ @sr_val = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$c' and table_schema='$sch' and column_name='value'");
+ @sr_unt = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$c' and table_schema='$sch' and column_name='unit'");
+ } else {
+ @sr_dev = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$c' and column_name='device'");
+ @sr_typ = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$c' and column_name='type'");
+ @sr_evt = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$c' and column_name='event'");
+ @sr_rdg = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$c' and column_name='reading'");
+ @sr_val = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$c' and column_name='value'");
+ @sr_unt = DbLog_sqlget($hash,"select column_name,character_maximum_length from information_schema.columns where table_name='$c' and column_name='unit'");
+
+ }
}
if($dbmodel =~ /SQLITE/) {
my $dev = (DbLog_sqlget($hash,"SELECT sql FROM sqlite_master WHERE name = '$current'"))[0];
@@ -3864,7 +3920,7 @@ sub DbLog_configcheck($) {
}
$check .= "Result of table '$current' check
";
- $check .= "Column width set in DB $dbname.current: 'DEVICE' = $cdat_dev, 'TYPE' = $cdat_typ, 'EVENT' = $cdat_evt, 'READING' = $cdat_rdg, 'VALUE' = $cdat_val, 'UNIT' = $cdat_unt
";
+ $check .= "Column width set in DB $current: 'DEVICE' = $cdat_dev, 'TYPE' = $cdat_typ, 'EVENT' = $cdat_evt, 'READING' = $cdat_rdg, 'VALUE' = $cdat_val, 'UNIT' = $cdat_unt
";
$check .= "Column width used by $name: 'DEVICE' = $cmod_dev, 'TYPE' = $cmod_typ, 'EVENT' = $cmod_evt, 'READING' = $cmod_rdg, 'VALUE' = $cmod_val, 'UNIT' = $cmod_unt
";
$check .= "Recommendation: $rec
";
#}
@@ -5854,6 +5910,39 @@ sub DbLog_setVersionInfo($) {
return;
}
+#########################################################################
+# Trace of Childhandles
+# dbh Database handle object
+# sth Statement handle object
+# drh Driver handle object (rarely seen or used in applications)
+# h Any of the handle types above ($dbh, $sth, or $drh)
+#########################################################################
+sub DbLog_startShowChildhandles ($) {
+ my ($str) = @_;
+ my ($name,$sub) = split(":",$str);
+ my $hash = $defs{$name};
+
+ RemoveInternalTimer($hash, "DbLog_startShowChildhandles");
+ my $iv = AttrVal($name, "traceHandles", 0);
+ return if(!$iv);
+
+ my %drivers = DBI->installed_drivers();
+ DbLog_showChildHandles($name,$drivers{$_}, 0, $_) for (keys %drivers);
+
+ InternalTimer(gettimeofday()+$iv, "DbLog_startShowChildhandles", "$name:$sub", 0) if($iv);
+return;
+}
+
+sub DbLog_showChildHandles ($$$$) {
+ my ($name,$h, $level, $key) = @_;
+
+ my $t = $h->{Type}."h";
+ $t = ($t=~/drh/)?"DriverHandle ":($t=~/dbh/)?"DatabaseHandle ":($t=~/sth/)?"StatementHandle":"Undefined";
+ Log3($name, 1, "DbLog - traceHandles (system wide) - Driver: ".$key.", ".$t.": ".("\t" x $level).$h);
+ DbLog_showChildHandles($name, $_, $level + 1, $key)
+ for (grep { defined } @{$h->{ChildHandles}});
+}
+
1;
=pod
@@ -6683,19 +6772,22 @@ return;
- attr <device> DbLogInclude regex:MinInterval,[regex:MinInterval] ...
+ attr <device> DbLogInclude regex:MinInterval[:force],[regex:MinInterval[:force]] ...
attr MyDevice1 DbLogInclude .*
attr MyDevice2 DbLogInclude state,(floorplantext|MyUserReading):300,battery:3600
+ attr MyDevice2 DbLogInclude state,(floorplantext|MyUserReading):300,battery:3600
attr MyDevice2 DbLogInclude state,(floorplantext|MyUserReading):300:force,battery:3600:force
- attr <device> DbLogExclude regex:MinInterval,[regex:MinInterval] ...
+ attr <device> DbLogExclude regex:MinInterval[:force],[regex:MinInterval[:force]] ...
attr MyDevice1 DbLogExclude .*
attr MyDevice2 DbLogExclude state,(floorplantext|MyUserReading):300,battery:3600
+ attr MyDevice2 DbLogExclude state,(floorplantext|MyUserReading):300,battery:3600
attr MyDevice2 DbLogExclude state,(floorplantext|MyUserReading):300:force,battery:3600:force
attr <device> traceHandles <n>
+
- attr <device> DbLogInclude regex:MinInterval,[regex:MinInterval] ...
+ attr <device> DbLogInclude regex:MinInterval[:force],[regex:MinInterval[:force]] ...
attr MyDevice1 DbLogInclude .*
attr MyDevice2 DbLogInclude state,(floorplantext|MyUserReading):300,battery:3600
+ attr MyDevice2 DbLogInclude state,(floorplantext|MyUserReading):300,battery:3600
attr MyDevice2 DbLogInclude state,(floorplantext|MyUserReading):300:force,battery:3600:force
- attr <device> DbLogExclude regex:MinInterval,[regex:MinInterval] ...
+ attr <device> DbLogExclude regex:MinInterval[:force],[regex:MinInterval[:force]] ...
attr MyDevice1 DbLogExclude .*
attr MyDevice2 DbLogExclude state,(floorplantext|MyUserReading):300,battery:3600
+ attr MyDevice2 DbLogExclude state,(floorplantext|MyUserReading):300,battery:3600
attr MyDevice2 DbLogExclude state,(floorplantext|MyUserReading):300:force,battery:3600:force
attr <device> traceHandles <n>
+