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;
  • DbLogInclude
  • @@ -6706,19 +6798,21 @@ return;
  • DbLogExclude
  • @@ -7020,6 +7114,21 @@ attr SMA_Energymeter DbLogValueFn
    + +
    + @@ -8043,18 +8155,23 @@ attr SMA_Energymeter DbLogValueFn
  • DbLogExclude
  • @@ -8356,6 +8473,21 @@ attr SMA_Energymeter DbLogValueFn
    + +
    +