98_fhemdebug.pm 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. ##############################################
  2. # $Id: 98_fhemdebug.pm 14596 2017-06-29 11:57:43Z rudolfkoenig $
  3. package main;
  4. use strict;
  5. use warnings;
  6. my $fhemdebug_enabled;
  7. my $main_callfn;
  8. sub
  9. fhemdebug_Initialize($){
  10. $cmds{"fhemdebug"}{Fn} = "fhemdebug_Fn";
  11. $cmds{"fhemdebug"}{Hlp} = "{start|stop|status}";
  12. }
  13. sub
  14. fhemdebug_Fn($$)
  15. {
  16. my ($cl,$param) = @_;
  17. if($param eq "enable") {
  18. return "fhemdebug is already enabled" if($fhemdebug_enabled);
  19. local $SIG{__WARN__} = sub { };
  20. $main_callfn = \&CallFn;
  21. *CallFn = \&fhemdebug_CallFn;
  22. $fhemdebug_enabled = 1;
  23. return undef;
  24. } elsif($param eq "disable") {
  25. return "fhemdebug is already disabled" if(!$fhemdebug_enabled);
  26. local $SIG{__WARN__} = sub { };
  27. *CallFn = $main_callfn;
  28. $fhemdebug_enabled = 0;
  29. return undef;
  30. } elsif($param eq "status") {
  31. return "fhemdebug is ".($fhemdebug_enabled ? "enabled":"disabled");
  32. } elsif($param =~ m/^memusage/) {
  33. return fhemdebug_memusage($param);
  34. } else {
  35. return "Usage: fhemdebug {enable|disable|status|memusage}";
  36. }
  37. }
  38. sub
  39. fhemdebug_CheckDefs($@)
  40. {
  41. my ($txt, $dev, $n) = @_;
  42. foreach my $d (keys %defs) {
  43. if(!defined($d)) {
  44. Log 1, "ERROR: undef \$defs entry found ($txt $dev $n)";
  45. delete($defs{undef});
  46. next;
  47. }
  48. if($d eq "") {
  49. Log 1, "ERROR: '' \$defs entry found ($txt $dev $n)";
  50. delete($defs{''});
  51. next;
  52. }
  53. if(ref $defs{$d} ne "HASH") {
  54. Log 1, "ERROR: \$defs{$d} is not a HASH ($txt $dev $n)";
  55. delete($defs{$d});
  56. next;
  57. }
  58. if(!$defs{$d}{TYPE}) {
  59. Log 1, "ERROR: >$d< has no TYPE, but following keys: >".
  60. join(",", sort keys %{$defs{$d}})."<".
  61. "($txt $dev $n)";
  62. delete($defs{$d});
  63. next;
  64. }
  65. }
  66. }
  67. sub
  68. fhemdebug_CallFn(@)
  69. {
  70. #Log 1, "fhemdebug_CallFn $_[0] $_[1];
  71. if(wantarray) {
  72. fhemdebug_CheckDefs("before", @_);
  73. no strict "refs";
  74. my @ret = &{$main_callfn}(@_);
  75. use strict "refs";
  76. fhemdebug_CheckDefs("after", @_);
  77. return @ret;
  78. } else {
  79. fhemdebug_CheckDefs("before", @_);
  80. no strict "refs";
  81. my $ret = &{$main_callfn}(@_);
  82. fhemdebug_CheckDefs("after", @_);
  83. use strict "refs";
  84. return $ret;
  85. }
  86. }
  87. sub
  88. fhemdebug_memusage($)
  89. {
  90. my ($param) = @_;
  91. eval "use Devel::Size";
  92. return $@ if($@);
  93. $Devel::Size::warn = 0;
  94. my @param = split(" ", $param);
  95. my $max = 50;
  96. my $re;
  97. $max = pop(@param) if(@param > 1 && $param[$#param] =~ m/^\d+$/);
  98. $re = pop(@param) if(@param > 1);
  99. my %ts;
  100. my $collectSize = sub($$$)
  101. {
  102. my ($fn, $h, $mname) = @_;
  103. return if($h->{__IN__CS__}); # save us from endless recursion
  104. $h->{__IN__CS__} = 1;
  105. eval {
  106. foreach my $n (keys %$h) {
  107. next if(!$n || $n =~ m/^[^A-Za-z]$/);
  108. if($n =~ m/::$/) {
  109. $fn->($fn, $h->{$n}, "$mname$n");
  110. next;
  111. }
  112. next if(main->can("$mname$n"));
  113. if($mname eq "main::" &&
  114. ($n eq "modules" || $n eq "defs" || $n eq "readyfnlist")) {
  115. for my $mn (keys %{$main::{$n}}) {
  116. $ts{"$mname$n::$mn"} = Devel::Size::total_size($main::{$n}{$mn});
  117. }
  118. } else {
  119. $ts{"$mname$n"} = Devel::Size::total_size($h->{$n});
  120. }
  121. }
  122. };
  123. delete $h->{__IN__CS__};
  124. Log 1, "collectSize $mname: $@" if($@);
  125. };
  126. $collectSize->($collectSize, \%main::, "main::");
  127. my @sts = sort { $ts{$b} <=> $ts{$a} } keys %ts;
  128. my @ret;
  129. for(my $i=0; $i < int(@sts); $i++) {
  130. next if($re && $sts[$i] !~ m/$re/);
  131. push @ret, sprintf("%4d. %-30s %8d", $i+1,substr($sts[$i],6),$ts{$sts[$i]});
  132. last if(@ret >= $max);
  133. }
  134. return join("\n", @ret);
  135. }
  136. 1;
  137. =pod
  138. =item command
  139. =item summary try to localize FHEM error messages
  140. =item summary_DE Hilfe bei der Lokalisierung von Fehlermeldungen
  141. =begin html
  142. <a name="fhemdebug"></a>
  143. <h3>fhemdebug</h3>
  144. <ul>
  145. <code>fhemdebug {enable|disable|status|}</code><br>
  146. <br>
  147. <ul>
  148. <li>enable/disable/status<br>
  149. fhemdebug produces debug information in the FHEM Log to help localize
  150. certain error messages. Currently following errors are examined:
  151. <ul>
  152. - Error: &gt;...&lt; has no TYPE, but following keys: &gt;...&lt;<br>
  153. </ul>
  154. As it frequently examines internal data-structures, it uses a lot of CPU,
  155. it is not recommended to enable it all the time. A FHEM restart after
  156. disabling it is not necessary.<br>
  157. </li>
  158. <li>memusage [regexp] [nr]<br>
  159. Dump the name of the first nr datastructures with the largest memory
  160. footprint. Filter the names by regexp, if specified.<br>
  161. <b>Notes</b>:
  162. <ul>
  163. <li>this function depends on the Devel::Size module, so this must be
  164. installed first.</li>
  165. <li>The used function Devel::Size::total_size crashes perl (and FHEM) for
  166. functions and some other data structures. memusage tries to avoid to
  167. call it for such data structures, but as the problem is not identified,
  168. it may crash your currently running instance. It works for me, but make
  169. sure you saved your fhem.cfg before coalling it.</li>
  170. <li>The known data structures modules and defs are reported in more
  171. detail.</li>
  172. </ul>
  173. </li>
  174. </ul>
  175. </ul>
  176. =end html
  177. =cut