t000755001750001750 013230423621 14060 5ustar00frewfrew000000000000Log-Contextual-0.008001eg.t100644001750001750 373413230423621 15007 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Log::Contextual::SimpleLogger; use Test::More qw(no_plan); use Log::Contextual qw(:log set_logger); my ($var1, $var2, $var3); my $complex_dispatcher = do { my $l1 = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { $var1 = shift }, }); my $l2 = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { $var2 = shift }, }); my $l3 = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { $var3 = shift }, }); my %registry = ( -logger => $l3, A1 => { -logger => $l1, lol => $l2, }, A2 => {-logger => $l2}, ); sub { my ($package, $info) = @_; my $logger = $registry{'-logger'}; if (my $r = $registry{$package}) { $logger = $r->{'-logger'} if $r->{'-logger'}; my (undef, undef, undef, $sub) = caller($info->{caller_level} + 1); $sub =~ s/^\Q$package\E:://g; $logger = $r->{$sub} if $r->{$sub}; } return $logger; } }; set_logger $complex_dispatcher; log_debug { '1.var3' }; is($var3, "[debug] 1.var3\n", "default logger works"); $var3 = ''; A1::lol(); A1::rofl(); is($var2, "[debug] 1.var2\n", "default package logger works"); is($var1, "[debug] 1.var1\n", "package::sub logger works"); $var1 = ''; $var2 = ''; A2::foo(); is($var2, "[debug] 2.var2\n", "only default package logger works"); $var2 = ''; A3::squint(); is($var3, "[debug] 2.var3\n", "global default logger works"); BEGIN { package A1; use Log::Contextual ':log'; sub lol { log_debug { '1.var2' } } sub rofl { log_debug { '1.var1' } } package A2; use Log::Contextual ':log'; sub foo { log_debug { '2.var2' } } package A3; use Log::Contextual ':log'; sub squint { log_debug { '2.var3' } } } Log-Contextual-0.008001000755001750001750 013230423621 13674 5ustar00frewfrew000000000000README100644001750001750 4506413230423621 14666 0ustar00frewfrew000000000000Log-Contextual-0.008001NAME Log::Contextual - Simple logging interface with a contextual log VERSION version 0.008001 SYNOPSIS use Log::Contextual qw( :log :dlog set_logger with_logger ); use Log::Contextual::SimpleLogger; use Log::Log4perl ':easy'; Log::Log4perl->easy_init($DEBUG); my $logger = Log::Log4perl->get_logger; set_logger $logger; log_debug { 'program started' }; sub foo { my $minilogger = Log::Contextual::SimpleLogger->new({ levels => [qw( trace debug )] }); my @args = @_; with_logger $minilogger => sub { log_trace { 'foo entered' }; my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @args; # ... slog_trace 'foo left'; }; } foo(); Beginning with version 1.008 Log::Dispatchouli also works out of the box with "Log::Contextual": use Log::Contextual qw( :log :dlog set_logger ); use Log::Dispatchouli; my $ld = Log::Dispatchouli->new({ ident => 'slrtbrfst', to_stderr => 1, debug => 1, }); set_logger $ld; log_debug { 'program started' }; DESCRIPTION Major benefits: * Efficient The default logging functions take blocks, so if a log level is disabled, the block will not run: # the following won't run if debug is off log_debug { "the new count in the database is " . $rs->count }; Similarly, the "D" prefixed methods only "Dumper" the input if the level is enabled. * Handy The logging functions return their arguments, so you can stick them in the middle of expressions: for (log_debug { "downloading:\n" . join qq(\n), @_ } @urls) { ... } * Generic "Log::Contextual" is an interface for all major loggers. If you log through "Log::Contextual" you will be able to swap underlying loggers later. * Powerful "Log::Contextual" chooses which logger to use based on user defined "CodeRef"s. Normally you don't need to know this, but you can take advantage of it when you need to later. * Scalable If you just want to add logging to your basic application, start with Log::Contextual::SimpleLogger and then as your needs grow you can switch to Log::Dispatchouli or Log::Dispatch or Log::Log4perl or whatever else. This module is a simple interface to extensible logging. It exists to abstract your logging interface so that logging is as painless as possible, while still allowing you to switch from one logger to another. It is bundled with a really basic logger, Log::Contextual::SimpleLogger, but in general you should use a real logger instead. For something more serious but not overly complicated, try Log::Dispatchouli (see "SYNOPSIS" for example.) A WORK IN PROGRESS This module is certainly not complete, but we will not break the interface lightly, so I would say it's safe to use in production code. The main result from that at this point is that doing: use Log::Contextual; will die as we do not yet know what the defaults should be. If it turns out that nearly everyone uses the ":log" tag and ":dlog" is really rare, we'll probably make ":log" the default. But only time and usage will tell. IMPORT OPTIONS See "SETTING DEFAULT IMPORT OPTIONS" for information on setting these project wide. -logger When you import this module you may use "-logger" as a shortcut for "set_logger", for example: use Log::Contextual::SimpleLogger; use Log::Contextual qw( :dlog ), -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] }); sometimes you might want to have the logger handy for other stuff, in which case you might try something like the following: my $var_log; BEGIN { $var_log = VarLogger->new } use Log::Contextual qw( :dlog ), -logger => $var_log; -levels The "-levels" import option allows you to define exactly which levels your logger supports. So the default, "[qw(debug trace warn info error fatal)]", works great for Log::Log4perl, but it doesn't support the levels for Log::Dispatch. But supporting those levels is as easy as doing use Log::Contextual -levels => [qw( debug info notice warning error critical alert emergency )]; -package_logger The "-package_logger" import option is similar to the "-logger" import option except "-package_logger" sets the logger for the current package. Unlike "-default_logger", "-package_logger" cannot be overridden with "set_logger" or "with_logger". package My::Package; use Log::Contextual::SimpleLogger; use Log::Contextual qw( :log ), -package_logger => Log::Contextual::WarnLogger->new({ env_prefix => 'MY_PACKAGE' }); If you are interested in using this package for a module you are putting on CPAN we recommend Log::Contextual::WarnLogger for your package logger. -default_logger The "-default_logger" import option is similar to the "-logger" import option except "-default_logger" sets the default logger for the current package. Basically it sets the logger to be used if "set_logger" is never called; so package My::Package; use Log::Contextual::SimpleLogger; use Log::Contextual qw( :log ), -default_logger => Log::Contextual::WarnLogger->new({ env_prefix => 'MY_PACKAGE' }); SETTING DEFAULT IMPORT OPTIONS Eventually you will get tired of writing the following in every single one of your packages: use Log::Log4perl; use Log::Log4perl ':easy'; BEGIN { Log::Log4perl->easy_init($DEBUG) } use Log::Contextual -logger => Log::Log4perl->get_logger; You can set any of the import options for your whole project if you define your own "Log::Contextual" subclass as follows: package MyApp::Log::Contextual; use base 'Log::Contextual'; use Log::Log4perl ':easy'; Log::Log4perl->easy_init($DEBUG) sub arg_default_logger { $_[1] || Log::Log4perl->get_logger } sub arg_levels { [qw(debug trace warn info error fatal custom_level)] } sub default_import { ':log' } # or maybe instead of default_logger sub arg_package_logger { $_[1] } # and almost definitely not this, which is only here for completeness sub arg_logger { $_[1] } Note the "$_[1] ||" in "arg_default_logger". All of these methods are passed the values passed in from the arguments to the subclass, so you can either throw them away, honor them, die on usage, etc. To be clear, if you define your subclass, and someone uses it as follows: use MyApp::Log::Contextual -default_logger => $foo, -levels => [qw(bar baz biff)]; Your "arg_default_logger" method will get $foo and your "arg_levels" will get "[qw(bar baz biff)]"; Additionally, the "default_import" method is what happens if a user tries to use your subclass with no arguments. The default just dies, but if you'd like to change the default to import a tag merely return the tags you'd like to import. So the following will all work: sub default_import { ':log' } sub default_import { ':dlog' } sub default_import { qw(:dlog :log ) } See Log::Contextual::Easy::Default for an example of a subclass of "Log::Contextual" that makes use of default import options. FUNCTIONS set_logger my $logger = WarnLogger->new; set_logger $logger; Arguments: "LOGGER CODEREF" "set_logger" will just set the current logger to whatever you pass it. It expects a "CodeRef", but if you pass it something else it will wrap it in a "CodeRef" for you. "set_logger" is really meant only to be called from a top-level script. To avoid foot-shooting the function will warn if you call it more than once. with_logger my $logger = WarnLogger->new; with_logger $logger => sub { if (1 == 0) { log_fatal { 'Non Logical Universe Detected' }; } else { log_info { 'All is good' }; } }; Arguments: "LOGGER CODEREF", "CodeRef $to_execute" "with_logger" sets the logger for the scope of the "CodeRef" $to_execute. As with "set_logger", "with_logger" will wrap $returning_logger with a "CodeRef" if needed. has_logger my $logger = WarnLogger->new; set_logger $logger unless has_logger; Arguments: none "has_logger" will return true if a logger has been set. log_$level Import Tag: ":log" Arguments: "CodeRef $returning_message, @args" "log_$level" functions all work the same except that a different method is called on the underlying $logger object. The basic pattern is: sub log_$level (&@) { if ($logger->is_$level) { $logger->$level(shift->(@_)); } @_ } Note that the function returns it's arguments. This can be used in a number of ways, but often it's convenient just for partial inspection of passthrough data my @friends = log_trace { 'friends list being generated, data from first friend: ' . Dumper($_[0]->TO_JSON) } generate_friend_list(); If you want complete inspection of passthrough data, take a look at the "Dlog_$level" functions. Which functions are exported depends on what was passed to "-levels". The default (no "-levels" option passed) would export: log_trace log_debug log_info log_warn log_error log_fatal Note: "log_fatal" does not call "die" for you, see "EXCEPTIONS AND ERROR HANDLING" slog_$level Mostly the same as "log_$level", but expects a string as first argument, not a block. Arguments are passed through just the same, but since it's just a string, interpolation of arguments into it must be done manually. my @friends = slog_trace 'friends list being generated.', generate_friend_list(); logS_$level Import Tag: ":log" Arguments: "CodeRef $returning_message, Item $arg" This is really just a special case of the "log_$level" functions. It forces scalar context when that is what you need. Other than that it works exactly same: my $friend = logS_trace { 'I only have one friend: ' . Dumper($_[0]->TO_JSON) } friend(); See also: "DlogS_$level". slogS_$level Mostly the same as "logS_$level", but expects a string as first argument, not a block. Arguments are passed through just the same, but since it's just a string, interpolation of arguments into it must be done manually. my $friend = slogS_trace 'I only have one friend.', friend(); Dlog_$level Import Tag: ":dlog" Arguments: "CodeRef $returning_message, @args" All of the following six functions work the same as their "log_$level" brethren, except they return what is passed into them and put the stringified (with Data::Dumper::Concise) version of their args into $_. This means you can do cool things like the following: my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all; and the output might look something like: names: "fREW" "fRIOUX" "fROOH" "fRUE" "fiSMBoC" Which functions are exported depends on what was passed to "-levels". The default (no "-levels" option passed) would export: Dlog_trace Dlog_debug Dlog_info Dlog_warn Dlog_error Dlog_fatal Note: "Dlog_fatal" does not call "die" for you, see "EXCEPTIONS AND ERROR HANDLING" Dslog_$level Mostly the same as "Dlog_$level", but expects a string as first argument, not a block. Arguments are passed through just the same, but since it's just a string, no interpolation point can be used, instead the Dumper output is appended. my @nicks = Dslog_debug "names: ", map $_->value, $frew->names->all; DlogS_$level Import Tag: ":dlog" Arguments: "CodeRef $returning_message, Item $arg" Like "logS_$level", these functions are a special case of "Dlog_$level". They only take a single scalar after the $returning_message instead of slurping up (and also setting "wantarray") all the @args my $pals_rs = DlogS_debug { "pals resultset: $_" } $schema->resultset('Pals')->search({ perlers => 1 }); DslogS_$level Mostly the same as "DlogS_$level", but expects a string as first argument, not a block. Arguments are passed through just the same, but since it's just a string, no interpolation point can be used, instead the Dumper output is appended. my $pals_rs = DslogS_debug "pals resultset: ", $schema->resultset('Pals')->search({ perlers => 1 }); LOGGER CODEREF Anywhere a logger object can be passed, a coderef is accepted. This is so that the user can use different logger objects based on runtime information. The logger coderef is passed the package of the caller, and the caller level the coderef needs to use if it wants more caller information. The latter is in a hashref to allow for more options in the future. Here is a basic example of a logger that exploits "caller" to reproduce the output of "warn" with a logger: my @caller_info; my $var_log = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { chomp($_[0]); warn "$_[0] at $caller_info[1] line $caller_info[2].\n" } }); my $warn_faker = sub { my ($package, $args) = @_; @caller_info = caller($args->{caller_level}); $var_log }; set_logger($warn_faker); log_debug { 'test' }; The following is an example that uses the information passed to the logger coderef. It sets the global logger to $l3, the logger for the "A1" package to $l1, except the "lol" method in "A1" which uses the $l2 logger and lastly the logger for the "A2" package to $l2. Note that it increases the caller level as it dispatches based on where the caller of the log function, not the log function itself. my $complex_dispatcher = do { my $l1 = ...; my $l2 = ...; my $l3 = ...; my %registry = ( -logger => $l3, A1 => { -logger => $l1, lol => $l2, }, A2 => { -logger => $l2 }, ); sub { my ( $package, $info ) = @_; my $logger = $registry{'-logger'}; if (my $r = $registry{$package}) { $logger = $r->{'-logger'} if $r->{'-logger'}; my (undef, undef, undef, $sub) = caller($info->{caller_level} + 1); $sub =~ s/^\Q$package\E:://g; $logger = $r->{$sub} if $r->{$sub}; } return $logger; } }; set_logger $complex_dispatcher; LOGGER INTERFACE Because this module is ultimately pretty looking glue (glittery?) with the awesome benefit of the Contextual part, users will often want to make their favorite logger work with it. The following are the methods that should be implemented in the logger: is_trace is_debug is_info is_warn is_error is_fatal trace debug info warn error fatal The first six merely need to return true if that level is enabled. The latter six take the results of whatever the user returned from their coderef and log them. For a basic example see Log::Contextual::SimpleLogger. LOG ROUTING In between the loggers and the log functions is a log router that is responsible for finding a logger to handle the log event and passing the log information to the logger. This relationship is described in the documentation for "Log::Contextual::Role::Router". "Log::Contextual" and packages that extend it will by default share a router singleton that implements the with_logger() and set_logger() functions and also respects the -logger, -package_logger, and -default_logger import options with their associated default value functions. The router singleton is available as the return value of the router() function. Users of Log::Contextual may overload router() to return instances of custom log routers that could for example work with loggers that use a different interface. EXCEPTIONS AND ERROR HANDLING "Log::Contextual", by design, does not intentionally invoke "die" on your behalf(*see footnote*) for "log_fatal". Logging events are characterized as information, not flow control, and conflating the two results in negative design anti-patterns. As such, "log_fatal" would at be better used to communicate information about a *future* failure, for example: if ( condition ) { log_fatal { "Bad Condition is true" }; die My::Exception->new(); } This has a number of benefits: * You're more likely to want to use useful Exception Objects and flow control instead of cheating with log messages. * You're less likely to run a risk of losing what the actual problem was when some error occurs in your creation of the Exception Object * You're less likely to run the risk of losing important log context due to exceptions occurring mid way through "die" unwinding and "exit" global destruction. If you're still too lazy to use exceptions, then you can do what you probably want as follows: if ( ... ) { log_fatal { "Bad condition is true" }; die "Bad condtion is true"; } Or for ":dlog" style: use Data::Dumper::Consise qw( Dumper ); if ( ... ) { # Dlog_fatal but not my $reason = "Bad condtion is true because: " . Dumper($thing); log_fatal { $reason }; die $reason; } footnote The underlying behaviour of "log_fatal" is dependent on the backing library. All the Loggers shipping with "Log::Contextual" behave this way, as do many of the supported loggers, like "Log::Log4perl". However, not all loggers work this way, and one must be careful. "Log::Dispatch" doesn't support implementing "log_fatal" at all "Log::Dispatchouli" implements "log_fatal" using "die" ( via Carp ) CONTRIBUTORS kentnl - Kent Fredric triddle - Tyler Riddle voj - Jakob Voß DESIGNER mst - Matt S. Trout AUTHOR Arthur Axel "fREW" Schmidt COPYRIGHT AND LICENSE This software is copyright (c) 2018 by Arthur Axel "fREW" Schmidt. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Changes100644001750001750 1026213230423621 15271 0ustar00frewfrew000000000000Log-Contextual-0.008001Revision history for Log-Contextual 0.008001 2018-01-19 09:14:55-08:00 America/Los_Angeles - Ensure new slog functions are exportable (Thanks Dan Book!) 0.008000 2017-11-24 08:40:15-08:00 America/Los_Angeles - Add slog for logging strings without a code block (Thanks Christian Walde!) - Fix exporting into classes that subclass from users of Log::Contextual. (Thanks Graham Knop!) 0.007001 2017-05-21 07:49:18-07:00 America/Los_Angeles - Stop testing exact bytes produced by Data::Dumper::Concise (Thanks for reporting Errietta Kostal) (Fixes GH#11) - Add some documentation about exceptions (Thanks Kent Fredric!) 0.007000 2016-04-11 21:35:41-07:00 America/Los_Angeles - Add `has_logger` predicate to avoid setting logger twice (Thanks Wes Malone! Thwes!) 0.006005 2015-03-14 12:54:46-05:00 America/Chicago - Fix performance (and arguably duplicate side effects!) in multilogger setups (Good catch and fix Christian Walde!) - Fix warning introduced in 5.21.x 0.006004 2014-07-15 21:50:41-05:00 America/Chicago - Various POD fixes (Karent Etheridge, Florian Schlichting) 0.006003 2014-02-22 09:41:29CST-0600 America/Chicago - Stop depending on XS module Sub::Identify 0.006002 2014-02-20 16:05:20CST-0600 America/Chicago - Fix missing POD 0.006001 2014-02-20 15:51:29CST-0600 America/Chicago - Fix warnings caused by importing more than once 0.006000 2013-09-05 - Add Log::Contextual::Easy::Default for simple LC usage (Jakob Voß) - Add Log::Contextual::Easy::Package for more different simple LC usage 0.005005 2013-08-08 - Fix minimum version of Exporter::Declare 0.005004 2013-08-08 - Dep on a newer version of Moo for multiple role composition 0.005003 2013-03-21 - Yell loudly if a user tries to use Log::Contextual::set_logger() or Log::Contextual::with_logger() (aka internals that don't work anymore) directly 0.005002 2013-02-14 (♥) - Fix RT#83267 (Tyler Riddle) 0.005001 2013-02-07 - No changes from previous dev release 0.005000_03 2013-01-16 - merge unpushed 0.004300 into master (frew--, Tyler Riddle++) 0.005000_02 2013-01-15 - add missing changelog entry (derp) 0.005000_01 2013-01-11 - significant changes in the way Log::Contexual works, but the upshot of it is that Log::Contextual is now much less global than before, and applications using Log::Contextual can guard against modules using set_logger (or something like that) and changing their logger. See the new Log::Contextual::Role::Router for more information 0.004300 2012-10-03 - add a way to set default import tags 0.004202 2012-08-04 - correct the caller_level passed into coderef, and document "both" uses of caller_level 0.004201 2012-07-21 - The smallest pod fix ever 0.004200 2012-07-20 - Improve information passed to logger coderef - Significant doc improvements - Fix warning in test suite in Perl 5.16 0.004100 2012-03-29 - Log::Contextual::WarnLogger now supports customized log levels via the 'levels' constructor argument (Karen Etheridge) 0.004001 2011-08-15 - Fix version of Exporter::Declare that we dep on 0.004000 2011-08-06 - Support Log::Contextual subclasses for default import options - Allow custom log levels 0.00305 2011-07-27 - Fix regression that caused D* subs to dumper even if the log level was off 0.00304 2010-07-31 - Add $package_UPTO environment variable for WarnLogger 0.00303 2010-07-10 - Fix broken Log::Log4perl test 0.00302 2010-07-08 - Add Log::Contextual::TeeLogger - Add levels_upto (RT58558) - Use Log::Log4perl 1.29 to clean up caller stuff 0.00301 2010-07-08 [deleted due to missing the TeeLogger] 0.00300 2010-06-03 - Add -package_logger import option 0.00202 2010-05-23 - Fix a bug that caused Dlog and friends not to work with a default 0.00201 2010-03-04 - I left a needed file for testing out of the MANIFEST; fixing :-/ 0.00200 2010-03-03 - add example for Log::Dispatchouli since it works nicely now - make Log::Log4perl work out of the box - Added WarnLogger for libraries - Warn if set_logger is called more than once - Fix tiny POD errors 0.00101 2010-02-21 - Fix tests to not need use lib (incorrect test failures) 0.00100 2010-02-20 - initial release arg.t100644001750001750 161413230423621 15160 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Log::Contextual::SimpleLogger; use Test::More 'no_plan'; my $var_log; my $var; my @levels = qw(debug trace warn info error fatal); BEGIN { $var_log = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { $var = shift } }) } use Log::Contextual qw{ :log :dlog}, -logger => $var_log; my @args = qw(fizz buzz fizzbuzz); for my $level (@levels) { for my $prefix (qw(log logS Dlog DlogS)) { my $original = local $_ = "don't tread on me"; my $method_name = "${prefix}_${level}"; my $ref = __PACKAGE__->can($method_name) or die "no ref found for method $method_name"; $ref->(sub { "$method_name" }, @args); ok($_ eq $original, "\$_ was not disturbed by $method_name"); ok($var eq "[$level] $method_name\n", "log argument was correct"); } } log.t100644001750001750 526113230423621 15172 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Log::Contextual qw{:log with_logger set_logger}; use Log::Contextual::SimpleLogger; use Test::More qw(no_plan); my @levels = qw(debug trace warn info error fatal); my $var1; my $var2; my $var3; my $var_logger1 = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { $var1 = shift }, }); my $var_logger2 = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { $var2 = shift }, }); my $var_logger3 = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { $var3 = shift }, }); SETLOGGER: { set_logger(sub { $var_logger3 }); log_debug { 'set_logger' }; is($var3, "[debug] set_logger\n", 'set logger works'); } SETLOGGERTWICE: { my $foo; local $SIG{__WARN__} = sub { $foo = shift }; set_logger(sub { $var_logger3 }); like( $foo, qr/set_logger \(or -logger\) called more than once! This is a bad idea! at/, 'set_logger twice warns correctly' ); } WITHLOGGER: { with_logger sub { $var_logger2 } => sub { with_logger $var_logger1 => sub { log_debug { 'nothing!' } }; log_debug { 'frew!' }; }; is($var1, "[debug] nothing!\n", 'inner scoped logger works'); is($var2, "[debug] frew!\n", 'outer scoped logger works'); } SETWITHLOGGER: { with_logger $var_logger1 => sub { log_debug { 'nothing again!' }; # do this just so the following set_logger won't warn local $SIG{__WARN__} = sub { }; set_logger(sub { $var_logger3 }); log_debug { 'this is a set inside a with' }; }; is( $var1, "[debug] nothing again!\n", 'inner scoped logger works after using set_logger' ); is($var3, "[debug] this is a set inside a with\n", 'set inside with works'); log_debug { 'frioux!' }; is( $var3, "[debug] frioux!\n", q{set_logger's logger comes back after scoped logger} ); } VANILLA: { for (@levels) { main->can("log_$_")->(sub { 'fiSMBoC' }); is($var3, "[$_] fiSMBoC\n", "$_ works"); my @vars = main->can("log_$_")->(sub { 'fiSMBoC: ' . $_[1] }, qw{foo bar baz}); is($var3, "[$_] fiSMBoC: bar\n", "log_$_ works with input"); ok( eq_array(\@vars, [qw{foo bar baz}]), "log_$_ passes data through correctly" ); my $val = main->can("logS_$_")->(sub { 'fiSMBoC: ' . $_[0] }, 'foo'); is($var3, "[$_] fiSMBoC: foo\n", "logS_$_ works with input"); is($val, 'foo', "logS_$_ passes data through correctly"); } } ok(!eval { Log::Contextual->import; 1 }, 'Blank Log::Contextual import dies'); LICENSE100644001750001750 4372713230423621 15017 0ustar00frewfrew000000000000Log-Contextual-0.008001This software is copyright (c) 2018 by Arthur Axel "fREW" Schmidt. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- This software is Copyright (c) 2018 by Arthur Axel "fREW" Schmidt. This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! --- The Artistic License 1.0 --- This software is Copyright (c) 2018 by Arthur Axel "fREW" Schmidt. This is free software, licensed under: The Artistic License 1.0 The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: - "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. - "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. - "Copyright Holder" is whoever is named in the copyright or copyrights for the package. - "You" is you, if you're thinking about copying or distributing this Package. - "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) - "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End cpanfile100644001750001750 31513230423621 15440 0ustar00frewfrew000000000000Log-Contextual-0.008001requires 'Data::Dumper::Concise' => 0; requires 'Exporter::Declare' => 0.111; requires 'Carp' => 0; requires 'Scalar::Util' => 0; requires 'Moo' => 1.003000; on test => sub { requires 'Test::Fatal'; } dist.ini100644001750001750 60013230423621 15375 0ustar00frewfrew000000000000Log-Contextual-0.008001name = Log-Contextual author = Arthur Axel "fREW" Schmidt license = Perl_5 copyright_holder = Arthur Axel "fREW" Schmidt version = 0.008001 [NextRelease] [@Git] [@Filter] -bundle = @Basic -remove = Readme [GithubMeta] issues = 1 [MetaJSON] [PodWeaver] [PkgVersion] [Pod2Readme] [PodSyntaxTests] [Prereqs::FromCPANfile] dlog.t100644001750001750 355613230423621 15343 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Log::Contextual::SimpleLogger; use Test::More 'no_plan'; my $var_log; my $var; my @levels = qw(debug trace warn info error fatal); BEGIN { $var_log = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { $var = shift } }) } use Log::Contextual qw{:dlog}, -logger => $var_log; for my $level (@levels) { my @foo = main->can("Dlog_$level")->(sub { "Look ma, data: $_" }, qw{frew bar baz}); ok( eq_array(\@foo, [qw{frew bar baz}]), "Dlog_$level passes data through correctly" ); is( $var, qq([$level] Look ma, data: "frew"\n"bar"\n"baz"\n), "Output for Dlog_$level is correct" ); my @sfoo = main->can("Dslog_$level")->("Look ma, data: ", qw{frew bar baz}); ok( eq_array(\@sfoo, [qw{frew bar baz}]), "Dslog_$level passes data through correctly" ); is( $var, qq([$level] Look ma, data: "frew"\n"bar"\n"baz"\n), "Output for Dslog_$level is correct" ); my $bar = main->can("DlogS_$level") ->(sub { "Look ma, data: $_" }, [qw{frew bar baz}]); ok( eq_array($bar, [qw{frew bar baz}]), 'DlogS_trace passes data through correctly' ); like( $var, qr(\[$level\] Look ma, data: \[), "Output for DlogS_$level is correct" ); @foo = main->can("Dlog_$level")->(sub { "nothing: $_" }, ()); ok(eq_array(\@foo, []), "Dlog_$level passes nothing through correctly"); is($var, "[$level] nothing: ()\n", "Output for Dlog_$level is correct"); my $sbar = main->can("DslogS_$level")->("Look ma, data: ", [qw{frew bar baz}]); ok( eq_array($sbar, [qw{frew bar baz}]), 'DslogS_trace passes data through correctly' ); like( $var, qr(\[$level\] Look ma, data: \[), "Output for DslogS_$level is correct" ); } easy.t100644001750001750 325513230423621 15353 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Test::More; use lib 't/lib'; use My::Module; # makes use of Log::Contextual::Easy::Default; use My::Module2; # makes use of Log::Contextual::Easy::Package; # capture logging messages of My::Module, mapping "[...] xxx" to "...$sep" sub logshort($$) { my ($cap, $sep) = @_; sub { local $_ = shift; s/^\[(.+)\] (xxx|"xxx")\n$/$1$sep/; $$cap .= $_; } } # capture warnings my ($cap_warn, $cap_with, $cap_set); local $SIG{__WARN__} = logshort \$cap_warn, '!'; { My::Module::log(); My::Module2::log(); is($cap_warn, undef, 'no logging by default'); } { local $ENV{MY_MODULE_UPTO} = 'info'; local $ENV{MY_MODULE2_UPTO} = 'info'; My::Module::log(); My::Module2::log(); is( $cap_warn, "info!warn!error!fatal!info!warn!error!fatal!", 'WarnLogger enabled via ENV' ); $cap_warn = ''; } { use Log::Contextual::SimpleLogger; use Log::Contextual qw(with_logger set_logger); set_logger( Log::Contextual::SimpleLogger->new({ levels => [qw(info warn error)], coderef => logshort \$cap_set, '/' })); my $with_logger = Log::Contextual::SimpleLogger->new({ levels => [qw(trace info fatal)], coderef => logshort \$cap_with, '|' }); with_logger $with_logger => sub { My::Module::log(); My::Module2::log(); # will not be overridden }; is($cap_with, 'trace|info|fatal|', 'with_logger'); My::Module::log(); My::Module2::log(); # will not be overridden is($cap_set, 'info/warn/error/', 'set_logger'); is($cap_warn, '', 'no warnings if with_logger or set_logger'); } done_testing; base.t100644001750001750 302213230423621 15314 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use lib 't/lib'; use BaseLogger qw{:log with_logger set_logger}; use Test::More qw(no_plan); my @levels = qw(lol wut zomg); VANILLA: { for (@levels) { main->can("log_$_")->(sub { 'fiSMBoC' }); is($DumbLogger2::var, "[$_] fiSMBoC\n", "$_ works"); main->can("slog_$_")->('fiSMBoC'); is($DumbLogger2::var, "[$_] fiSMBoC\n", "string $_ works"); main->can("slog_$_")->('0'); is($DumbLogger2::var, "[$_] 0\n", "false string $_ works"); my @vars = main->can("log_$_")->(sub { 'fiSMBoC: ' . $_[1] }, qw{foo bar baz}); is($DumbLogger2::var, "[$_] fiSMBoC: bar\n", "log_$_ works with input"); ok( eq_array(\@vars, [qw{foo bar baz}]), "log_$_ passes data through correctly" ); my @svars = main->can("slog_$_")->('fiSMBoC', qw{foo bar baz}); is($DumbLogger2::var, "[$_] fiSMBoC\n", "slog_$_ ignores input"); ok( eq_array(\@svars, [qw{foo bar baz}]), "slog_$_ passes data through correctly" ); my $val = main->can("logS_$_")->(sub { 'fiSMBoC: ' . $_[0] }, 'foo'); is($DumbLogger2::var, "[$_] fiSMBoC: foo\n", "logS_$_ works with input"); is($val, 'foo', "logS_$_ passes data through correctly"); my $sval = main->can("slogS_$_")->('fiSMBoC', 'foo'); is($DumbLogger2::var, "[$_] fiSMBoC\n", "slogS_$_ ignores input"); is($val, 'foo', "slogS_$_ passes data through correctly"); } } ok(!eval { Log::Contextual->import; 1 }, 'Blank Log::Contextual import dies'); META.yml100644001750001750 144713230423621 15234 0ustar00frewfrew000000000000Log-Contextual-0.008001--- abstract: 'Simple logging interface with a contextual log' author: - 'Arthur Axel "fREW" Schmidt ' build_requires: Test::Fatal: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 0 generated_by: 'Dist::Zilla version 6.010, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Log-Contextual requires: Carp: '0' Data::Dumper::Concise: '0' Exporter::Declare: '0.111' Moo: '1.003' Scalar::Util: '0' resources: bugtracker: https://github.com/frioux/Log-Contextual/issues homepage: https://github.com/frioux/Log-Contextual repository: https://github.com/frioux/Log-Contextual.git version: '0.008001' x_serialization_backend: 'YAML::Tiny version 1.70' MANIFEST100644001750001750 202213230423621 15102 0ustar00frewfrew000000000000Log-Contextual-0.008001# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.010. CONTRIBUTING Changes LICENSE MANIFEST META.json META.yml Makefile.PL README cpanfile dist.ini lib/Log/Contextual.pm lib/Log/Contextual/Easy/Default.pm lib/Log/Contextual/Easy/Package.pm lib/Log/Contextual/Role/Router.pm lib/Log/Contextual/Role/Router/HasLogger.pm lib/Log/Contextual/Role/Router/SetLogger.pm lib/Log/Contextual/Role/Router/WithLogger.pm lib/Log/Contextual/Router.pm lib/Log/Contextual/SimpleLogger.pm lib/Log/Contextual/TeeLogger.pm lib/Log/Contextual/WarnLogger.pm t/arg.t t/author-pod-syntax.t t/base.t t/caller.t t/default_import.t t/default_logger.t t/dlog.t t/easy.t t/eg.t t/has_logger.t t/inherit.t t/lib/BaseLogger.pm t/lib/DefaultImportLogger.pm t/lib/My/Module.pm t/lib/My/Module2.pm t/lib/TestExporter.pm t/lib/TestRouter.pm t/log-with-levels.t t/log.t t/log4perl.conf t/log4perl.t t/package_logger.t t/perltidy.t t/router_api.t t/rt83267-begin.t t/rt83267.t t/simplelogger.t t/warnlogger-with-levels.t t/warnlogger.t t/yell-loudly.t META.json100644001750001750 272613230423621 15405 0ustar00frewfrew000000000000Log-Contextual-0.008001{ "abstract" : "Simple logging interface with a contextual log", "author" : [ "Arthur Axel \"fREW\" Schmidt " ], "dynamic_config" : 0, "generated_by" : "Dist::Zilla version 6.010, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Log-Contextual", "prereqs" : { "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "develop" : { "requires" : { "Test::Pod" : "1.41" } }, "runtime" : { "requires" : { "Carp" : "0", "Data::Dumper::Concise" : "0", "Exporter::Declare" : "0.111", "Moo" : "1.003", "Scalar::Util" : "0" } }, "test" : { "requires" : { "Test::Fatal" : "0" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/frioux/Log-Contextual/issues" }, "homepage" : "https://github.com/frioux/Log-Contextual", "repository" : { "type" : "git", "url" : "https://github.com/frioux/Log-Contextual.git", "web" : "https://github.com/frioux/Log-Contextual" } }, "version" : "0.008001", "x_serialization_backend" : "Cpanel::JSON::XS version 3.0239" } caller.t100644001750001750 213213230423621 15645 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Log::Contextual::SimpleLogger; use Test::More qw(no_plan); use Log::Contextual qw(:log set_logger); my $var; my @caller_info; my $var_log = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { chomp($_[0]); $var = "$_[0] at $caller_info[1] line $caller_info[2].\n" } }); my $warn_faker = sub { my ($package, $args) = @_; @caller_info = caller($args->{caller_level}); $var_log }; set_logger($warn_faker); log_debug { 'test log_debug' }; is($var, "[debug] test log_debug at " . __FILE__ . " line " . (__LINE__- 2) . ".\n", 'fake warn'); logS_debug { 'test logS_debug' }; is( $var, "[debug] test logS_debug at " . __FILE__ . " line " . (__LINE__- 3) . ".\n", 'fake warn' ); logS_debug { 'test Dlog_debug' }; is( $var, "[debug] test Dlog_debug at " . __FILE__ . " line " . (__LINE__- 3) . ".\n", 'fake warn' ); logS_debug { 'test DlogS_debug' }; is( $var, "[debug] test DlogS_debug at " . __FILE__ . " line " . (__LINE__- 3) . ".\n", 'fake warn' ); rt83267.t100644001750001750 65513230423621 15432 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Test::More 'no_plan'; #bug report does not include a case where Log::Contextual is #brought in via 'use' #try to import a single log function but do not include any tags BEGIN { require Log::Contextual; Log::Contextual->import('log_info'); } eval { log_info { "test" }; }; like( $@, qr/^ no logger set! you can't try to log something without a logger!/, 'Got correct error' ); inherit.t100644001750001750 120613230423621 16046 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Test::More; use Test::Fatal; use Log::Contextual qw(set_logger); use Log::Contextual::SimpleLogger; BEGIN { package MySuperClass; use Log::Contextual qw(:log); } BEGIN { package MyChildClass; BEGIN { our @ISA = qw(MySuperClass) }; use Log::Contextual qw(:log); sub do_thing { log_error { "child class log" }; } } my $last_log; set_logger(Log::Contextual::SimpleLogger->new({ levels => [qw(error)], coderef => sub { $last_log = shift }, })); is exception { MyChildClass->do_thing; }, undef, 'log imports work in child class with exports in parent'; done_testing; Makefile.PL100644001750001750 234013230423621 15726 0ustar00frewfrew000000000000Log-Contextual-0.008001# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v6.010. use strict; use warnings; use ExtUtils::MakeMaker; my %WriteMakefileArgs = ( "ABSTRACT" => "Simple logging interface with a contextual log", "AUTHOR" => "Arthur Axel \"fREW\" Schmidt ", "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => 0 }, "DISTNAME" => "Log-Contextual", "LICENSE" => "perl", "NAME" => "Log::Contextual", "PREREQ_PM" => { "Carp" => 0, "Data::Dumper::Concise" => 0, "Exporter::Declare" => "0.111", "Moo" => "1.003", "Scalar::Util" => 0 }, "TEST_REQUIRES" => { "Test::Fatal" => 0 }, "VERSION" => "0.008001", "test" => { "TESTS" => "t/*.t" } ); my %FallbackPrereqs = ( "Carp" => 0, "Data::Dumper::Concise" => 0, "Exporter::Declare" => "0.111", "Moo" => "1.003", "Scalar::Util" => 0, "Test::Fatal" => 0 ); unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); CONTRIBUTING100644001750001750 14013230423621 15562 0ustar00frewfrew000000000000Log-Contextual-0.008001Before submitting patches please run perltidy with the .perltidyrc included in this repository. log4perl.t100644001750001750 160013230423621 16132 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Test::More; if ( eval <<'EOE' require Log::Log4perl; die if $Log::Log4perl::VERSION < 1.29; 1 EOE ) { plan tests => 2; } else { plan skip_all => 'Log::Log4perl 1.29 not installed' } use FindBin; unlink 'myerrs.log' if -e 'myerrs.log'; Log::Log4perl->init("$FindBin::Bin/log4perl.conf"); use Log::Contextual qw( :log set_logger ); set_logger(Log::Log4perl->get_logger); my @elines; push @elines, __LINE__ and log_error { 'err FIRST' }; sub foo { push @elines, __LINE__ and log_error { 'err SECOND' }; } foo(); open my $log, '<', 'myerrs.log'; my @datas = <$log>; close $log; is $datas[0], "file:t/log4perl.t line:$elines[0] method:main:: - err FIRST\n", 'file and line work with Log4perl'; is $datas[1], "file:t/log4perl.t line:$elines[1] method:main::foo - err SECOND\n", 'file and line work with Log4perl in a sub'; unlink 'myerrs.log'; perltidy.t100644001750001750 45513230423621 16225 0ustar00frewfrew000000000000Log-Contextual-0.008001/t#!perl use strict; use warnings; use Test::More; plan skip_all => 'Set TIDY_TESTING if you want to run this test' unless $ENV{TIDY_TESTING}; require Test::PerlTidy; Test::PerlTidy::run_tests( path => '.', perltidyrc => '.perltidyrc', exclude => ['.build/'], ); done_testing; router_api.t100644001750001750 251613230423621 16562 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Test::More; use lib 't/lib'; use TestExporter qw(:log), -logger => 'logger value', -default_logger => 'default logger value', -package_logger => 'package logger value'; my @test_args = qw( some argument values ); log_info { "Ignored value" } @test_args; my $results = TestExporter->router->captured; my %export_info = ( exporter => 'TestExporter', target => 'main', arguments => { logger => 'logger value', default_logger => 'default logger value', package_logger => 'package logger value' }, ); my %message_info = ( exporter => 'TestExporter', caller_package => 'main', caller_level => 1, message_level => 'info', message_args => \@test_args, ); is_deeply($results->{before_import}, \%export_info, 'before_import() values are correct'); is_deeply($results->{after_import}, \%export_info, 'after_import() values are correct'); #can't really compare the sub ref value so make sure it exists and is the right type #and remove it for the later result check my $message_block = delete $results->{message}->{message_sub}; is(ref $message_block, 'CODE', 'handle_log_request() got a sub ref for the message generator'); is_deeply($results->{message}, \%message_info, 'handle_log_request() other values are correct'); done_testing; warnlogger.t100644001750001750 636413230423621 16565 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Log::Contextual::WarnLogger; use Log::Contextual qw{:log set_logger} => -logger => Log::Contextual::WarnLogger->new({env_prefix => 'FOO'}); use Test::More qw(no_plan); my $l = Log::Contextual::WarnLogger->new({env_prefix => 'BAR'}); { local $ENV{BAR_TRACE} = 0; local $ENV{BAR_DEBUG} = 1; local $ENV{BAR_INFO} = 0; local $ENV{BAR_WARN} = 0; local $ENV{BAR_ERROR} = 0; local $ENV{BAR_FATAL} = 0; ok(!$l->is_trace, 'is_trace is false on WarnLogger'); ok($l->is_debug, 'is_debug is true on WarnLogger'); ok(!$l->is_info, 'is_info is false on WarnLogger'); ok(!$l->is_warn, 'is_warn is false on WarnLogger'); ok(!$l->is_error, 'is_error is false on WarnLogger'); ok(!$l->is_fatal, 'is_fatal is false on WarnLogger'); } { local $ENV{BAR_UPTO} = 'TRACE'; ok($l->is_trace, 'is_trace is true on WarnLogger'); ok($l->is_debug, 'is_debug is true on WarnLogger'); ok($l->is_info, 'is_info is true on WarnLogger'); ok($l->is_warn, 'is_warn is true on WarnLogger'); ok($l->is_error, 'is_error is true on WarnLogger'); ok($l->is_fatal, 'is_fatal is true on WarnLogger'); } { local $ENV{BAR_UPTO} = 'warn'; ok(!$l->is_trace, 'is_trace is false on WarnLogger'); ok(!$l->is_debug, 'is_debug is false on WarnLogger'); ok(!$l->is_info, 'is_info is false on WarnLogger'); ok($l->is_warn, 'is_warn is true on WarnLogger'); ok($l->is_error, 'is_error is true on WarnLogger'); ok($l->is_fatal, 'is_fatal is true on WarnLogger'); } { local $ENV{FOO_TRACE} = 0; local $ENV{FOO_DEBUG} = 1; local $ENV{FOO_INFO} = 0; local $ENV{FOO_WARN} = 0; local $ENV{FOO_ERROR} = 0; local $ENV{FOO_FATAL} = 0; ok( eval { log_trace { die 'this should live' }; 1 }, 'trace does not get called' ); ok( !eval { log_debug { die 'this should die' }; 1 }, 'debug gets called' ); ok( eval { log_info { die 'this should live' }; 1 }, 'info does not get called' ); ok( eval { log_warn { die 'this should live' }; 1 }, 'warn does not get called' ); ok( eval { log_error { die 'this should live' }; 1 }, 'error does not get called' ); ok( eval { log_fatal { die 'this should live' }; 1 }, 'fatal does not get called' ); } { local $ENV{FOO_TRACE} = 1; local $ENV{FOO_DEBUG} = 1; local $ENV{FOO_INFO} = 1; local $ENV{FOO_WARN} = 1; local $ENV{FOO_ERROR} = 1; local $ENV{FOO_FATAL} = 1; my $cap; local $SIG{__WARN__} = sub { $cap = shift }; log_debug { 'frew' }; is($cap, "[debug] frew\n", 'WarnLogger outputs to STDERR correctly'); log_trace { 'trace' }; is($cap, "[trace] trace\n", 'trace renders correctly'); log_debug { 'debug' }; is($cap, "[debug] debug\n", 'debug renders correctly'); log_info { 'info' }; is($cap, "[info] info\n", 'info renders correctly'); log_warn { 'warn' }; is($cap, "[warn] warn\n", 'warn renders correctly'); log_error { 'error' }; is($cap, "[error] error\n", 'error renders correctly'); log_fatal { 'fatal' }; is($cap, "[fatal] fatal\n", 'fatal renders correctly'); } has_logger.t100644001750001750 51313230423621 16476 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Log::Contextual::SimpleLogger; use Test::More; use Log::Contextual qw(:log set_logger has_logger); my $log = Log::Contextual::SimpleLogger->new; ok(!has_logger, 'has_logger returns false when logger unset'); set_logger $log; ok(has_logger, 'has_logger returns true when logger set'); done_testing; log4perl.conf100644001750001750 100313230423621 16611 0ustar00frewfrew000000000000Log-Contextual-0.008001/t############################################################ # A simple root logger with a Log::Log4perl::Appender::File # file appender in Perl. ############################################################ log4perl.rootLogger=ERROR, LOGFILE log4perl.appender.LOGFILE=Log::Log4perl::Appender::File log4perl.appender.LOGFILE.filename=myerrs.log log4perl.appender.LOGFILE.mode=append log4perl.appender.LOGFILE.layout=PatternLayout log4perl.appender.LOGFILE.layout.ConversionPattern=file:%F line:%L method:%M - %m%n yell-loudly.t100644001750001750 65213230423621 16643 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Test::More tests => 2; use Test::Fatal; use Log::Contextual qw(:log); like( exception { Log::Contextual::set_logger() }, qr/set_logger is no longer a direct sub in Log::Contextual/, 'Log::Contextual::set_logger dies', ); like( exception { Log::Contextual::with_logger() }, qr/with_logger is no longer a direct sub in Log::Contextual/, 'Log::Contextual::with_logger dies', ); simplelogger.t100644001750001750 540413230423621 17101 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use File::Temp; use Log::Contextual::SimpleLogger; use Log::Contextual qw{:log set_logger} => -logger => Log::Contextual::SimpleLogger->new({levels => [qw{debug}]}); use Test::More qw(no_plan); my $l = Log::Contextual::SimpleLogger->new({levels => [qw{debug}]}); ok(!$l->is_trace, 'is_trace is false on SimpleLogger'); ok($l->is_debug, 'is_debug is true on SimpleLogger'); ok(!$l->is_info, 'is_info is false on SimpleLogger'); ok(!$l->is_warn, 'is_warn is false on SimpleLogger'); ok(!$l->is_error, 'is_error is false on SimpleLogger'); ok(!$l->is_fatal, 'is_fatal is false on SimpleLogger'); ok( eval { log_trace { die 'this should live' }; 1 }, 'trace does not get called' ); ok( !eval { log_debug { die 'this should die' }; 1 }, 'debug gets called' ); ok( eval { log_info { die 'this should live' }; 1 }, 'info does not get called' ); ok( eval { log_warn { die 'this should live' }; 1 }, 'warn does not get called' ); ok( eval { log_error { die 'this should live' }; 1 }, 'error does not get called' ); ok( eval { log_fatal { die 'this should live' }; 1 }, 'fatal does not get called' ); { my $tempfile = File::Temp->new(UNLINK => 1, TEMPLATE => 'stderrXXXXXX'); my $fn = fileno($tempfile); open(STDERR, ">&$fn") or die $!; log_debug { 'frew' }; my $out = do { local @ARGV = $tempfile; <> }; is($out, "[debug] frew\n", 'SimpleLogger outputs to STDERR correctly'); } my $response; my $l2 = Log::Contextual::SimpleLogger->new({ levels => [qw{trace debug info warn error fatal}], coderef => sub { $response = $_[0] }, }); { local $SIG{__WARN__} = sub { }; # do this just to hide warning for tests set_logger($l2); } log_trace { 'trace' }; is($response, "[trace] trace\n", 'trace renders correctly'); log_debug { 'debug' }; is($response, "[debug] debug\n", 'debug renders correctly'); log_info { 'info' }; is($response, "[info] info\n", 'info renders correctly'); log_warn { 'warn' }; is($response, "[warn] warn\n", 'warn renders correctly'); log_error { 'error' }; is($response, "[error] error\n", 'error renders correctly'); log_fatal { 'fatal' }; is($response, "[fatal] fatal\n", 'fatal renders correctly'); log_debug {'line 1', 'line 2'}; is($response, "[debug] line 1\nline 2\n", 'multiline log renders correctly'); my $u = Log::Contextual::SimpleLogger->new({levels_upto => 'debug'}); ok(!$u->is_trace, 'is_trace is false on SimpleLogger'); ok($u->is_debug, 'is_debug is true on SimpleLogger'); ok($u->is_info, 'is_info is true on SimpleLogger'); ok($u->is_warn, 'is_warn is true on SimpleLogger'); ok($u->is_error, 'is_error is true on SimpleLogger'); ok($u->is_fatal, 'is_fatal is true on SimpleLogger'); rt83267-begin.t100644001750001750 74513230423621 16514 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse Test::More qw(no_plan); BEGIN { eval { package NotMain; use strict; use warnings; use Test::More; use Log::Contextual::SimpleLogger; use Log::Contextual qw(:log), -default_logger => Log::Contextual::SimpleLogger->new({levels => [qw( )]}); eval { log_info { "Yep" } }; is($@, '', 'Invoked log function in package other than main'); }; is($@, '', 'non-main package subtest did not die'); } package_logger.t100644001750001750 300313230423621 17333 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Log::Contextual qw{:log with_logger set_logger}; use Log::Contextual::SimpleLogger; use Test::More qw(no_plan); my $var1; my $var2; my $var3; my $var_logger1 = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { $var1 = shift }, }); my $var_logger2; BEGIN { $var_logger2 = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { $var2 = shift }, }) } my $var_logger3; BEGIN { $var_logger3 = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { $var3 = shift }, }) } { package J; use Log::Contextual qw{:dlog :log with_logger set_logger}, -package_logger => $var_logger3; sub foo { log_debug { 'bar' }; } sub bar { Dlog_debug { "bar: $_" } 'frew'; } } { package K; use Log::Contextual qw{:log with_logger set_logger}, -package_logger => $var_logger2; sub foo { log_debug { 'foo' }; } } J::foo; K::foo; is($var2, "[debug] foo\n", 'package_logger works for one package'); is($var3, "[debug] bar\n", 'package_logger works for both packages'); J::bar; is($var3, qq([debug] bar: "frew"\n), 'package_logger works for one package'); $var2 = ''; $var1 = ''; set_logger($var_logger1); K::foo; is($var1, q(), '... and set_logger does not win'); is($var2, "[debug] foo\n", '... and package_logger still gets the value'); default_import.t100644001750001750 142013230423621 17420 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use lib 't/lib'; use DefaultImportLogger; use Test::More qw(no_plan); my @levels = qw(lol wut zomg); VANILLA: { for (@levels) { main->can("log_$_")->(sub { 'fiSMBoC' }); is($DumbLogger2::var, "[$_] fiSMBoC\n", "$_ works"); my @vars = main->can("log_$_")->(sub { 'fiSMBoC: ' . $_[1] }, qw{foo bar baz}); is($DumbLogger2::var, "[$_] fiSMBoC: bar\n", "log_$_ works with input"); ok( eq_array(\@vars, [qw{foo bar baz}]), "log_$_ passes data through correctly" ); my $val = main->can("logS_$_")->(sub { 'fiSMBoC: ' . $_[0] }, 'foo'); is($DumbLogger2::var, "[$_] fiSMBoC: foo\n", "logS_$_ works with input"); is($val, 'foo', "logS_$_ passes data through correctly"); } } default_logger.t100644001750001750 273213230423621 17374 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Log::Contextual qw{:log with_logger set_logger}; use Log::Contextual::SimpleLogger; use Test::More qw(no_plan); my $var1; my $var2; my $var3; my $var_logger1 = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { $var1 = shift }, }); my $var_logger2; BEGIN { $var_logger2 = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { $var2 = shift }, }) } my $var_logger3; BEGIN { $var_logger3 = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { $var3 = shift }, }) } { package J; use Log::Contextual qw{:dlog :log with_logger set_logger}, -default_logger => $var_logger3; sub foo { log_debug { 'bar' }; } sub bar { Dlog_debug { "bar: $_" } 'frew'; } } { package K; use Log::Contextual qw{:log with_logger set_logger}, -default_logger => $var_logger2; sub foo { log_debug { 'foo' }; } } J::foo; K::foo; is($var2, "[debug] foo\n", 'default_logger works for one package'); is($var3, "[debug] bar\n", 'default_logger works for both packages'); J::bar; is($var3, qq([debug] bar: "frew"\n), 'default_logger works for one package'); $var2 = ''; set_logger($var_logger1); K::foo; is($var2, q(), '... but set_logger wins'); is($var1, "[debug] foo\n", '... and gets the value'); My000755001750001750 013230423621 15213 5ustar00frewfrew000000000000Log-Contextual-0.008001/t/libModule.pm100644001750001750 32113230423621 17112 0ustar00frewfrew000000000000Log-Contextual-0.008001/t/lib/Mypackage My::Module; use Log::Contextual::Easy::Default; sub log { Dlog_fatal { $_ } DlogS_error { $_ } logS_warn { $_[0] } logS_info { $_[0] } log_debug { $_[0] } log_trace { $_[0] } 'xxx'; } 1; log-with-levels.t100644001750001750 336113230423621 17432 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Log::Contextual qw{:dlog :log with_logger set_logger}, -levels => ['custom']; use Log::Contextual::SimpleLogger; use Test::More qw(no_plan); my $logger = DumbLogger->new; set_logger(sub { $logger }); log_custom { 'fiSMBoC' }; is($DumbLogger::var, "fiSMBoC", "custom works"); my @vars = log_custom { 'fiSMBoC: ' . $_[1] } qw{foo bar baz}; is($DumbLogger::var, "fiSMBoC: bar", "log_custom works with input"); ok( eq_array(\@vars, [qw{foo bar baz}]), "log_custom passes data through correctly" ); my $val = logS_custom { 'fiSMBoC: ' . $_[0] } 'foo'; is($DumbLogger::var, "fiSMBoC: foo", "logS_custom works with input"); is($val, 'foo', "logS_custom passes data through correctly"); my @foo = Dlog_custom { "Look ma, data: $_" } qw{frew bar baz}; ok( eq_array(\@foo, [qw{frew bar baz}]), "Dlog_custom passes data through correctly" ); is( $DumbLogger::var, qq(Look ma, data: "frew"\n"bar"\n"baz"\n), "Output for Dlog_custom is correct" ); my $bar = DlogS_custom { "Look ma, data: $_" }[qw{frew bar baz}]; ok(eq_array($bar, [qw{frew bar baz}]), 'DlogS_custom passes data through correctly'); like( $DumbLogger::var, qr(Look ma, data: \[), "Output for DlogS_custom is correct" ); @foo = Dlog_custom { "nothing: $_" } (); ok(eq_array(\@foo, []), "Dlog_custom passes nothing through correctly"); is($DumbLogger::var, "nothing: ()", "Output for Dlog_custom is correct"); ok(!main->can($_), "$_ not imported") for map +("log_$_", "logS_$_"), qw(debug trace warn info error fatal); ok(!eval { Log::Contextual->import; 1 }, 'Blank Log::Contextual import dies'); BEGIN { package DumbLogger; our $var; sub new { bless {}, 'DumbLogger' } sub is_custom { 1 } sub custom { $var = $_[1] } 1; } lib000755001750001750 013230423621 14626 5ustar00frewfrew000000000000Log-Contextual-0.008001/tBaseLogger.pm100644001750001750 107713230423621 17343 0ustar00frewfrew000000000000Log-Contextual-0.008001/t/libpackage BaseLogger; use base 'Log::Contextual'; use Log::Contextual::SimpleLogger; my $logger = DumbLogger2->new; sub arg_levels { $_[1] || [qw(lol wut zomg)] } sub arg_logger { $_[1] || $logger } sub router { our $Router_Instance ||= do { require Log::Contextual::Router; Log::Contextual::Router->new } } package DumbLogger2; our $var; sub new { bless {}, 'DumbLogger2' } sub is_wut { 1 } sub wut { $var = "[wut] $_[1]\n" } sub is_lol { 1 } sub lol { $var = "[lol] $_[1]\n" } sub is_zomg { 1 } sub zomg { $var = "[zomg] $_[1]\n" } 1; TestRouter.pm100644001750001750 75313230423621 17431 0ustar00frewfrew000000000000Log-Contextual-0.008001/t/libpackage TestRouter; use Moo; use Log::Contextual::SimpleLogger; with 'Log::Contextual::Role::Router'; has captured => (is => 'ro', default => sub { {} }); sub before_import { my ($self, %export_info) = @_; $self->captured->{before_import} = \%export_info; } sub after_import { my ($self, %export_info) = @_; $self->captured->{after_import} = \%export_info; } sub handle_log_request { my ($self, %message_info) = @_; $self->captured->{message} = \%message_info; } 1; Module2.pm100644001750001750 32213230423621 17175 0ustar00frewfrew000000000000Log-Contextual-0.008001/t/lib/Mypackage My::Module2; use Log::Contextual::Easy::Package; sub log { Dlog_fatal { $_ } DlogS_error { $_ } logS_warn { $_[0] } logS_info { $_[0] } log_debug { $_[0] } log_trace { $_[0] } 'xxx'; } 1; Log000755001750001750 013230423621 15104 5ustar00frewfrew000000000000Log-Contextual-0.008001/libContextual.pm100644001750001750 6276513230423621 17770 0ustar00frewfrew000000000000Log-Contextual-0.008001/lib/Logpackage Log::Contextual; $Log::Contextual::VERSION = '0.008001'; # ABSTRACT: Simple logging interface with a contextual log use strict; use warnings; my @levels = qw(debug trace warn info error fatal); use Exporter::Declare; use Exporter::Declare::Export::Generator; use Data::Dumper::Concise; use Scalar::Util 'blessed'; use B qw(svref_2object); sub stash_name { my ($coderef) = @_; ref $coderef or return; my $cv = B::svref_2object($coderef); $cv->isa('B::CV') or return; # bail out if GV is undefined $cv->GV->isa('B::SPECIAL') and return; return $cv->GV->STASH->NAME; } my @dlog = ( (map "Dlog_$_", @levels), (map "DlogS_$_", @levels), (map "Dslog_$_", @levels), (map "DslogS_$_", @levels)); my @log = ( (map "log_$_", @levels), (map "logS_$_", @levels), (map "slog_$_", @levels), (map "slogS_$_", @levels)); sub _maybe_export { my ($spec, $target, $name, $new_code) = @_; no strict 'refs'; if (defined &{"${target}::${name}"}) { my $code = \&{"${target}::${name}"}; # this will warn $spec->add_export("&$name", $new_code) unless (stash_name($code) eq __PACKAGE__); } else { $spec->add_export("&$name", $new_code) } } eval { require Log::Log4perl; die if $Log::Log4perl::VERSION < 1.29; Log::Log4perl->wrapper_register(__PACKAGE__) }; # ____ is because tags must have at least one export and we don't want to # export anything but the levels selected sub ____ { } exports('____', @dlog, @log, qw( set_logger with_logger has_logger )); export_tag dlog => ('____'); export_tag log => ('____'); import_arguments qw(logger package_logger default_logger); sub router { our $Router_Instance ||= do { require Log::Contextual::Router; Log::Contextual::Router->new } } sub default_import { my ($class) = shift; die 'Log::Contextual does not have a default import list'; () } sub arg_logger { $_[1] } sub arg_levels { $_[1] || [qw(debug trace warn info error fatal)] } sub arg_package_logger { $_[1] } sub arg_default_logger { $_[1] } sub before_import { my ($class, $importer, $spec) = @_; my $router = $class->router; my $exports = $spec->exports; my %router_args = ( exporter => $class, target => $importer, arguments => $spec->argument_info ); my @tags = $class->default_import($spec) if $spec->config->{default}; for (@tags) { die "only tags are supported for defaults at this time" unless $_ =~ /^:(.*)$/; $spec->config->{$1} = 1; } $router->before_import(%router_args); if ($exports->{'&set_logger'}) { die ref($router) . " does not support set_logger()" unless $router->does('Log::Contextual::Role::Router::SetLogger'); _maybe_export($spec, $importer, 'set_logger', sub { $router->set_logger(@_) }, ); } if ($exports->{'&with_logger'}) { die ref($router) . " does not support with_logger()" unless $router->does('Log::Contextual::Role::Router::WithLogger'); _maybe_export($spec, $importer, 'with_logger', sub { $router->with_logger(@_) }, ); } if ($exports->{'&has_logger'}) { die ref($router) . " does not support has_logger()" unless $router->does('Log::Contextual::Role::Router::HasLogger'); _maybe_export($spec, $importer, 'has_logger', sub { $router->has_logger(@_) }, ); } my @levels = @{$class->arg_levels($spec->config->{levels})}; for my $level (@levels) { my %base = (exporter => $class, caller_level => 1, message_level => $level); my %exports; if ($spec->config->{log} || $exports->{"&log_$level"}) { $exports{log_} = sub (&@) { my ($code, @args) = @_; $router->handle_log_request( %base, caller_package => scalar(caller), message_sub => $code, message_args => \@args, ); return @args; }; } if ($spec->config->{log} || $exports->{"&slog_$level"}) { $exports{slog_} = sub { my ($text, @args) = @_; $router->handle_log_request( %base, caller_package => scalar(caller), message_text => $text, message_args => \@args, ); return @args; }; } if ($spec->config->{log} || $exports->{"&logS_$level"}) { $exports{logS_} = sub (&@) { my ($code, @args) = @_; $router->handle_log_request( %base, caller_package => scalar(caller), message_sub => $code, message_args => \@args, ); return $args[0]; }; } if ($spec->config->{log} || $exports->{"&slogS_$level"}) { $exports{slogS_} = sub { my ($text, @args) = @_; $router->handle_log_request( %base, caller_package => scalar(caller), message_text => $text, message_args => \@args, ); return $args[0]; }; } if ($spec->config->{dlog} || $exports->{"&Dlog_$level"}) { $exports{Dlog_} = sub (&@) { my ($code, @args) = @_; my $wrapped = sub { local $_ = (@_ ? Data::Dumper::Concise::Dumper @_ : '()'); &$code; }; $router->handle_log_request( %base, caller_package => scalar(caller), message_sub => $wrapped, message_args => \@args, ); return @args; }; } if ($spec->config->{dlog} || $exports->{"&Dslog_$level"}) { $exports{Dslog_} = sub { my ($text, @args) = @_; my $wrapped = sub { $text . (@_ ? Data::Dumper::Concise::Dumper @_ : '()'); }; $router->handle_log_request( %base, caller_package => scalar(caller), message_sub => $wrapped, message_args => \@args, ); return @args; }; } if ($spec->config->{dlog} || $exports->{"&DlogS_$level"}) { $exports{DlogS_} = sub (&$) { my ($code, $ref) = @_; my $wrapped = sub { local $_ = Data::Dumper::Concise::Dumper($_[0]); &$code; }; $router->handle_log_request( %base, caller_package => scalar(caller), message_sub => $wrapped, message_args => [$ref], ); return $ref; }; } if ($spec->config->{dlog} || $exports->{"&DslogS_$level"}) { $exports{DslogS_} = sub { my ($text, $ref) = @_; my $wrapped = sub { $text . Data::Dumper::Concise::Dumper($_[0]); }; $router->handle_log_request( %base, caller_package => scalar(caller), message_sub => $wrapped, message_args => [$ref], ); return $ref; }; } _maybe_export($spec, $importer, $_ . $level, $exports{$_}) for keys %exports; } } sub after_import { my ($class, $importer, $spec) = @_; my %router_args = ( exporter => $class, target => $importer, arguments => $spec->argument_info ); $class->router->after_import(%router_args); } for (qw(set with)) { no strict 'refs'; my $sub = "${_}_logger"; *{"Log::Contextual::$sub"} = sub { die "$sub is no longer a direct sub in Log::Contextual. " . 'Note that this feature was never tested nor documented. ' . "Please fix your code to import $sub instead of trying to use it directly" } } 1; __END__ =pod =encoding UTF-8 =head1 NAME Log::Contextual - Simple logging interface with a contextual log =head1 VERSION version 0.008001 =head1 SYNOPSIS use Log::Contextual qw( :log :dlog set_logger with_logger ); use Log::Contextual::SimpleLogger; use Log::Log4perl ':easy'; Log::Log4perl->easy_init($DEBUG); my $logger = Log::Log4perl->get_logger; set_logger $logger; log_debug { 'program started' }; sub foo { my $minilogger = Log::Contextual::SimpleLogger->new({ levels => [qw( trace debug )] }); my @args = @_; with_logger $minilogger => sub { log_trace { 'foo entered' }; my ($foo, $bar) = Dlog_trace { "params for foo: $_" } @args; # ... slog_trace 'foo left'; }; } foo(); Beginning with version 1.008 L also works out of the box with C: use Log::Contextual qw( :log :dlog set_logger ); use Log::Dispatchouli; my $ld = Log::Dispatchouli->new({ ident => 'slrtbrfst', to_stderr => 1, debug => 1, }); set_logger $ld; log_debug { 'program started' }; =head1 DESCRIPTION Major benefits: =over 2 =item * Efficient The default logging functions take blocks, so if a log level is disabled, the block will not run: # the following won't run if debug is off log_debug { "the new count in the database is " . $rs->count }; Similarly, the C prefixed methods only C the input if the level is enabled. =item * Handy The logging functions return their arguments, so you can stick them in the middle of expressions: for (log_debug { "downloading:\n" . join qq(\n), @_ } @urls) { ... } =item * Generic C is an interface for all major loggers. If you log through C you will be able to swap underlying loggers later. =item * Powerful C chooses which logger to use based on L<< user defined Cs|/LOGGER CODEREF >>. Normally you don't need to know this, but you can take advantage of it when you need to later. =item * Scalable If you just want to add logging to your basic application, start with L and then as your needs grow you can switch to L or L or L or whatever else. =back This module is a simple interface to extensible logging. It exists to abstract your logging interface so that logging is as painless as possible, while still allowing you to switch from one logger to another. It is bundled with a really basic logger, L, but in general you should use a real logger instead. For something more serious but not overly complicated, try L (see L for example.) =head1 A WORK IN PROGRESS This module is certainly not complete, but we will not break the interface lightly, so I would say it's safe to use in production code. The main result from that at this point is that doing: use Log::Contextual; will die as we do not yet know what the defaults should be. If it turns out that nearly everyone uses the C<:log> tag and C<:dlog> is really rare, we'll probably make C<:log> the default. But only time and usage will tell. =head1 IMPORT OPTIONS See L for information on setting these project wide. =head2 -logger When you import this module you may use C<-logger> as a shortcut for L, for example: use Log::Contextual::SimpleLogger; use Log::Contextual qw( :dlog ), -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )] }); sometimes you might want to have the logger handy for other stuff, in which case you might try something like the following: my $var_log; BEGIN { $var_log = VarLogger->new } use Log::Contextual qw( :dlog ), -logger => $var_log; =head2 -levels The C<-levels> import option allows you to define exactly which levels your logger supports. So the default, C<< [qw(debug trace warn info error fatal)] >>, works great for L, but it doesn't support the levels for L. But supporting those levels is as easy as doing use Log::Contextual -levels => [qw( debug info notice warning error critical alert emergency )]; =head2 -package_logger The C<-package_logger> import option is similar to the C<-logger> import option except C<-package_logger> sets the logger for the current package. Unlike L, C<-package_logger> cannot be overridden with L or L. package My::Package; use Log::Contextual::SimpleLogger; use Log::Contextual qw( :log ), -package_logger => Log::Contextual::WarnLogger->new({ env_prefix => 'MY_PACKAGE' }); If you are interested in using this package for a module you are putting on CPAN we recommend L for your package logger. =head2 -default_logger The C<-default_logger> import option is similar to the C<-logger> import option except C<-default_logger> sets the B logger for the current package. Basically it sets the logger to be used if C is never called; so package My::Package; use Log::Contextual::SimpleLogger; use Log::Contextual qw( :log ), -default_logger => Log::Contextual::WarnLogger->new({ env_prefix => 'MY_PACKAGE' }); =head1 SETTING DEFAULT IMPORT OPTIONS Eventually you will get tired of writing the following in every single one of your packages: use Log::Log4perl; use Log::Log4perl ':easy'; BEGIN { Log::Log4perl->easy_init($DEBUG) } use Log::Contextual -logger => Log::Log4perl->get_logger; You can set any of the import options for your whole project if you define your own C subclass as follows: package MyApp::Log::Contextual; use base 'Log::Contextual'; use Log::Log4perl ':easy'; Log::Log4perl->easy_init($DEBUG) sub arg_default_logger { $_[1] || Log::Log4perl->get_logger } sub arg_levels { [qw(debug trace warn info error fatal custom_level)] } sub default_import { ':log' } # or maybe instead of default_logger sub arg_package_logger { $_[1] } # and almost definitely not this, which is only here for completeness sub arg_logger { $_[1] } Note the C<< $_[1] || >> in C. All of these methods are passed the values passed in from the arguments to the subclass, so you can either throw them away, honor them, die on usage, etc. To be clear, if you define your subclass, and someone uses it as follows: use MyApp::Log::Contextual -default_logger => $foo, -levels => [qw(bar baz biff)]; Your C method will get C<$foo> and your C will get C<[qw(bar baz biff)]>; Additionally, the C method is what happens if a user tries to use your subclass with no arguments. The default just dies, but if you'd like to change the default to import a tag merely return the tags you'd like to import. So the following will all work: sub default_import { ':log' } sub default_import { ':dlog' } sub default_import { qw(:dlog :log ) } See L for an example of a subclass of C that makes use of default import options. =head1 FUNCTIONS =head2 set_logger my $logger = WarnLogger->new; set_logger $logger; Arguments: L C will just set the current logger to whatever you pass it. It expects a C, but if you pass it something else it will wrap it in a C for you. C is really meant only to be called from a top-level script. To avoid foot-shooting the function will warn if you call it more than once. =head2 with_logger my $logger = WarnLogger->new; with_logger $logger => sub { if (1 == 0) { log_fatal { 'Non Logical Universe Detected' }; } else { log_info { 'All is good' }; } }; Arguments: L, C C sets the logger for the scope of the C C<$to_execute>. As with L, C will wrap C<$returning_logger> with a C if needed. =head2 has_logger my $logger = WarnLogger->new; set_logger $logger unless has_logger; Arguments: none C will return true if a logger has been set. =head2 log_$level Import Tag: C<:log> Arguments: C C functions all work the same except that a different method is called on the underlying C<$logger> object. The basic pattern is: sub log_$level (&@) { if ($logger->is_$level) { $logger->$level(shift->(@_)); } @_ } Note that the function returns it's arguments. This can be used in a number of ways, but often it's convenient just for partial inspection of passthrough data my @friends = log_trace { 'friends list being generated, data from first friend: ' . Dumper($_[0]->TO_JSON) } generate_friend_list(); If you want complete inspection of passthrough data, take a look at the L functions. Which functions are exported depends on what was passed to L. The default (no C<-levels> option passed) would export: =over 2 =item log_trace =item log_debug =item log_info =item log_warn =item log_error =item log_fatal B C does not call C for you, see L =back =head2 slog_$level Mostly the same as L, but expects a string as first argument, not a block. Arguments are passed through just the same, but since it's just a string, interpolation of arguments into it must be done manually. my @friends = slog_trace 'friends list being generated.', generate_friend_list(); =head2 logS_$level Import Tag: C<:log> Arguments: C This is really just a special case of the L functions. It forces scalar context when that is what you need. Other than that it works exactly same: my $friend = logS_trace { 'I only have one friend: ' . Dumper($_[0]->TO_JSON) } friend(); See also: L. =head2 slogS_$level Mostly the same as L, but expects a string as first argument, not a block. Arguments are passed through just the same, but since it's just a string, interpolation of arguments into it must be done manually. my $friend = slogS_trace 'I only have one friend.', friend(); =head2 Dlog_$level Import Tag: C<:dlog> Arguments: C All of the following six functions work the same as their L brethren, except they return what is passed into them and put the stringified (with L) version of their args into C<$_>. This means you can do cool things like the following: my @nicks = Dlog_debug { "names: $_" } map $_->value, $frew->names->all; and the output might look something like: names: "fREW" "fRIOUX" "fROOH" "fRUE" "fiSMBoC" Which functions are exported depends on what was passed to L. The default (no C<-levels> option passed) would export: =over 2 =item Dlog_trace =item Dlog_debug =item Dlog_info =item Dlog_warn =item Dlog_error =item Dlog_fatal B C does not call C for you, see L =back =head2 Dslog_$level Mostly the same as L, but expects a string as first argument, not a block. Arguments are passed through just the same, but since it's just a string, no interpolation point can be used, instead the Dumper output is appended. my @nicks = Dslog_debug "names: ", map $_->value, $frew->names->all; =head2 DlogS_$level Import Tag: C<:dlog> Arguments: C Like L, these functions are a special case of L. They only take a single scalar after the C<$returning_message> instead of slurping up (and also setting C) all the C<@args> my $pals_rs = DlogS_debug { "pals resultset: $_" } $schema->resultset('Pals')->search({ perlers => 1 }); =head2 DslogS_$level Mostly the same as L, but expects a string as first argument, not a block. Arguments are passed through just the same, but since it's just a string, no interpolation point can be used, instead the Dumper output is appended. my $pals_rs = DslogS_debug "pals resultset: ", $schema->resultset('Pals')->search({ perlers => 1 }); =head1 LOGGER CODEREF Anywhere a logger object can be passed, a coderef is accepted. This is so that the user can use different logger objects based on runtime information. The logger coderef is passed the package of the caller, and the caller level the coderef needs to use if it wants more caller information. The latter is in a hashref to allow for more options in the future. Here is a basic example of a logger that exploits C to reproduce the output of C with a logger: my @caller_info; my $var_log = Log::Contextual::SimpleLogger->new({ levels => [qw(trace debug info warn error fatal)], coderef => sub { chomp($_[0]); warn "$_[0] at $caller_info[1] line $caller_info[2].\n" } }); my $warn_faker = sub { my ($package, $args) = @_; @caller_info = caller($args->{caller_level}); $var_log }; set_logger($warn_faker); log_debug { 'test' }; The following is an example that uses the information passed to the logger coderef. It sets the global logger to C<$l3>, the logger for the C package to C<$l1>, except the C method in C which uses the C<$l2> logger and lastly the logger for the C package to C<$l2>. Note that it increases the caller level as it dispatches based on where the caller of the log function, not the log function itself. my $complex_dispatcher = do { my $l1 = ...; my $l2 = ...; my $l3 = ...; my %registry = ( -logger => $l3, A1 => { -logger => $l1, lol => $l2, }, A2 => { -logger => $l2 }, ); sub { my ( $package, $info ) = @_; my $logger = $registry{'-logger'}; if (my $r = $registry{$package}) { $logger = $r->{'-logger'} if $r->{'-logger'}; my (undef, undef, undef, $sub) = caller($info->{caller_level} + 1); $sub =~ s/^\Q$package\E:://g; $logger = $r->{$sub} if $r->{$sub}; } return $logger; } }; set_logger $complex_dispatcher; =head1 LOGGER INTERFACE Because this module is ultimately pretty looking glue (glittery?) with the awesome benefit of the Contextual part, users will often want to make their favorite logger work with it. The following are the methods that should be implemented in the logger: is_trace is_debug is_info is_warn is_error is_fatal trace debug info warn error fatal The first six merely need to return true if that level is enabled. The latter six take the results of whatever the user returned from their coderef and log them. For a basic example see L. =head1 LOG ROUTING In between the loggers and the log functions is a log router that is responsible for finding a logger to handle the log event and passing the log information to the logger. This relationship is described in the documentation for C. C and packages that extend it will by default share a router singleton that implements the with_logger() and set_logger() functions and also respects the -logger, -package_logger, and -default_logger import options with their associated default value functions. The router singleton is available as the return value of the router() function. Users of Log::Contextual may overload router() to return instances of custom log routers that could for example work with loggers that use a different interface. =head1 EXCEPTIONS AND ERROR HANDLING C, by design, does not B invoke C on your behalf(L<*see footnote*|/footnote>) for C. Logging events are characterized as information, not flow control, and conflating the two results in negative design anti-patterns. As such, C would at be better used to communicate information about a I failure, for example: if ( condition ) { log_fatal { "Bad Condition is true" }; die My::Exception->new(); } This has a number of benefits: =over 4 =item * You're more likely to want to use useful Exception Objects and flow control instead of cheating with log messages. =item * You're less likely to run a risk of losing what the actual problem was when some error occurs in your creation of the Exception Object =item * You're less likely to run the risk of losing important log context due to exceptions occurring mid way through C unwinding and C global destruction. =back If you're still too lazy to use exceptions, then you can do what you probably want as follows: if ( ... ) { log_fatal { "Bad condition is true" }; die "Bad condtion is true"; } Or for C<:dlog> style: use Data::Dumper::Consise qw( Dumper ); if ( ... ) { # Dlog_fatal but not my $reason = "Bad condtion is true because: " . Dumper($thing); log_fatal { $reason }; die $reason; } =head2 footnote The underlying behaviour of C is dependent on the backing library. All the Loggers shipping with C behave this way, as do many of the supported loggers, like C. However, not all loggers work this way, and one must be careful. C doesn't support implementing C L C implements C using C ( via Carp ) =head1 CONTRIBUTORS kentnl - Kent Fredric triddle - Tyler Riddle voj - Jakob Voß =head1 DESIGNER mst - Matt S. Trout =head1 AUTHOR Arthur Axel "fREW" Schmidt =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2018 by Arthur Axel "fREW" Schmidt. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut TestExporter.pm100644001750001750 20313230423621 17747 0ustar00frewfrew000000000000Log-Contextual-0.008001/t/libpackage TestExporter; use Moo; use TestRouter; extends 'Log::Contextual'; sub router { our $Router ||= TestRouter->new } 1; author-pod-syntax.t100644001750001750 45413230423621 17776 0ustar00frewfrew000000000000Log-Contextual-0.008001/t#!perl BEGIN { unless ($ENV{AUTHOR_TESTING}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } # This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests. use strict; use warnings; use Test::More; use Test::Pod 1.41; all_pod_files_ok(); warnlogger-with-levels.t100644001750001750 615213230423621 21021 0ustar00frewfrew000000000000Log-Contextual-0.008001/tuse strict; use warnings; use Log::Contextual::WarnLogger; # -levels => [qw(custom1 custom2)]; use Log::Contextual qw{:log set_logger} => -logger => Log::Contextual::WarnLogger->new({env_prefix => 'FOO'}); use Test::More qw(no_plan); use Test::Fatal; { my $l; like( exception { $l = Log::Contextual::WarnLogger->new({levels => ''}) }, qr/invalid levels specification: must be non-empty arrayref/, 'cannot pass empty string for levels', ); like( exception { $l = Log::Contextual::WarnLogger->new({levels => []}) }, qr/invalid levels specification: must be non-empty arrayref/, 'cannot pass empty list for levels', ); is( exception { $l = Log::Contextual::WarnLogger->new( {levels => undef, env_prefix => 'FOO'}) }, undef, 'ok to leave levels undefined', ); } { my $l = Log::Contextual::WarnLogger->new({ env_prefix => 'BAR', levels => [qw(custom1 custom2)]}); foreach my $sub (qw(is_custom1 is_custom2 custom1 custom2)) { is(exception { $l->$sub }, undef, $sub . ' is handled by AUTOLOAD',); } foreach my $sub (qw(is_foo foo)) { is( exception { $l->$sub }, undef, 'arbitrary sub ' . $sub . ' is handled by AUTOLOAD', ); } } { # levels is optional - most things should still work otherwise. my $l = Log::Contextual::WarnLogger->new({env_prefix => 'BAR',}); # if we don't know the level, and there are no environment variables set, # just log everything. { ok($l->is_custom1, 'is_custom1 defaults to true on WarnLogger'); ok($l->is_custom2, 'is_custom2 defaults to true on WarnLogger'); } # otherwise, go with what the variable says. { local $ENV{BAR_CUSTOM1} = 0; local $ENV{BAR_CUSTOM2} = 1; ok(!$l->is_custom1, 'is_custom1 is false on WarnLogger'); ok($l->is_custom2, 'is_custom2 is true on WarnLogger'); ok($l->is_foo, 'is_foo defaults to true on WarnLogger'); local $ENV{BAR_UPTO} = 'foo'; like( exception { $l->is_bar }, qr/Unrecognized log level 'foo' in \$ENV\{BAR_UPTO\}/, 'Cannot use an unrecognized log level in UPTO', ); } } # these tests taken from t/warnlogger.t my $l = Log::Contextual::WarnLogger->new({ env_prefix => 'BAR', levels => [qw(custom1 custom2)]}); { local $ENV{BAR_CUSTOM1} = 0; local $ENV{BAR_CUSTOM2} = 1; ok(!$l->is_custom1, 'is_custom1 is false on WarnLogger'); ok($l->is_custom2, 'is_custom2 is true on WarnLogger'); ok(!$l->is_foo, 'is_foo is false (custom levels supplied) on WarnLogger'); } { local $ENV{BAR_UPTO} = 'custom1'; ok($l->is_custom1, 'is_custom1 is true on WarnLogger'); ok($l->is_custom2, 'is_custom2 is true on WarnLogger'); } { local $ENV{BAR_UPTO} = 'custom2'; ok(!$l->is_custom1, 'is_custom1 is false on WarnLogger'); ok($l->is_custom2, 'is_custom2 is true on WarnLogger'); } { local $ENV{BAR_UPTO} = 'foo'; like( exception { $l->is_custom1 }, qr/Unrecognized log level 'foo'/, 'Cannot use an unrecognized log level in UPTO', ); } Contextual000755001750001750 013230423621 17232 5ustar00frewfrew000000000000Log-Contextual-0.008001/lib/LogRouter.pm100644001750001750 1010213230423621 21222 0ustar00frewfrew000000000000Log-Contextual-0.008001/lib/Log/Contextualpackage Log::Contextual::Router; $Log::Contextual::Router::VERSION = '0.008001'; # ABSTRACT: Route messages to loggers use Moo; use Scalar::Util 'blessed'; with 'Log::Contextual::Role::Router', 'Log::Contextual::Role::Router::SetLogger', 'Log::Contextual::Role::Router::WithLogger', 'Log::Contextual::Role::Router::HasLogger'; eval { require Log::Log4perl; die if $Log::Log4perl::VERSION < 1.29; Log::Log4perl->wrapper_register(__PACKAGE__) }; has _default_logger => ( is => 'ro', default => sub { {} }, init_arg => undef, ); has _package_logger => ( is => 'ro', default => sub { {} }, init_arg => undef, ); has _get_logger => ( is => 'ro', default => sub { {} }, init_arg => undef, ); sub before_import { } sub after_import { my ($self, %import_info) = @_; my $exporter = $import_info{exporter}; my $target = $import_info{target}; my $config = $import_info{arguments}; if (my $l = $exporter->arg_logger($config->{logger})) { $self->set_logger($l); } if (my $l = $exporter->arg_package_logger($config->{package_logger})) { $self->_set_package_logger_for($target, $l); } if (my $l = $exporter->arg_default_logger($config->{default_logger})) { $self->_set_default_logger_for($target, $l); } } sub with_logger { my $logger = $_[1]; if (ref $logger ne 'CODE') { die 'logger was not a CodeRef or a logger object. Please try again.' unless blessed($logger); $logger = do { my $l = $logger; sub { $l } } } local $_[0]->_get_logger->{l} = $logger; $_[2]->(); } sub set_logger { my $logger = $_[1]; if (ref $logger ne 'CODE') { die 'logger was not a CodeRef or a logger object. Please try again.' unless blessed($logger); $logger = do { my $l = $logger; sub { $l } } } warn 'set_logger (or -logger) called more than once! This is a bad idea!' if $_[0]->_get_logger->{l}; $_[0]->_get_logger->{l} = $logger; } sub has_logger { !!$_[0]->_get_logger->{l} } sub _set_default_logger_for { my $logger = $_[2]; if (ref $logger ne 'CODE') { die 'logger was not a CodeRef or a logger object. Please try again.' unless blessed($logger); $logger = do { my $l = $logger; sub { $l } } } $_[0]->_default_logger->{$_[1]} = $logger } sub _set_package_logger_for { my $logger = $_[2]; if (ref $logger ne 'CODE') { die 'logger was not a CodeRef or a logger object. Please try again.' unless blessed($logger); $logger = do { my $l = $logger; sub { $l } } } $_[0]->_package_logger->{$_[1]} = $logger } sub get_loggers { my ($self, %info) = @_; my $package = $info{caller_package}; my $log_level = $info{message_level}; my $logger = ( $_[0]->_package_logger->{$package} || $_[0]->_get_logger->{l} || $_[0]->_default_logger->{$package} || die q( no logger set! you can't try to log something without a logger! )); $info{caller_level}++; $logger = $logger->($package, \%info); return $logger if $logger ->${\"is_${log_level}"}; return (); } sub handle_log_request { my ($self, %message_info) = @_; my $generator = $message_info{message_sub}; my $text = $message_info{message_text}; my $args = $message_info{message_args}; my $log_level = $message_info{message_level}; $message_info{caller_level}++; my @loggers = $self->get_loggers(%message_info) or return; my @log = defined $text ? ($text) : ($generator->(@$args)); $_->$log_level(@log) for @loggers; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Log::Contextual::Router - Route messages to loggers =head1 VERSION version 0.008001 =head1 AUTHOR Arthur Axel "fREW" Schmidt =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2018 by Arthur Axel "fREW" Schmidt. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut DefaultImportLogger.pm100644001750001750 75413230423621 21231 0ustar00frewfrew000000000000Log-Contextual-0.008001/t/libpackage DefaultImportLogger; use base 'Log::Contextual'; use Log::Contextual::SimpleLogger; my $logger = DumbLogger2->new; sub default_import { ':log' } sub arg_levels { $_[1] || [qw(lol wut zomg)] } sub arg_logger { $_[1] || $logger } package DumbLogger2; our $var; sub new { bless {}, 'DumbLogger2' } sub is_wut { 1 } sub wut { $var = "[wut] $_[1]\n" } sub is_lol { 1 } sub lol { $var = "[lol] $_[1]\n" } sub is_zomg { 1 } sub zomg { $var = "[zomg] $_[1]\n" } 1; TeeLogger.pm100644001750001750 711313230423621 21607 0ustar00frewfrew000000000000Log-Contextual-0.008001/lib/Log/Contextualpackage Log::Contextual::TeeLogger; $Log::Contextual::TeeLogger::VERSION = '0.008001'; # ABSTRACT: Output to more than one logger use strict; use warnings; { for my $name (qw( trace debug info warn error fatal )) { no strict 'refs'; *{$name} = sub { my $self = shift; foreach my $logger (@{$self->{loggers}}) { $logger->$name(@_); } }; my $is_name = "is_${name}"; *{$is_name} = sub { my $self = shift; foreach my $logger (@{$self->{loggers}}) { return 1 if $logger->$is_name(@_); } return 0; }; } } sub new { my ($class, $args) = @_; my $self = bless {}, $class; ref($self->{loggers} = $args->{loggers}) eq 'ARRAY' or die "No loggers passed to tee logger"; return $self; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Log::Contextual::TeeLogger - Output to more than one logger =head1 VERSION version 0.008001 =head1 SYNOPSIS use Log::Contextual::SimpleLogger; use Log::Contextual::TeeLogger; use Log::Contextual qw( :log ), -logger => Log::Contextual::TeeLogger->new({ loggers => [ Log::Contextual::SimpleLogger->new({ levels => [ 'debug' ] }), Log::Contextual::SimpleLogger->new({ levels => [ 'info' ], coderef => sub { print @_ }, }), ]}); ## docs below here not yet edited log_info { 'program started' }; # no-op because info is not in levels sub foo { log_debug { 'entered foo' }; ... } =head1 DESCRIPTION This module is a simple logger made mostly for demonstration and initial experimentation with L. We recommend you use a real logger instead. For something more serious but not overly complicated, take a look at L. =head1 METHODS =head2 new Arguments: C<< Dict[ levels => ArrayRef[Str], coderef => Optional[CodeRef] ] $conf >> my $l = Log::Contextual::SimpleLogger->new({ levels => [qw( info warn )], coderef => sub { print @_ }, # the default prints to STDERR }); Creates a new SimpleLogger object with the passed levels enabled and optionally a C may be passed to modify how the logs are output/stored. Levels may contain: trace debug info warn error fatal =head2 $level Arguments: C<@anything> All of the following six methods work the same. The basic pattern is: sub $level { my $self = shift; print STDERR "[$level] " . join qq{\n}, @_; if $self->is_$level; } =head3 trace $l->trace( 'entered method foo with args ' join q{,}, @args ); =head3 debug $l->debug( 'entered method foo' ); =head3 info $l->info( 'started process foo' ); =head3 warn $l->warn( 'possible misconfiguration at line 10' ); =head3 error $l->error( 'non-numeric user input!' ); =head3 fatal $l->fatal( '1 is never equal to 0!' ); B C does not call C for you, see L =head2 is_$level All of the following six functions just return true if their respective level is enabled. =head3 is_trace say 'tracing' if $l->is_trace; =head3 is_debug say 'debuging' if $l->is_debug; =head3 is_info say q{info'ing} if $l->is_info; =head3 is_warn say 'warning' if $l->is_warn; =head3 is_error say 'erroring' if $l->is_error; =head3 is_fatal say q{fatal'ing} if $l->is_fatal; =head1 AUTHOR Arthur Axel "fREW" Schmidt =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2018 by Arthur Axel "fREW" Schmidt. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut WarnLogger.pm100644001750001750 1464013230423621 22024 0ustar00frewfrew000000000000Log-Contextual-0.008001/lib/Log/Contextualpackage Log::Contextual::WarnLogger; $Log::Contextual::WarnLogger::VERSION = '0.008001'; # ABSTRACT: logger for libraries using Log::Contextual use strict; use warnings; use Carp 'croak'; my @default_levels = qw( trace debug info warn error fatal ); # generate subs to handle the default levels # anything else will have to be handled by AUTOLOAD at runtime { for my $level (@default_levels) { no strict 'refs'; my $is_name = "is_$level"; *{$level} = sub { my $self = shift; $self->_log($level, @_) if $self->$is_name; }; *{$is_name} = sub { my $self = shift; return 1 if $ENV{$self->{env_prefix} . '_' . uc $level}; my $upto = $ENV{$self->{env_prefix} . '_UPTO'}; return unless $upto; $upto = lc $upto; return $self->{level_num}{$level} >= $self->{level_num}{$upto}; }; } } our $AUTOLOAD; sub AUTOLOAD { my $self = $_[0]; (my $name = our $AUTOLOAD) =~ s/.*:://; return if $name eq 'DESTROY'; # extract the log level from the sub name my ($is, $level) = $name =~ m/^(is_)?(.+)$/; my $is_name = "is_$level"; no strict 'refs'; *{$level} = sub { my $self = shift; $self->_log($level, @_) if $self->$is_name; }; *{$is_name} = sub { my $self = shift; my $prefix_field = $self->{env_prefix} . '_' . uc $level; return 1 if $ENV{$prefix_field}; # don't log if the variable specifically says not to return 0 if defined $ENV{$prefix_field} and not $ENV{$prefix_field}; my $upto_field = $self->{env_prefix} . '_UPTO'; my $upto = $ENV{$upto_field}; if ($upto) { $upto = lc $upto; croak "Unrecognized log level '$upto' in \$ENV{$upto_field}" if not defined $self->{level_num}{$upto}; return $self->{level_num}{$level} >= $self->{level_num}{$upto}; } # if we don't recognize this level and nothing says otherwise, log! return 1 if not $self->{custom_levels}; }; goto &$AUTOLOAD; } sub new { my ($class, $args) = @_; my $levels = $args->{levels}; croak 'invalid levels specification: must be non-empty arrayref' if defined $levels and (ref $levels ne 'ARRAY' or !@$levels); my $custom_levels = defined $levels; $levels ||= [@default_levels]; my %level_num; @level_num{@$levels} = (0 .. $#{$levels}); my $self = bless { levels => $levels, level_num => \%level_num, custom_levels => $custom_levels, }, $class; $self->{env_prefix} = $args->{env_prefix} or die 'no env_prefix passed to Log::Contextual::WarnLogger->new'; return $self; } sub _log { my $self = shift; my $level = shift; my $message = join("\n", @_); $message .= "\n" unless $message =~ /\n$/; warn "[$level] $message"; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Log::Contextual::WarnLogger - logger for libraries using Log::Contextual =head1 VERSION version 0.008001 =head1 SYNOPSIS package My::Package; use Log::Contextual::WarnLogger; use Log::Contextual qw( :log ), -default_logger => Log::Contextual::WarnLogger->new({ env_prefix => 'MY_PACKAGE', levels => [ qw(debug info notice warning error critical alert emergency) ], }); # warns '[info] program started' if $ENV{MY_PACKAGE_TRACE} is set log_info { 'program started' }; # no-op because info is not in levels sub foo { # warns '[debug] entered foo' if $ENV{MY_PACKAGE_DEBUG} is set log_debug { 'entered foo' }; ... } =head1 DESCRIPTION This module is a simple logger made for libraries using L. We recommend the use of this logger as your default logger as it is simple and useful for most users, yet users can use L to override your choice of logger in their own code thanks to the way L works. =head1 METHODS =head2 new Arguments: C<< Dict[ env_prefix => Str, levels => List ] $conf >> my $l = Log::Contextual::WarnLogger->new({ env_prefix => 'BAR' }); or: my $l = Log::Contextual::WarnLogger->new({ env_prefix => 'BAR', levels => [ 'level1', 'level2' ], }); Creates a new logger object where C defines what the prefix is for the environment variables that will be checked for the log levels. The log levels may be customized, but if not defined, these are used: =over 4 =item trace =item debug =item info =item warn =item error =item fatal =back For example, if C is set to C the following environment variables will be used: FREWS_PACKAGE_UPTO FREWS_PACKAGE_TRACE FREWS_PACKAGE_DEBUG FREWS_PACKAGE_INFO FREWS_PACKAGE_WARN FREWS_PACKAGE_ERROR FREWS_PACKAGE_FATAL Note that C is a convenience variable. If you set C<< FOO_UPTO=TRACE >> it will enable all log levels. Similarly, if you set it to C only fatal will be enabled. =head2 $level Arguments: C<@anything> All of the following six methods work the same. The basic pattern is: sub $level { my $self = shift; warn "[$level] " . join qq{\n}, @_; if $self->is_$level; } =head3 trace $l->trace( 'entered method foo with args ' join q{,}, @args ); =head3 debug $l->debug( 'entered method foo' ); =head3 info $l->info( 'started process foo' ); =head3 warn $l->warn( 'possible misconfiguration at line 10' ); =head3 error $l->error( 'non-numeric user input!' ); =head3 fatal $l->fatal( '1 is never equal to 0!' ); If different levels are specified, appropriate functions named for your custom levels work as you expect. B C does not call C for you, see L =head2 is_$level All of the following six functions just return true if their respective environment variable is enabled. =head3 is_trace say 'tracing' if $l->is_trace; =head3 is_debug say 'debuging' if $l->is_debug; =head3 is_info say q{info'ing} if $l->is_info; =head3 is_warn say 'warning' if $l->is_warn; =head3 is_error say 'erroring' if $l->is_error; =head3 is_fatal say q{fatal'ing} if $l->is_fatal; If different levels are specified, appropriate is_$level functions work as you would expect. =head1 AUTHOR Arthur Axel "fREW" Schmidt =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2018 by Arthur Axel "fREW" Schmidt. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Role000755001750001750 013230423621 20133 5ustar00frewfrew000000000000Log-Contextual-0.008001/lib/Log/ContextualRouter.pm100644001750001750 1314013230423621 22130 0ustar00frewfrew000000000000Log-Contextual-0.008001/lib/Log/Contextual/Rolepackage Log::Contextual::Role::Router; $Log::Contextual::Role::Router::VERSION = '0.008001'; # ABSTRACT: Abstract interface between loggers and logging code blocks use Moo::Role; requires 'before_import'; requires 'after_import'; requires 'handle_log_request'; 1; __END__ =pod =encoding UTF-8 =head1 NAME Log::Contextual::Role::Router - Abstract interface between loggers and logging code blocks =head1 VERSION version 0.008001 =head1 SYNOPSIS package MyApp::Log::Router; use Moo; use Log::Contextual::SimpleLogger; with 'Log::Contextual::Role::Router'; has logger => (is => 'lazy'); sub _build_logger { return Log::Contextual::SimpleLogger->new({ levels_upto => 'debug' }); } sub before_import { my ($self, %export_info) = @_; my $exporter = $export_info{exporter}; my $target = $export_info{target}; print STDERR "Package '$target' will import from '$exporter'\n"; } sub after_import { my ($self, %export_info) = @_; my $exporter = $export_info{exporter}; my $target = $export_info{target}; print STDERR "Package '$target' has imported from '$exporter'\n"; } sub handle_log_request { my ($self, %message_info) = @_; my $log_code_block = $message_info{message_sub}; my $args = $message_info{message_args}; my $log_level_name = $message_info{message_level}; my $logger = $self->logger; my $is_active = $logger->can("is_${log_level_name}"); return unless defined $is_active && $logger->$is_active; my $log_message = $log_code_block->(@$args); $logger->$log_level_name($log_message); } package MyApp::Log::Contextual; use Moo; use MyApp::Log::Router; extends 'Log::Contextual'; #This example router is a singleton sub router { our $Router ||= MyApp::Log::Router->new } package main; use strict; use warnings; use MyApp::Log::Contextual qw(:log); log_info { "Hello there" }; =head1 DESCRIPTION Log::Contextual has three parts =over 4 =item Export manager and logging method generator These tasks are handled by the C package. =item Logger selection and invocation The logging functions generated and exported by Log::Contextual call a method on an instance of a log router object which is responsible for invoking any loggers that should get an opportunity to receive the log message. The C class implements the set_logger() and with_logger() functions as well as uses the arg_ prefixed functions to configure itself and provide the standard C logger selection API. =item Log message formatting and output The logger objects themselves accept or reject a log message at a certain log level with a guard method per level. If the logger is going to accept the log message the router is then responsible for executing the log message code block and passing the generated message to the logging object's log method. =back =head1 METHODS =over 4 =item before_import($self, %import_info) =item after_import($self, %import_info) These two required methods are called with identical arguments at two different places during the import process. The before_import() method is invoked prior to the logging subroutines being exported into the target package and after_import() is called when the export is completed but before control returns to the package that imported the API. The arguments are passed as a hash with the following keys: =over 4 =item exporter This is the name of the package that has been imported. It can also be 'Log::Contextual' itself. In the case of the synopsis the value for exporter would be 'MyApp::Log::Contextual'. =item target This is the package name that is importing the logging API. In the case of the synopsis the value would be 'main'. =item arguments This is a hash reference containing the configuration values that were provided for the import. The key is the name of the configuration item that was specified without the leading hyphen ('-'). For instance if the logging API is imported as follows use Log::Contextual qw( :log ), -logger => Custom::Logger->new({ levels => [qw( debug )] }); then $import_info{arguments}->{logger} would contain that instance of Custom::Logger. =back =item handle_log_request($self, %message_info) This method is called by C when a log event happens. The arguments are passed as a hash with the following keys =over 4 =item exporter This is the name of the package that created the logging methods used to generate the log event. =item caller_package This is the name of the package that the log event has happened inside of. =item caller_level This is an integer that contains the value to pass to caller() that will provide information about the location the log event was created at. =item log_level This is the name of the log level associated with the log event. =item message_sub This is the message generating code block associated with the log event passed as a subref. If the logger accepts the log request the router should execute the subref to create the log message and then pass the message as a string to the logger. =item message_args This is an array reference that contains the arguments given to the message generating code block. When invoking the message generator it will almost certainly be expecting these argument values as well. =back =back =head1 AUTHOR Arthur Axel "fREW" Schmidt =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2018 by Arthur Axel "fREW" Schmidt. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut SimpleLogger.pm100644001750001750 776013230423621 22333 0ustar00frewfrew000000000000Log-Contextual-0.008001/lib/Log/Contextualpackage Log::Contextual::SimpleLogger; $Log::Contextual::SimpleLogger::VERSION = '0.008001'; # ABSTRACT: Super simple logger made for playing with Log::Contextual use strict; use warnings; { for my $name (qw( trace debug info warn error fatal )) { no strict 'refs'; *{$name} = sub { my $self = shift; $self->_log($name, @_) if ($self->{$name}); }; *{"is_$name"} = sub { my $self = shift; return $self->{$name}; }; } } sub new { my ($class, $args) = @_; my $self = bless {}, $class; $self->{$_} = 1 for @{$args->{levels}}; $self->{coderef} = $args->{coderef} || sub { print STDERR @_ }; if (my $upto = $args->{levels_upto}) { my @levels = (qw( trace debug info warn error fatal )); my $i = 0; for (@levels) { last if $upto eq $_; $i++ } for ($i .. $#levels) { $self->{$levels[$_]} = 1 } } return $self; } sub _log { my $self = shift; my $level = shift; my $message = join("\n", @_); $message .= "\n" unless $message =~ /\n$/; $self->{coderef}->(sprintf("[%s] %s", $level, $message)); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Log::Contextual::SimpleLogger - Super simple logger made for playing with Log::Contextual =head1 VERSION version 0.008001 =head1 SYNOPSIS use Log::Contextual::SimpleLogger; use Log::Contextual qw( :log ), -logger => Log::Contextual::SimpleLogger->new({ levels => [qw( debug )]}); log_info { 'program started' }; # no-op because info is not in levels sub foo { log_debug { 'entered foo' }; ... } =head1 DESCRIPTION This module is a simple logger made mostly for demonstration and initial experimentation with L. We recommend you use a real logger instead. For something more serious but not overly complicated, take a look at L. =head1 METHODS =head2 new Arguments: C<< Dict[ levels => Optional[ArrayRef[Str]], levels_upto => Level, coderef => Optional[CodeRef], ] $conf >> my $l = Log::Contextual::SimpleLogger->new({ levels => [qw( info warn )], coderef => sub { print @_ }, # the default prints to STDERR }); or my $l = Log::Contextual::SimpleLogger->new({ levels_upto => 'debug', coderef => sub { print @_ }, # the default prints to STDERR }); Creates a new SimpleLogger object with the passed levels enabled and optionally a C may be passed to modify how the logs are output/stored. C enables all the levels upto and including the level passed. Levels may contain: trace debug info warn error fatal =head2 $level Arguments: C<@anything> All of the following six methods work the same. The basic pattern is: sub $level { my $self = shift; print STDERR "[$level] " . join qq{\n}, @_; if $self->is_$level; } =head3 trace $l->trace( 'entered method foo with args ' join q{,}, @args ); =head3 debug $l->debug( 'entered method foo' ); =head3 info $l->info( 'started process foo' ); =head3 warn $l->warn( 'possible misconfiguration at line 10' ); =head3 error $l->error( 'non-numeric user input!' ); =head3 fatal $l->fatal( '1 is never equal to 0!' ); B C does not call C for you, see L =head2 is_$level All of the following six functions just return true if their respective level is enabled. =head3 is_trace say 'tracing' if $l->is_trace; =head3 is_debug say 'debuging' if $l->is_debug; =head3 is_info say q{info'ing} if $l->is_info; =head3 is_warn say 'warning' if $l->is_warn; =head3 is_error say 'erroring' if $l->is_error; =head3 is_fatal say q{fatal'ing} if $l->is_fatal; =head1 AUTHOR Arthur Axel "fREW" Schmidt =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2018 by Arthur Axel "fREW" Schmidt. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Easy000755001750001750 013230423621 20133 5ustar00frewfrew000000000000Log-Contextual-0.008001/lib/Log/ContextualPackage.pm100644001750001750 364213230423621 22171 0ustar00frewfrew000000000000Log-Contextual-0.008001/lib/Log/Contextual/Easypackage Log::Contextual::Easy::Package; $Log::Contextual::Easy::Package::VERSION = '0.008001'; # ABSTRACT: Import all logging methods with WarnLogger as default package logger use strict; use warnings; use base 'Log::Contextual'; sub arg_package_logger { if ($_[1]) { return $_[1]; } else { require Log::Contextual::WarnLogger; my $package = uc(caller(3)); $package =~ s/::/_/g; return Log::Contextual::WarnLogger->new({env_prefix => $package}); } } sub default_import { qw(:dlog :log ) } 1; __END__ =pod =encoding UTF-8 =head1 NAME Log::Contextual::Easy::Package - Import all logging methods with WarnLogger as default package logger =head1 VERSION version 0.008001 =head1 SYNOPSIS In your module: package My::Module; use Log::Contextual::Easy::Package; log_debug { "your message" }; Dlog_trace { $_ } @vars; In your program: use My::Module; # enable warnings $ENV{MY_MODULE_UPTO}="TRACE"; # or use a specific logger with set_logger / with_logger =head1 DESCRIPTION By default, this module enables a L with C based on the module's name that uses Log::Contextual::Easy. The logging levels are set to C C, C, C, C, and C (in this order) and all logging functions (L, L, L, and L) are exported. For what C<::Package> implies, see L. =head1 SEE ALSO =over 4 =item L =back =head1 AUTHOR Arthur Axel "fREW" Schmidt =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2018 by Arthur Axel "fREW" Schmidt. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Default.pm100644001750001750 360413230423621 22220 0ustar00frewfrew000000000000Log-Contextual-0.008001/lib/Log/Contextual/Easypackage Log::Contextual::Easy::Default; $Log::Contextual::Easy::Default::VERSION = '0.008001'; # ABSTRACT: Import all logging methods with WarnLogger as default use strict; use warnings; use base 'Log::Contextual'; sub arg_default_logger { if ($_[1]) { return $_[1]; } else { require Log::Contextual::WarnLogger; my $package = uc(caller(3)); $package =~ s/::/_/g; return Log::Contextual::WarnLogger->new({env_prefix => $package}); } } sub default_import { qw(:dlog :log ) } 1; __END__ =pod =encoding UTF-8 =head1 NAME Log::Contextual::Easy::Default - Import all logging methods with WarnLogger as default =head1 VERSION version 0.008001 =head1 SYNOPSIS In your module: package My::Module; use Log::Contextual::Easy::Default; log_debug { "your message" }; Dlog_trace { $_ } @vars; In your program: use My::Module; # enable warnings $ENV{MY_MODULE_UPTO}="TRACE"; # or use a specific logger with set_logger / with_logger =head1 DESCRIPTION By default, this module enables a L with C based on the module's name that uses Log::Contextual::Easy. The logging levels are set to C C, C, C, C, and C (in this order) and all logging functions (L, L, L, and L) are exported. For what C<::Default> implies, see L. =head1 SEE ALSO =over 4 =item L =back =head1 AUTHOR Arthur Axel "fREW" Schmidt =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2018 by Arthur Axel "fREW" Schmidt. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Router000755001750001750 013230423621 21413 5ustar00frewfrew000000000000Log-Contextual-0.008001/lib/Log/Contextual/RoleHasLogger.pm100644001750001750 131713230423621 23766 0ustar00frewfrew000000000000Log-Contextual-0.008001/lib/Log/Contextual/Role/Routerpackage Log::Contextual::Role::Router::HasLogger; $Log::Contextual::Role::Router::HasLogger::VERSION = '0.008001'; # ABSTRACT: Abstract interface between loggers and logging code blocks use Moo::Role; requires 'has_logger'; 1; __END__ =pod =encoding UTF-8 =head1 NAME Log::Contextual::Role::Router::HasLogger - Abstract interface between loggers and logging code blocks =head1 VERSION version 0.008001 =head1 AUTHOR Arthur Axel "fREW" Schmidt =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2018 by Arthur Axel "fREW" Schmidt. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut SetLogger.pm100644001750001750 131713230423621 24006 0ustar00frewfrew000000000000Log-Contextual-0.008001/lib/Log/Contextual/Role/Routerpackage Log::Contextual::Role::Router::SetLogger; $Log::Contextual::Role::Router::SetLogger::VERSION = '0.008001'; # ABSTRACT: Abstract interface between loggers and logging code blocks use Moo::Role; requires 'set_logger'; 1; __END__ =pod =encoding UTF-8 =head1 NAME Log::Contextual::Role::Router::SetLogger - Abstract interface between loggers and logging code blocks =head1 VERSION version 0.008001 =head1 AUTHOR Arthur Axel "fREW" Schmidt =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2018 by Arthur Axel "fREW" Schmidt. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut WithLogger.pm100644001750001750 132313230423621 24163 0ustar00frewfrew000000000000Log-Contextual-0.008001/lib/Log/Contextual/Role/Routerpackage Log::Contextual::Role::Router::WithLogger; $Log::Contextual::Role::Router::WithLogger::VERSION = '0.008001'; # ABSTRACT: Abstract interface between loggers and logging code blocks use Moo::Role; requires 'with_logger'; 1; __END__ =pod =encoding UTF-8 =head1 NAME Log::Contextual::Role::Router::WithLogger - Abstract interface between loggers and logging code blocks =head1 VERSION version 0.008001 =head1 AUTHOR Arthur Axel "fREW" Schmidt =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2018 by Arthur Axel "fREW" Schmidt. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut