Capture warning information and exception information in Perl and write logs
This article describes how to capture warning information, exception information, and write logs in Perl, this article provides practical examples of capturing warnings-not processing, capturing warnings-and converting them into exceptions, capturing warnings-and writing logs, capturing and writing logs, for more information, see
Although it is recommended to enable warning in every Perl script and module, you do not want to see the warning from Perl.
On the one hand, you want to use warnings in front of the Code as your security net, on the other hand, usually warnings will appear on the screen. In most cases, the customer does not know how to handle these warnings. If you are lucky, these warnings only surprise customers. Unfortunately, they are trying to fix them... (this is not a Perl programmer .)
Third, you may want to save these warnings for analysis.
In addition, there are many Perl scripts and applications in many places that do not use warnings or #! Use-w in the row. With use warnings added, a large number of warnings may be generated.
In the long run, these warnings must be eliminated, but in the short term?
Even with a long-term plan, you cannot write code with no bugs at all, and you cannot ensure that the application will never print a warning message in the future.
Can you?
You can capture them before warning is printed to the screen.
Signal
Perl has a built-in hash table named % SIG, where the key is the name of the operating system signal. The corresponding value is a function (most of which are function references). These functions are called when a specific signal is triggered.
In addition to the standard signals provided by the system, Perl also adds two internal "signals ". One of them is
In this article, we will see how this affects warning information.
Anonymous Functions
Sub {} is an anonymous function, that is, a function with only the function body but no name. (In this example, the function body is empty, but I hope you can understand what I mean .)
Capture warning-not handled
If you add the following code:
The Code is as follows:
Local $ SIG {__ WARN __}= sub {
# Warnings can be obtained here
};
This actually means that every time a warning message is generated somewhere in the program, no processing is performed. Basically, this will hide all warnings.
Capture warning -- and convert to exception
You coshould also write: You can also write it:
The Code is as follows:
Local $ SIG {__ WARN __}= sub {
Die;
};
This will call die () every time a warning is generated, that is, convert each warning to an exception.
If you want to include warning information in the exception, you can write it as follows:
The Code is as follows:
Local $ SIG {__ WARN __}= sub {
My $ message = shift;
Die $ message;
};
The actual warning information is passed to the anonymous function as a unique parameter.
Capture warnings -- and write logs
You may want to do something else in the middle:
Filter out noisy warning information for later analysis:
The Code is as follows:
Local $ SIG {__ WARN __}= sub {
My $ message = shift;
Logger ($ message );
};
Here we assume that logger () is your log writing function.
Write logs
Assume that your application already has a log mechanism. If you don't have one, you 'd better add it. Even if you cannot add it, you need the built-in logging mechanism of the operating system. For example, Linux syslog, MS Windows Event Logger, other operating systems also have their internal logging mechanism.
In this example, we use a self-made logger () function to represent this idea.
Complete example of capturing and writing logs
The Code is as follows:
#! /Usr/bin/perl
Use strict;
Use warnings;
Local $ SIG {__ WARN __}= sub {
My $ message = shift;
Logger ('warning', $ message );
};
My $ counter;
Count ();
Print "$ counter \ n ";
Sub count {
$ Counter = $ counter + 42;
}
Sub logger {
My ($ level, $ msg) = @_;
If (open my $ out, '>', 'log.txt '){
Chomp $ msg;
Print $ out "$ level-$ msg \ n ";
}
}
The following line is added to the log.txt file:
The Code is as follows:
Use of uninitialized value in addition (+) at code_with_warnings.pl line 14.
The $ counter variable and the count () function are only part of the warning example.
Warning Information in the warning processing function
_ WARN _ is automatically disabled during function execution. Therefore, the (new) warning information generated during the warning processing function execution does not cause infinite loops.
You can learn more in the perlvar document.
Avoid multiple warnings
Note that duplicate warning messages may flood log files. I can use a simple cache-like feature to reduce the number of duplicate warning messages.
The Code is as follows:
#! /Usr/bin/perl
Use strict;
Use warnings;
My % WARNS;
Local $ SIG {__ WARN __}= sub {
My $ message = shift;
Return if $ WARNS {$ message} ++;
Logger ('warning', $ message );
};
My $ counter;
Count ();
Print "$ counter \ n ";
$ Counter = undef;
Count ();
Sub count {
$ Counter = $ counter + 42;
}
Sub logger {
My ($ level, $ msg) = @_;
If (open my $ out, '>', 'log.txt '){
Chomp $ msg;
Print $ out "$ level-$ msg \ n ";
}
}
As you can see, we assign the $ counter variable to undef and call the count () function again to generate the same warning.
We also replaced the _ WARN _ handler with a slightly more complex version:
The Code is as follows:
My % WARNS;
Local $ SIG {__ WARN __}= sub {
My $ message = shift;
Return if $ WARNS {$ message} ++;
Logger ('warning', $ message );
};
Before calling logger, check whether the current string is in the % WARNShash table. If not, it is added and logger () is called (). If yes, call return instead of record the same event twice.
You may recall that we used the same idea in unique values in an array.
What is local?
In all the examples above, I use the local function to localize (warn) the effect. Strictly speaking, we do not need to do this in these examples, because assume that the Code is the first part of the main script. In this case, it doesn't matter. After all, it is in the global scope.
However, it is best to use this method.
Local is important for limiting (warning) Changes in the module. In particular, the modules to be released. If there is no localization, the entire application will be affected. Limit limits the impact to the closed code block.
Avoid using global % WARNS
If you are using Perl 5.10 or an updated version, you can rewrite the code to replace the global variable % WARNS. To do this, use v5.10; at the beginning of the script, and then use the state keyword inside the anonymous function to declare the variable.
The Code is as follows:
#! /Usr/bin/perl
Use strict;
Use warnings;
Use v5.10;
Local $ SIG {__ WARN __}= sub {
State % WARNS;
My $ message = shift;
Return if $ WARNS {$ message} ++;
Logger ('warning', $ message );
};