$SIG{__WARN__} 处理警告use strict;
use warnings;
# 保存原始警告处理器
my $orig_warn_handler = $SIG{__WARN__};
# 自定义警告处理器
$SIG{__WARN__} = sub {
my $message = shift;
# 记录到日志文件
open my $log, '>>', 'warnings.log' or die "无法打开日志文件: $!";
print $log localtime() . " - 警告: $message";
close $log;
# 同时打印到屏幕(可选)
print STDERR "警告: $message";
};
# 示例:生成警告
my $undef_value;
print $undef_value; # 会触发警告
use POSIX 'strftime';
my $LOG_FILE = 'app_warnings.log';
$SIG{__WARN__} = sub {
my $msg = shift;
chomp $msg;
my $timestamp = strftime("%Y-%m-%d %H:%M:%S", localtime);
# 写入日志
if (open my $fh, '>>', $LOG_FILE) {
print $fh "[$timestamp] WARN: $msg\n";
close $fh;
} else {
# 如果无法写入日志,至少打印到STDERR
print STDERR "无法写入警告日志: $! - 原始警告: $msg\n";
}
# 可选:调用原始处理器
if (ref $orig_warn_handler eq 'CODE') {
$orig_warn_handler->($msg);
}
};
eval 捕获异常use strict;
use warnings;
sub write_to_log {
my ($level, $message) = @_;
my $timestamp = localtime();
open my $log, '>>', 'errors.log' or die "无法打开日志文件: $!";
print $log "[$timestamp] $level: $message\n";
close $log;
}
# 使用 eval 捕获异常
eval {
# 可能出错的代码
open my $fh, '<', 'nonexistent.txt' or die "无法打开文件: $!";
# ... 处理文件
1; # 返回 true 表示成功
} or do {
my $error = $@ || 'Unknown error';
write_to_log('ERROR', $error);
# 可以选择重新抛出或处理错误
warn "操作失败: $error";
};
use strict;
use warnings;
use Try::Tiny;
# 配置日志
my $LOG_FILE = 'app_errors.log';
sub log_error {
my ($level, $message, @context) = @_;
my $timestamp = localtime();
my $context_str = @context ? " [" . join(", ", @context) . "]" : "";
open my $fh, '>>', $LOG_FILE or die "无法打开日志文件: $!";
print $fh "[$timestamp] $level: $message$context_str\n";
close $fh;
}
try {
# 可能出错的代码
my $result = risky_operation();
print "成功: $result\n";
}
catch {
my $error = $_;
chomp $error;
# 记录错误
log_error('ERROR', $error, __FILE__, __LINE__);
# 可选:发送邮件通知等
# notify_admin($error);
# 恢复操作
recover_from_error();
}
finally {
# 无论成功失败都会执行
cleanup_resources();
};
use strict;
use warnings;
use Log::Log4perl;
# 配置文件
my $config = q(
log4perl.rootLogger = INFO, LOGFILE, SCREEN
log4perl.appender.LOGFILE = Log::Log4perl::Appender::File
log4perl.appender.LOGFILE.filename = app.log
log4perl.appender.LOGFILE.mode = append
log4perl.appender.LOGFILE.layout = PatternLayout
log4perl.appender.LOGFILE.layout.ConversionPattern = [%d] %p %m%n
log4perl.appender.SCREEN = Log::Log4perl::Appender::Screen
log4perl.appender.SCREEN.stderr = 1
log4perl.appender.SCREEN.layout = PatternLayout
log4perl.appender.SCREEN.layout.ConversionPattern = [%d] %p %m%n
# 捕获警告
log4perl.category.warn = WARN, LOGFILE
log4perl.category.warn.additivity= 0
);
# 初始化
Log::Log4perl::init(\$config);
my $logger = Log::Log4perl->get_logger();
# 重定向警告到日志
$SIG{__WARN__} = sub {
my $msg = shift;
$logger->warn("警告捕获: $msg");
};
# 使用 try-catch 记录异常
use Try::Tiny;
sub risky_operation {
try {
# ... 操作代码
$logger->info("操作开始");
# 可能失败的操作
die "操作失败" if rand() < 0.5;
$logger->info("操作成功");
return 1;
}
catch {
$logger->error("操作失败: $_");
$logger->error("堆栈跟踪: " . Carp::longmess());
return 0;
};
}
risky_operation();
use strict;
use warnings;
use Log::Dispatch;
use Log::Dispatch::File;
use Log::Dispatch::Screen;
# 创建分发器
my $log = Log::Dispatch->new(
outputs => [
[
'File',
min_level => 'debug',
filename => 'application.log',
mode => 'append',
format => '[%d] %p %m%n',
],
[
'Screen',
min_level => 'warning',
stderr => 1,
format => '[%d] %p %m%n',
],
]
);
# 警告处理器
$SIG{__WARN__} = sub {
my $msg = shift;
$log->warning("警告: $msg");
};
# 异常处理
eval {
# 业务逻辑
$log->info("开始处理");
# ... 可能出错的代码
$log->info("处理完成");
} or do {
my $error = $@ || 'Unknown error';
$log->error("异常捕获: $error");
};
# 记录不同级别
$log->debug("调试信息");
$log->info("一般信息");
$log->warning("警告信息");
$log->error("错误信息");
$log->critical("严重错误");
#!/usr/bin/perl
use strict;
use warnings;
use Carp qw(cluck);
use Try::Tiny;
package MyApp::Logger;
use Log::Log4perl;
sub new {
my ($class, %args) = @_;
# 配置
my $config = $args{config} || q(
log4perl.rootLogger = INFO, MAIN
log4perl.appender.MAIN = Log::Log4perl::Appender::File
log4perl.appender.MAIN.filename = app.log
log4perl.appender.MAIN.mode = append
log4perl.appender.MAIN.layout = PatternLayout
log4perl.appender.MAIN.layout.ConversionPattern = [%d] %p %F:%L %m%n
);
Log::Log4perl::init(\$config);
my $self = {
logger => Log::Log4perl->get_logger(),
};
bless $self, $class;
$self->setup_warning_handler();
return $self;
}
sub setup_warning_handler {
my $self = shift;
$SIG{__WARN__} = sub {
my $msg = shift;
$self->{logger}->warn($msg);
# 保存原始警告输出
print STDERR "警告: $msg" unless $ENV{SUPPRESS_WARNINGS};
};
}
sub log_error {
my ($self, $error, %context) = @_;
my $message = $error;
if (my $stack = $context{stack_trace}) {
$message .= "\n堆栈跟踪:\n$stack";
}
$self->{logger}->error($message);
}
package MyApp;
use base 'MyApp::Logger';
sub new {
my ($class) = @_;
my $self = $class->SUPER::new();
bless $self, $class;
return $self;
}
sub risky_operation {
my $self = shift;
try {
$self->{logger}->info("开始风险操作");
# 模拟可能失败的代码
if (rand() < 0.3) {
die "随机失败";
}
# 可能产生警告
my $undefined;
print $undefined; # 警告
$self->{logger}->info("操作成功");
return 1;
}
catch {
my $error = $_;
# 获取堆栈跟踪
local $Carp::CarpLevel = 1;
my $stack_trace = cluck();
# 记录错误
$self->log_error($error,
stack_trace => $stack_trace,
timestamp => time(),
operation => 'risky_operation',
);
# 恢复或重试逻辑
$self->recover_from_error($error);
return 0;
};
}
sub recover_from_error {
my ($self, $error) = @_;
$self->{logger}->info("尝试恢复...");
# 恢复逻辑
}
# 主程序
package main;
my $app = MyApp->new();
$app->risky_operation();
1;
package SimpleLogger;
use strict;
use warnings;
use POSIX 'strftime';
use Fcntl qw(:flock);
sub new {
my ($class, %args) = @_;
my $self = {
log_file => $args{log_file} || 'app.log',
level => $args{level} || 'INFO',
levels => {
DEBUG => 1,
INFO => 2,
WARN => 3,
ERROR => 4,
FATAL => 5,
},
};
bless $self, $class;
return $self;
}
sub log {
my ($self, $level, $message, %context) = @_;
# 检查日志级别
return if $self->{levels}{$level} < $self->{levels}{$self->{level}};
my $timestamp = strftime("%Y-%m-%d %H:%M:%S", localtime);
my $file = $context{file} || (caller(1))[1];
my $line = $context{line} || (caller(1))[2];
my $log_msg = sprintf("[%s] %-5s %s:%d - %s\n",
$timestamp, $level, $file, $line, $message);
# 线程安全写入
if (open my $fh, '>>', $self->{log_file}) {
flock($fh, LOCK_EX);
print $fh $log_msg;
flock($fh, LOCK_UN);
close $fh;
}
# 错误级别也输出到STDERR
if ($level eq 'ERROR' || $level eq 'FATAL') {
print STDERR $log_msg;
}
}
# 快捷方法
sub debug { shift->log('DEBUG', @_) }
sub info { shift->log('INFO', @_) }
sub warn { shift->log('WARN', @_) }
sub error { shift->log('ERROR', @_) }
sub fatal { shift->log('FATAL', @_) }
1;
这个详细指南涵盖了从基本到高级的警告和异常捕获技术。根据项目需求选择合适的方案,大型项目推荐使用 Log::Log4perl,小型项目可以使用 Try::Tiny 配合自定义日志。