![]() |
![]()
| ![]() |
![]()
NAMELog::Any::App - An easy way to use Log::Any in applicationsVERSIONThis document describes version 0.540 of Log::Any::App (from Perl distribution Log-Any-App), released on 2019-01-09.SYNOPSISMost of the time you only need to do this:# in your script.pl use Log::Any::App '$log'; $log->warn("blah ..."); if ($log->is_debug) { ... } # or, in command line % perl -MLog::Any::App -MModuleThatUsesLogAny -e'...' Here's the default logging that Log::Any::App sets up for you: Condition screen file syslog dir --------------------------------+-------+------------------+-------------+--- -e (one-liners) y - - - Scripts running as normal user y ~/NAME.log - - Scripts running as root y /var/log/NAME.log - - Daemons - y y - You can customize level from outside the script, using environment variables or command-line options (won't interfere with command-line processing modules like Getopt::Long etc): % DEBUG=1 script.pl % LOG_LEVEL=trace script.pl % script.pl --verbose And to customize other stuffs: use Log::Any::App '$log', -syslog => 1, # turn on syslog logging explicitly -screen => 0, # turn off screen logging explicitly -file => {path=>'/foo/bar', max_size=>'10M', histories=>10}; # customize file logging For more customization like categories, per-category level, per-output level, multiple outputs, string patterns, etc see "USING AND EXAMPLES" and init(). DESCRIPTIONIMPORTANT: Please read "ROAD TO 1.0" on some incompatibilities in the near future, before 1.0 is released.Log::Any::App is a convenient combo for Log::Any and Log::Log4perl (although alternative backends beside Log4perl might be considered in the future). To use Log::Any::App you need to be sold on the idea of Log::Any first, so please do a read up on that first. The goal of Log::Any::App is to provide developers an easy and concise way to add logging to their *applications*. That is, instead of modules; modules remain using Log::Any to produce logs. Applications can upgrade to full Log4perl later when necessary, although in my experience, they usually don't. With Log::Any::App, you can replace this code in your application: use Log::Any '$log'; use Log::Any::Adapter; use Log::Log4perl; my $log4perl_config = ' some long multiline config...'; Log::Log4perl->init(\$log4perl_config); Log::Any::Adapter->set('Log4perl'); with just this: use Log::Any::App '$log'; # plus some other options when necessary Most of the time you don't need to configure anything as Log::Any::App will construct the most appropriate default Log4perl configuration for your application. USING AND EXAMPLESTo use Log::Any::App, just do:use Log::Any::App '$log'; or from the command line: % perl -MLog::Any::App -MModuleThatUsesLogAny -e ... This will send logs to screen as well as file (unless -e scripts, which only log to screen). Default log file is ~/$SCRIPT_NAME.log, or /var/log/$SCRIPT_NAME.log if script is running as root. Default level is 'warn'. The 'use Log::Any::App' statement can be issued before or after the modules that use Log::Any, it doesn't matter. Logging will be initialized in the INIT phase by Log::Any::App. You are not required to import '$log', and don't need to if you do not produce logs in your application (only in the modules). Changing logging levelSince one of the most commonly tweaked logging setting is level (for example: increasing level when debugging problems), Log::Any::App provides several mechanisms to change log level, either from the script or from outside the script, for your convenience. Below are the mechanisms, ordered from highest priority:
These mechanisms are explained in more details in the documentation for the init() function. But below are some examples. To change level from inside the script: use Log::Any::App '$log', -level => 'debug'; This is useful if you want a fixed level that cannot be overridden by other mechanisms (since setting level using import argument has the highest priority). But oftentimes what you want is changing level without modifying the script itself. Thereby, just write: use Log::Any::App '$log'; and then you can use environment variables to change level: TRACE=1 script.pl; # setting level to trace DEBUG=1 script.pl; # setting level to debug VERBOSE=1 script.pl; # setting level to info QUIET=1 script.pl; # setting level to error LOG_LEVEL=trace script.pl; # setting a specific log level or command-line options: script.pl --trace script.pl --debug script.pl --verbose script.pl --quiet script.pl --log_level=debug; # '--log-level debug' will also do Regarding command-line options: Log::Any::App won't consume the command-line options from @ARGV and thus won't interfere with command-line processing modules like Getopt::Long or App::Options. If you use a command-line processing module and plan to use command-line options to set level, you might want to define these level options, or your command-line processing module will complain about unknown options. Changing default levelThe default log level is 'warn'. To change the default level, you can use 'main' package variables (since they have the lowest priority):use Log::Any::App '$log'; BEGIN { our $Log_Level = 'info' } # be more verbose by default Then you will still be able to use level flag files or environment variables or command-line options to override this setting. Changing per-output levelLogging level can also be specified on a per-output level. For example, if you want your script to be chatty on the screen but still logs to file at the default 'warn' level:SCREEN_VERBOSE=1 script.pl SCREEN_DEBUG=1 script.pl SCREEN_TRACE=1 script.pl SCREEN_LOG_LEVEL=info script.pl script.pl --screen_verbose script.pl --screen-debug script.pl --screen-trace=1 script.pl --screen-log-level=info Similarly, to set only file level, use FILE_VERBOSE, FILE_LOG_LEVEL, --file-trace, and so on. Setting default per-output levelAs with setting default level, you can also set default level on a per-output basis:use Log::Any::App '$log'; BEGIN { our $Screen_Log_Level = 'off'; our $File_Quiet = 1; # setting file level to 'error' # and so on } If a per-output level is not specified, it will default to the general log level. Enabling/disabling outputTo disable a certain output, you can do this:use Log::Any::App '$log', -file => 0; or: use Log::Any::App '$log', -screen => {level=>'off'}; and this won't allow the output to be re-enabled from outside the script. However if you do this: use Log::Any::App; BEGIN { our $Screen_Log_Level = 'off' } then by default screen logging is turned off but you will be able to override the screen log level using level flag files or environment variables or command-line options (SCREEN_DEBUG, --screen-verbose, and so on). Changing log level of cron scriptsEnvironment variables and command-line options allow changing log level without modifying the script. But for scripts specified in crontab, they still require changing crontab entries, e.g.:# turn on debugging */5 * * * * DEBUG=1 foo # be silent */5 * * * * bar --quiet Another mechanism, level flag file, is useful in this case. By doing: $ echo debug > ~/foo.log_level # touch /etc/bar.QUIET you can also change log levels without modifying your crontab. Changing log file name/locationBy default Log::Any::App will log to file to ~/$NAME.log (or /var/log/$NAME.log if script is running as root), where $NAME is taken from the basename of $0. But this can be changed using:use Log::Any::App '$log', -name => 'myprog'; Or, using custom path: use Log::Any::App '$log', -file => '/path/to/file'; Changing other output parametersEach output argument can accept a hashref to specify various options. For example:use Log::Any::App '$log', -screen => {color=>0}, # never use color -file => {path=>'/var/log/foo', max_size=>'10M', histories=>10, }, For all the available options of each output, see the init() function. Logging to syslogLogging to syslog is enabled by default if your script looks like or declare that it is a daemon, e.g.:use Net::Daemon; # this indicate your program is a daemon use Log::Any::App; # syslog logging will be turned on by default use Log::Any::App -daemon => 1; # script declares that it is a daemon # idem package main; our $IS_DAEMON = 1; But if you are certain you don't want syslog logging: use Log::Any::App -syslog => 0; Logging to directoryThis is done using Log::Dispatch::Dir where each log message is logged to a different file in a specified directory. By default logging to dir is not turned on, to turn it on:use Log::Any::App '$log', -dir => 1; For all the available options of directory output, see the init() function. Multiple outputsEach output argument can accept an arrayref to specify more than one output. For example below is a code to log to three files:use Log::Any::App '$log', -file => [1, # default, to ~/$NAME.log or /var/log/$NAME.log "/var/log/log1", {path=>"/var/log/debug_foo", category=>'Foo', level=>'debug'}]; Changing level of certain module(s)Suppose you want to shut up logs from modules Foo, Bar::Baz, and Qux (and their submodules as well, e.g. Foo::Alpha, Bar::Baz::Beta::Gamma) because they are too noisy:use Log::Any::App '$log', -category_level => { Foo => 'off', 'Bar::Baz' => 'off', Qux => 'off' }; or (same thing): use Log::Any::App '$log', -category_alias => { -noisy => [qw/Foo Bar::Baz Qux/] }, -category_level => { -noisy => 'off' }; You can even specify this on a per-output basis. Suppose you only want to shut up the noisy modules on the screen, but not on the file: use Log::Any::App '$log', -category_alias => { -noisy => [qw/Foo Bar::Baz Qux/] }, -screen => { category_level => { -noisy => 'off' } }; Or perhaps, you want to shut up the noisy modules everywhere, except on the screen: use Log::Any::App '$log', -category_alias => { -noisy => [qw/Foo Bar::Baz Qux/] }, -category_level => { -noisy => 'off' }, -syslog => 1, # uses general -category_level -file => "/var/log/foo", # uses general -category_level -screen => { category_level => {} }; # overrides general -category_level You can also do this from the outside the script using environment variable, which is more flexible. Encode data structure using JSON: % LOG_SHOW_CATEGORY=1 \ LOG_CATEGORY_ALIAS='{"-noisy":["Foo","Bar::Baz","Quz"]}' \ LOG_CATEGORY_LEVEL='{"-noisy":"off"}' script.pl ... Only displaying log from certain module(s)Use a combination of LOG_LEVEL and LOG_CATEGORY_LEVEL. For example:% LOG_LEVEL=off LOG_CATEGORY_LEVEL='{"Foo.Bar":"trace", "Baz":"info"}' \ script.pl ... Displaying category name% LOG_SHOW_CATEGORY=1 script.pl ... Now instead of: [25] Starting baz ritual ... now log messages will be prefixed with category: [cat Foo.Bar][25] Starting baz ritual ... Displaying location name% LOG_SHOW_LOCATION=1 script.pl ... Now log messages will be prefixed with location (function/file/line number) information: [loc Foo::Bar lib/Foo/Bar.pm (12)][25] Starting baz ritual ... Preventing logging level to be changed from outside the scriptSometimes, for security/audit reasons, you don't want to allow script caller to change logging level. As explained previously, you can use the 'level' import argument (the highest priority of level-setting):use Log::Any::App '$log', -level => 'debug'; # always use debug level TODO: Allow something like 'debug+' to allow other mechanisms to *increase* the level but not decrease it. Or 'debug-' to allow other mechanisms to decrease level but not increase it. And finally 'debug,trace' to specify allowable levels (is this necessary?) DebuggingTo see the Log4perl configuration that is generated by Log::Any::App and how it came to be, set environment LOGANYAPP_DEBUG to true.PATTERN STYLESLog::Any::App provides some styles for Log4perl patterns. You can specify "pattern_style" instead of directly specifying "pattern". example:use Log::Any::App -screen => {pattern_style=>"script_long"}; Name Description Example output ---- ----------- -------------- plain The message, the whole message, Message and nothing but the message. Used by dir logging. Equivalent to pattern: '%m' plain_nl Message plus newline. The default Message for screen without LOG_ELAPSED_TIME_IN_SCREEN. Equivalent to pattern: '%m%n' script_short For scripts that run for a short [234] Message time (a few seconds). Shows just the number of milliseconds. This is the default for screen under LOG_ELAPSED_TIME_IN_SCREEN. Equivalent to pattern: '[%r] %m%n' script_long Scripts that will run for a [2010-04-22 18:01:02] Message while (more than a few seconds). Shows date/time. Equivalent to pattern: '[%d] %m%n' daemon For typical daemons. Shows PID [pid 1234] [2010-04-22 18:01:02] Message and date/time. This is the default for file logging. Equivalent to pattern: '[pid %P] [%d] %m%n' syslog Style suitable for syslog [pid 1234] Message logging. Equivalent to pattern: '[pid %p] %m' For each of the above there are also "cat_XXX" (e.g. "cat_script_long") which are the same as XXX but with "[cat %c]" in front of the pattern. It is used mainly to show categories and then filter by categories. You can turn picking default pattern style with category using environment variable LOG_SHOW_CATEGORY. And for each of the above there are also "loc_XXX" (e.g. "loc_syslog") which are the same as XXX but with "[loc %l]" in front of the pattern. It is used to show calling location (file, function/method, and line number). You can turn picking default pattern style with location prefix using environment variable LOG_SHOW_LOCATION. If you have a favorite pattern style, please do share them. BUGS/TODOSNeed to provide appropriate defaults for Windows/other OS.ROAD TO 1.0Here are some planned changes/development before 1.0 is reached. There might be some incompatibilities, please read this section carefully.
FUNCTIONSNone is exported.init(\@args)This is the actual function that implements the setup and configuration of logging. You normally need not call this function explicitly (but see below), it will be called once in an INIT block. In fact, when you do:use Log::Any::App 'a', 'b', 'c'; it is actually passed as: init(['a', 'b', 'c']); You will need to call init() manually if you require Log::Any::App at runtime, in which case it is too late to run INIT block. If you want to run Log::Any::App in runtime phase, do this: require Log::Any::App; Log::Any::App::init(['a', 'b', 'c']); Arguments to init can be one or more of:
FAQWhy?I initially wrote Log::Any::App because I'm sick of having to parse command-line options to set log level like --verbose, --log-level=debug for every script. Also, before using Log::Any I previously used Log4perl directly and modules which produce logs using Log4perl cannot be directly use'd in one-liners without Log4perl complaining about uninitialized configuration or some such. Thus, I like Log::Any's default null adapter and want to settle using Log::Any for any kind of logging. Log::Any::App makes it easy to output Log::Any logs in your scripts and even one-liners.What's the benefit of using Log::Any::App?You get all the benefits of Log::Any, as what Log::Any::App does is just wrap Log::Any and Log4perl with some nice defaults. It provides you with an easy way to consume Log::Any logs and customize level/some other options via various ways.And what's the benefit of using Log::Any?This is better described in the Log::Any documentation itself, but in short: Log::Any frees your module users to use whatever logging framework they want. It increases the reusability of your modules.Do I need Log::Any::App if I am writing modules?No, if you write modules just use Log::Any.Why use Log4perl?Log::Any::App uses the Log4perl adapter to display the logs because it is mature, flexible, featureful. The other alternative adapter is Log::Dispatch, but you can use Log::Dispatch::* output modules in Log4perl and (currently) not vice versa.Other adapters might be considered in the future, for now I'm fairly satisfied with Log4perl. It does have a slightly heavy startup cost for my taste, but it is still bearable. Are you coupling adapter with Log::Any (thus defeating Log::Any's purpose)?No, producing logs are still done with Log::Any as usual and not tied to Log4perl in any way. Your modules, as explained above, only 'use Log::Any' and do not depend on Log::Any::App at all.Should portions of your application code get refactored into modules later, you don't need to change the logging part. And if your application becomes more complex and Log::Any::App doesn't suffice your custom logging needs anymore, you can just replace 'use Log::Any::App' line with something more adequate. How do I create extra logger objects?The usual way as with Log::Any:my $other_log = Log::Any->get_logger(category => $category); My needs are not met by the simple configuration system of Log::Any::App!You can use the Log4perl adapter directly and write your own Log4perl configuration (or even other adapters). Log::Any::App is meant for quick and simple logging output needs anyway (but do tell me if your logging output needs are reasonably simple and should be supported by Log::Any::App).What is array output for?Logging to a Perl array might be useful for testing/debugging, or (one use-case I can think of) for letting users of your program connect to your program directly to request viewing the logs being produced (although logging to other outputs doesn't preclude this ability). For example, here is a program that uses a separate thread to listen to Unix socket for requests to view the (last 100) logs. Requires perl built with threads enabled.use threads; use threads::shared; BEGIN { our @buf :shared } use IO::Socket::UNIX::Util qw(create_unix_stream_socket); use Log::Any::App '$log', -array => [{array => 'main::buf', max_elems=>100}]; my $sock = create_unix_stream_socket('/tmp/app-logview.sock'); # thread to listen to unix socket and receive log viewing instruction my $thr = threads->create( sub { local $| = 1; while (my $cli = $sock->accept) { while (1) { print $cli "> "; my $line = <$cli>; last unless $line; if ($line =~ /\Ar(ead)?\b/i) { print $cli @buf; } else { print $cli "Unknown command\n"; } } } }); # main thread, application which produces logs $|++; while (1) { $log->warnf("Log (%d) ...", ++$i); sleep 1; } After you run this program, you can connect to it, e.g. from another terminal: % socat UNIX-CONNECT:/tmp/app-logview.sock - > read [2014/07/06 23:34:49] Log (1) ... [2014/07/06 23:34:50] Log (2) ... [2014/07/06 23:34:50] Log (3) ... [2014/07/06 23:34:51] Log (4) ... [2014/07/06 23:34:51] Log (5) ... ENVIRONMENTBelow is summary of environment variables used.Turning on/off loggingLOG (bool) Setting general levelTRACE (bool) setting general level to trace DEBUG (bool) setting general level to debug VERBOSE (bool) setting general level to info QUIET (bool) setting general level to error (turn off warnings) LOG_LEVEL (str) Setting per-output levelFILE_TRACE, FILE_DEBUG, FILE_VERBOSE, FILE_QUIET, FILE_LOG_LEVEL SCREEN_TRACE and so on DIR_TRACE and so on SYSLOG_TRACE and so on UNIXSOCK_TRACE and so on ARRAY_TRACE and so on Setting per-category levelLOG_CATEGORY_LEVEL (hash, json) LOG_CATEGORY_ALIAS (hash, json) Setting per-output, per-category levelFILE_LOG_CATEGORY_LEVEL SCREEN_LOG_CATEGORY_LEVEL and so on Controlling extra fields to logLOG_SHOW_LOCATION LOG_SHOW_CATEGORY Force-enable or disable colorCOLOR (bool) Turn on Log::Any::App's debuggingLOGANYAPP_DEBUG (bool) Turn on showing elapsed time in screenLOG_ELAPSED_TIME_IN_SCREEN (bool) Note that elapsed time is currently produced using Log::Log4perl's %r (number of milliseconds since the program started, where program started means when Log::Log4perl starts counting time). FilteringLOG_FILTER_TEXT (str) LOG_FILTER_NO_TEXT (str) LOG_FILTER_CITEXT (str) LOG_FILTER_NO_CITEXT (str) LOG_FILTER_RE (str) LOG_FILTER_NO_RE (str) Per-output filtering{FILE,DIR,SCREEN,SYSLOG,UNIXSOCK,ARRAY}_LOG_FILTER_TEXT (str) and so on Extra things to log
HOMEPAGEPlease visit the project's homepage at <https://metacpan.org/release/Log-Any-App>.SOURCESource repository is at <https://github.com/perlancar/perl-Log-Any-App>.BUGSPlease report any bugs or feature requests on the bugtracker website <https://rt.cpan.org/Public/Dist/Display.html?Name=Log-Any-App>When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. SEE ALSOLog::Any and Log::Log4perlSome alternative logging modules: Log::Dispatchouli (based on Log::Dispatch), Log::Fast, Log::Log4perl::Tiny. Really, there are 7,451 of them (roughly one third of CPAN) at the time of this writing. AUTHORperlancar <perlancar@cpan.org>COPYRIGHT AND LICENSEThis software is copyright (c) 2019, 2015, 2014, 2013, 2012, 2011, 2010 by perlancar@cpan.org.This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
|