use constant STDERR_TARGET => 1;
use Data::Dumper;
+use List::MoreUtils qw(all);
use POSIX qw(strftime getpid);
+use Scalar::Util qw(blessed refaddr weaken looks_like_number);
use Time::HiRes qw(gettimeofday tv_interval);
-use YAML;
use SL::Request ();
+use SL::YAML;
use strict;
use utf8;
$self->message(WARN, $message);
}
-sub dump {
- my ($self, $level, $name, $variable, %options) = @_;
+sub clone_for_dump {
+ my ($src, $dumped) = @_;
+
+ return undef if !defined($src);
+ return $src if !ref($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} = [];
- my $password;
- if ($variable && ('Form' eq ref $variable) && defined $variable->{password}) {
- $password = $variable->{password};
- $variable->{password} = 'X' x 8;
+ foreach my $entry (@{ $src }) {
+ my $exists = !!$dumped->{refaddr($entry) // ''};
+ push @{ $dumped->{$addr} }, clone_for_dump($entry, $dumped);
+
+ 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);
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;
}
sub dump_yaml {
my ($self, $level, $name, $variable) = @_;
- $self->message($level, "dumping ${name}:\n" . YAML::Dump($variable));
+ $self->message($level, "dumping ${name}:\n" . SL::YAML::Dump($variable));
}
sub dump_sql_result {
map { $column_lengths{$_} = length $row->{$_} if (length $row->{$_} > $column_lengths{$_}) } keys %{ $row };
}
+ my %alignment;
+ foreach my $column (keys %column_lengths) {
+ my $all_look_like_number = all { (($_->{$column} // '') eq '') || looks_like_number($_->{$column}) } @{ $results };
+ $alignment{$column} = $all_look_like_number ? '' : '-';
+ }
+
my @sorted_names = sort keys %column_lengths;
- my $format = join '|', map { '%' . $column_lengths{$_} . 's' } @sorted_names;
+ my $format = join '|', map { '%' . $alignment{$_} . $column_lengths{$_} . 's' } @sorted_names;
$prefix .= ' ' if $prefix;
$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) = @_;
return;
}
- my @texts = map { ref $_ ? YAML::Dump($_) : $_ } ($item1, $item2);
+ my @texts = map { ref $_ ? SL::YAML::Dump($_) : $_ } ($item1, $item2);
$self->message($level, Text::Diff::diff(\$texts[0], \$texts[1], \%params));
}
sub level2string {
no warnings;
# use $_[0] as a bit mask and return levelstrings separated by /
- join '/', qw(info debug1 debug2 query trace error_call_trace request_timer WARNING)[ grep { (reverse split //, sprintf "%08b", $_[0])[$_] } 0..7 ]
+ join '/', qw(info debug1 debug2 query trace error_call_trace request_timer request WARNING trace2 show_caller)[ grep { (reverse split //, sprintf "%011b", $_[0])[$_] } 0..11 ]
}
sub begin_request {
return 1 unless want_request_timer();
my $now = $self->get_request_time;
- my $diff = int((($now - ($self->{previous_log_time} // 0)) * 10_000 + 5) / 10);
+
+ 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)" : ''));