是否可以使用log::Log4perl注册一个函数来预处理日志消息?
在: 我可以很好地打印我的引用,而不是是否可以使用log::Log4perl注册一个函数来预处理日志消息?,perl,logging,log4perl,Perl,Logging,Log4perl,在: 我可以很好地打印我的引用,而不是数组(0xFFDFKDJ)。但是每次输入这么长的代码太无聊了。我只想: $logger->preprocessor({ filter => \&Data::Dumper::Dumper, value => $ref }); $logger->debug( $ref, $ref2 ); $logger->info( $array ); 和$ref,$ref2和$array将由Data::Dumper转
数组(0xFFDFKDJ)
。但是每次输入这么长的代码太无聊了。我只想:
$logger->preprocessor({
filter => \&Data::Dumper::Dumper,
value => $ref
});
$logger->debug( $ref, $ref2 );
$logger->info( $array );
和$ref
,$ref2
和$array
将由Data::Dumper转储
有没有办法做到这一点
UPD在你的回答的帮助下,我做了 现在你只要:
log4perl.appender.A1.layout=FallbackLayout
log4perl.appender.A1.layout.chain=PatternLayout
log4perl.appender.A1.layout.chain.ConversionPattern=%m%n
log4perl.appender.A1.warp_message = sub { $#_ = 2 if @_ > 3; \
return @_; }
# OR
log4perl.appender.A1.warp_message = main::warp_my_message
sub warp_my_message {
my( @chunks ) = @_;
use Data::Dump qw/ pp /;
for my $msg ( @chunks ) {
$msg = pp $msg if ref $msg;
}
return @chunks;
}
UPD2
或者你可以使用这个小模块
log4perl.appender.SomeAPP.warp_message = Preprocess::Messages::msg_filter
log4perl.appender.SomeAPP.layout = Preprocess::Messages
package Preprocess::Messages;
sub msg_filter {
my @chunks = @_;
for my $msg ( @chunks ) {
$msg = pp $msg if ref $msg;
}
return @chunks;
};
sub render {
my $self = shift;
my $layout = Log::Log4perl::Layout::PatternLayout->new(
'%d %P %p> %c %F:%L %M%n %m{indent=2}%n%n'
);
$_[-1] += 1; # increase level of the caller
return $layout->render( join $Log::Log4perl::JOIN_MSG_ARRAY_CHAR, @{ shift() }, @_ );
}
sub new {
my $class = shift;
$class = ref ($class) || $class;
return bless {}, $class;
}
1;
是的,当然可以设置“warp\u message=0”并将msg\u过滤器和渲染组合在一起
log4perl.appender.SomeAPP.warp_message = 0
log4perl.appender.SomeAPP.layout = Preprocess::Messages
sub render {
my($self, $message, $category, $priority, $caller_level) = @_;
my $layout = Log::Log4perl::Layout::PatternLayout->new(
'%d %P %p> %c %F:%L %M%n %m{indent=2}%n%n'
);
for my $item ( @{ $message } ) {
$item = pp $item if ref $item;
}
$message = join $Log::Log4perl::JOIN_MSG_ARRAY_CHAR, @$message;
return $layout->render( $message, $category, $priority, $caller_level+1 );
}
简单的方法:使用warp\u消息
最简单的方法是创建一个自定义appender,这样您就可以获得传递给记录器的原始引用:
package DumpAppender;
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Indent = 0;
$Data::Dumper::Terse = 1;
sub new {
bless {}, $_[0];
}
sub log {
my($self, %params) = @_;
print ref($_) ? Dumper($_) : $_ for @{ $params{message} };
print "\n";
}
package main;
use strict;
use warnings;
use Log::Log4perl;
Log::Log4perl->init(\q{
log4perl.rootLogger=DEBUG,Dump
log4perl.appender.Dump=DumpAppender
log4perl.appender.Dump.layout=NoopLayout
log4perl.appender.Dump.warp_message=0
});
my $logger = Log::Log4perl->get_logger;
$logger->debug(
'This is a string, but this is a reference: ',
{ foo => 'bar' },
);
输出:
这是一个字符串,但这是一个引用:{'foo'=>'bar'}
不幸的是,如果您采用这种方法,您将无法编写自己的代码来处理布局、打开文件等。除了只需要打印到屏幕上的非常简单的项目外,我不会采用这种方法
更好的方法:复合追加器
更好的方法是自己写。复合appender在以某种方式对消息进行操作(例如过滤或缓存)后,将消息转发到另一个appender。使用这种方法,您只能编写用于转储引用的代码,并让现有的appender来完成繁重的工作
下面显示如何编写复合追加器。其中一些在的文档中有解释,但我从Mike Schilli的中复制了很多:
输出:
2015/09/14 13:38:47调试这是一个字符串,但这是一个引用:{'foo'=>'bar'}
请注意,如果通过API而不是文件初始化Log::Log4perl,则必须执行一些额外的步骤。这在Log::Log4perl::Appender文档的一节中有记录。如果我没记错的话,我想您可以定制一个Appender并调用它。找不到我的旧代码,但文档中有一个缩进示例,我认为您可以创建一个日志子,如果ref()eq'ARRAY'。。。
package DumpAppender;
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Indent = 0;
$Data::Dumper::Terse = 1;
sub new {
bless {}, $_[0];
}
sub log {
my($self, %params) = @_;
print ref($_) ? Dumper($_) : $_ for @{ $params{message} };
print "\n";
}
package main;
use strict;
use warnings;
use Log::Log4perl;
Log::Log4perl->init(\q{
log4perl.rootLogger=DEBUG,Dump
log4perl.appender.Dump=DumpAppender
log4perl.appender.Dump.layout=NoopLayout
log4perl.appender.Dump.warp_message=0
});
my $logger = Log::Log4perl->get_logger;
$logger->debug(
'This is a string, but this is a reference: ',
{ foo => 'bar' },
);
package DumpAppender;
use strict;
use warnings;
our @ISA = qw(Log::Log4perl::Appender);
use Data::Dumper;
$Data::Dumper::Indent = 0;
$Data::Dumper::Terse = 1;
sub new {
my ($class, %options) = @_;
my $self = {
appender => undef,
%options
};
# Pass back the appender to be limited as a dependency to the configuration
# file parser.
push @{ $options{l4p_depends_on} }, $self->{appender};
# Run our post_init method in the configurator after all appenders have been
# defined to make sure the appenders we're connecting to really exist.
push @{ $options{l4p_post_config_subs} }, sub { $self->post_init() };
bless $self, $class;
}
sub log {
my ($self, %params) = @_;
# Adjust call stack so messages are reported with the correct caller and
# file
local $Log::Log4perl::caller_depth = $Log::Log4perl::caller_depth + 2;
# Dump all references with Data::Dumper
$_ = ref($_) ? Dumper($_) : $_ for @{ $params{message} };
$self->{app}->SUPER::log(
\%params,
$params{log4p_category},
$params{log4p_level}
);
}
sub post_init {
my ($self) = @_;
if(! exists $self->{appender}) {
die "No appender defined for " . __PACKAGE__;
}
my $appenders = Log::Log4perl->appenders();
my $appender = Log::Log4perl->appenders()->{$self->{appender}};
if(! defined $appender) {
die "Appender $self->{appender} not defined (yet) when " .
__PACKAGE__ . " needed it";
}
$self->{app} = $appender;
}
package main;
use strict;
use warnings;
use Log::Log4perl;
Log::Log4perl->init(\q{
log4perl.rootLogger=DEBUG, Dump
log4perl.appender.Dump=DumpAppender
log4perl.appender.Dump.appender=SCREEN
log4perl.appender.SCREEN=Log::Log4perl::Appender::Screen
log4perl.appender.SCREEN.layout=PatternLayout
log4perl.appender.SCREEN.layout.ConversionPattern=%d %p %m%n
});
my $logger = Log::Log4perl->get_logger;
$logger->debug(
'This is a string, but this is a reference: ',
{ foo => 'bar' },
);