X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=SL%2FLXDebug.pm;h=7dddf2a02d2e17017d5028c0bf129ca0a14e084d;hb=2fe6237c8b09d2f5a83145673c15be84bdfadf8a;hp=016015f520914a0347797c87278b09e61b2c8c39;hpb=278523a45d785ee37a915067b73ffe098b5df88d;p=kivitendo-erp.git diff --git a/SL/LXDebug.pm b/SL/LXDebug.pm index 016015f52..7dddf2a02 100644 --- a/SL/LXDebug.pm +++ b/SL/LXDebug.pm @@ -11,19 +11,22 @@ use constant REQUEST_TIMER => 1 << 6; use constant REQUEST => 1 << 7; use constant WARN => 1 << 8; use constant TRACE2 => 1 << 9; -use constant ALL => (1 << 10) - 1; +use constant SHOW_CALLER => 1 << 10; +use constant ALL => (1 << 11) - 1; use constant DEVEL => INFO | DEBUG1 | QUERY | TRACE | BACKTRACE_ON_ERROR | REQUEST_TIMER; use constant FILE_TARGET => 0; use constant STDERR_TARGET => 1; use Data::Dumper; -use POSIX qw(strftime getppid); +use POSIX qw(strftime getpid); +use Scalar::Util qw(blessed refaddr weaken); use Time::HiRes qw(gettimeofday tv_interval); use YAML; use SL::Request (); use strict; +use utf8; my ($text_diff_available); @@ -143,7 +146,10 @@ sub message { no warnings; my ($self, $level, $message) = @_; - $self->_write(level2string($level), $message) if (($self->{"level"} | $global_level) & $level || !$level); + my $show_caller = ($level | $global_level) & SHOW_CALLER(); + $level &= ~SHOW_CALLER(); + + $self->_write(level2string($level), $message, show_caller => $show_caller) if (($self->{"level"} | $global_level) & $level || !$level); } sub warn { no warnings; @@ -151,15 +157,49 @@ sub warn { $self->message(WARN, $message); } -sub dump { - my ($self, $level, $name, $variable, %options) = @_; +sub clone_for_dump { + my ($src, $dumped) = @_; + + return undef if !defined($src); + + $dumped ||= {}; + my $addr = refaddr($src); + + return $dumped->{$addr} if $dumped->{$addr // ''}; + + + if (blessed($src) && $src->can('as_debug_info')) { + $dumped->{$addr} = $src->as_debug_info; + + } elsif (ref($src) eq 'ARRAY') { + $dumped->{$addr} = []; + + foreach my $entry (@{ $src }) { + my $exists = !!$dumped->{refaddr($entry) // ''}; + push @{ $dumped->{$addr} }, clone_for_dump($entry, $dumped); - my $password; - if ($variable && ('Form' eq ref $variable) && defined $variable->{password}) { - $password = $variable->{password}; - $variable->{password} = 'X' x 8; + weaken($dumped->{$addr}->[-1]) if $exists; + + } + + } elsif (ref($src) =~ m{^(?:HASH|Form|SL::.+)$}) { + $dumped->{$addr} = {}; + + foreach my $key (keys %{ $src }) { + my $exists = !!$dumped->{refaddr($src->{$key}) // ''}; + $dumped->{$addr}->{$key} = clone_for_dump($src->{$key}, $dumped); + + weaken($dumped->{$addr}->{$key}) if $exists; + } } + return $dumped->{$addr} // "$src"; +} + +sub dump { + my ($self, $level, $name, $variable, %options) = @_; + + $variable = clone_for_dump($variable); my $dumper = Data::Dumper->new([$variable]); $dumper->Sortkeys(1); $dumper->Indent(2); @@ -167,15 +207,6 @@ sub dump { my $output = $dumper->Dump(); $self->message($level, "dumping ${name}:\n" . $output); - $variable->{password} = $password if (defined $password); - - # Data::Dumper does not reset the iterator belonging to this hash - # if 'Sortkeys' is true. Therefore clear the iterator manually. - # See "perldoc -f each". - if ($variable && (('HASH' eq ref $variable) || ('Form' eq ref $variable))) { - keys %{ $variable }; - } - return $output; } @@ -213,17 +244,6 @@ sub dump_sql_result { $self->message($level, $prefix . sprintf('(%d row%s)', scalar @{ $results }, scalar @{ $results } > 1 ? 's' : '')); } -sub dump_object { - my ($self, $level, $text, $object) = @_; - - my $copy; - if ($object) { - $copy->{$_} = $object->$_ for $object->meta->columns; - } - - $self->dump($level, $text, $copy); -} - sub show_diff { my ($self, $level, $item1, $item2, %params) = @_; @@ -259,9 +279,29 @@ sub is_tracing_enabled { sub _write { no warnings; - my ($self, $prefix, $message) = @_; + my ($self, $prefix, $message, %options) = @_; + + my @prefixes = ($prefix); + + if ($options{show_caller}) { + my $level = 1; + while (1) { + my ($package, $filename, $line, $subroutine) = caller($level); + + if (($filename // '') =~ m{LXDebug\.pm$}) { + $level++; + next; + } + + push @prefixes, "${filename}:${line}"; + last; + } + } + + $prefix = join ' ', grep { $_ } @prefixes; + my @now = gettimeofday(); - my $date = strftime("%Y-%m-%d %H:%M:%S." . sprintf('%03d', int($now[1] / 1000)) . " $$ [" . getppid() . "] ${prefix}: ", localtime($now[0])); + my $date = strftime("%Y-%m-%d %H:%M:%S." . sprintf('%03d', int($now[1] / 1000)) . " $$ [" . getpid() . "] ${prefix}: ", localtime($now[0])); local *FILE; chomp($message); @@ -273,6 +313,7 @@ sub _write_raw { local *FILE; if ((FILE_TARGET == $self->{"target"}) && open(FILE, ">>", $self->{"file"})) { + binmode FILE, ":utf8"; print FILE $message; close FILE; @@ -294,9 +335,10 @@ sub begin_request { } sub end_request { - my $self = shift; + my ($self, %params) = @_; return 1 unless want_request_timer(); - $self->_write("time", $self->get_request_time); + + $self->_write("time", sprintf('%f (%s/%s)', $self->get_request_time, $params{script_name}, $params{action})); $self->{calldepth} = 0; } @@ -304,7 +346,15 @@ sub end_request { sub log_time { my ($self, @slurp) = @_; return 1 unless want_request_timer(); - $self->_write("time", $self->get_request_time() . (@slurp ? " (@slurp)" : '')); + + my $now = $self->get_request_time; + + return 1 unless $now; + + my $diff = $self->{previous_log_time} ? int((($now - ($self->{previous_log_time} // 0)) * 10_000 + 5) / 10) : $now * 10_0000 + 5; + $self->{previous_log_time} = $now; + + $self->_write("time", "${now}s Δ ${diff}ms" . (@slurp ? " (@slurp)" : '')); } sub get_request_time {