stop being a caveman! use log::log4perl;

71
Stop Being A Caveman! use Log::Log4perl; by Eric Andreychek [email protected]

Upload: delila

Post on 05-Feb-2016

39 views

Category:

Documents


0 download

DESCRIPTION

Stop Being A Caveman! use Log::Log4perl;. by Eric Andreychek [email protected]. A long time ago... in a galaxy far, far away people debugged Perl code using print and warn statements some of these Perl coders even used the legendary and infamous Perl debugger - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Stop Being A Caveman! use Log::Log4perl;

Stop Being A Caveman!use Log::Log4perl;

by Eric [email protected]

Page 2: Stop Being A Caveman! use Log::Log4perl;

A long time ago...

in a galaxy far, far away

people debugged Perl code

using print and warn statements

some of these Perl coders even used

the legendary and infamous Perl debugger

these hard working Perl coders were known as ...

Cavemen

Page 3: Stop Being A Caveman! use Log::Log4perl;

Put These To Rest

Log4perl can help us make ideas like print, warn, and the Perl debugger artifacts of history

Page 4: Stop Being A Caveman! use Log::Log4perl;

Lets get this part out of the way...

● Log4perl lets you log stuff

● In Perl

● And it's really cool

Page 5: Stop Being A Caveman! use Log::Log4perl;

All You Need...

● Define a logging level

● Define where and what to log

● Use the (so-simple-it's-silly) interface

Page 6: Stop Being A Caveman! use Log::Log4perl;

Log Levels

fatal

error

warn

info

debug

Highest

Lowest

Page 7: Stop Being A Caveman! use Log::Log4perl;

Logger Objects

● Logger objects ($logger) do the work– Retrieved using Log4perl's get_logger() method

● Logging may occur in any sub in your program– No need to pass $logger to each sub

● Messy and Annoying

● Log4perl stores the logger object internally– A call to get_logger() returns that stored object

● Called a singleton

Page 8: Stop Being A Caveman! use Log::Log4perl;

Logging Example

$logger = get_logger();

# Logs when warn, info, or debug

$logger->warn(“Help me Obi-Wan, you're my only hope”);

# Remains dormant when error or fatal!

Page 9: Stop Being A Caveman! use Log::Log4perl;

Initializing Log4perl

# To set up logging, you could use the following:

use Log::Log4perl qw( :easy );

Log::Log4perl->easy_init( $ERROR );

Page 10: Stop Being A Caveman! use Log::Log4perl;

Not!We don't need no steenking “easy”

# To set up logging, you could use the following:

use Log::Log4perl qw( :easy );

Log::Log4perl->easy_init( $ERROR );

Page 11: Stop Being A Caveman! use Log::Log4perl;

Initializing Log4perl: /The Real (:?wo)?man's Way/

# Darth.pl

use Darth();use Log::Log4perl();

$config = get_my_config();Log::Log4perl::init( $config );

Page 12: Stop Being A Caveman! use Log::Log4perl;

Using Log4perl

package Darth;

use Log::Log4perl qw( get_logger );

sub new { my ( $class, $name ) = @_; my $logger = get_logger();

$logger->debug(“Creating Darth $name”);

return bless( { darth => $name }, $class );}

Page 13: Stop Being A Caveman! use Log::Log4perl;

Using Log4perl

sub get_lightsaber { my $self = shift; my $logger = get_logger();

$logger->debug(“Fetching lightsaber from the armory”);

my $saber = $self->_saber_type || “Red Single-Sided Saber”; $logger->warn(“Giving Darth his light saber: $saber”);

return $saber;}

Page 14: Stop Being A Caveman! use Log::Log4perl;

Log4perl Return Values

● Logging functions return the number of places they were logged– If message logged: return true– If no message logged: return undef– $total = $logger->warn( $message );

● Being at the WARN level doesn't necessarily mean $logger->warn($message) will be logged– Log4perl could suppress the message– A suppressed message would return undef

Page 15: Stop Being A Caveman! use Log::Log4perl;

Using Log4perl: Errors# Later on in darth.plmy $saber = $darth->get_lightsaber;

unless ( $saber ) { my $error = “Nothing to defend against the good guys with, ” .

“not even an electronic sausage!”

# This will often work, but tends to be a really bad idea $logger->fatal( $error ) && die( $error )

# This utility method doesn't depend on the return value of # $logger->fatal, it will always die $logger->logdie( $error )}

Page 16: Stop Being A Caveman! use Log::Log4perl;

Future of Internet Keyboards

Page 17: Stop Being A Caveman! use Log::Log4perl;

Configuring The Beast

● Configuring Log4perl: TMTOWTDI– Perl– Config files– Both

Page 18: Stop Being A Caveman! use Log::Log4perl;

Config Files (my favorite)

use Log::Log4perl qw( get_logger );

Log::Log4perl::init( “log4perl.conf” );

my $logger = get_logger();

Page 19: Stop Being A Caveman! use Log::Log4perl;

Config File ExampleContents of log4perl.conf

log4perl.logger = INFO, Screen

log4perl.appender.Screen = Log::Dispatch::Screen

log4perl.appender.Screen.layout = SimpleLayout

Page 20: Stop Being A Caveman! use Log::Log4perl;

Config File: CategoryThis config applies to my what?

log4perl.logger = INFO, Screen

log4perl.appender.Screen = Log::Dispatch::Screen

log4perl.appender.Screen.layout = SimpleLayout

Page 21: Stop Being A Caveman! use Log::Log4perl;

Config File: AppenderYou want me to log where?

log4perl.logger = INFO, Screen

log4perl.appender.Screen = Log::Dispatch::Screen

log4perl.appender.Screen.layout = SimpleLayout

Page 22: Stop Being A Caveman! use Log::Log4perl;

Config File: Message LayoutYou want me to log how?

log4perl.logger = INFO, Screen

log4perl.appender.Screen = Log::Dispatch::Screen

log4perl.appender.Screen.layout = SimpleLayout

Page 23: Stop Being A Caveman! use Log::Log4perl;

Appender (log) Methods

● Log4perl uses Log::Dispatch to perform logging– Log::Dispatch supports a number of locations

● ApacheLog● DBI● Email● Files● STDOUT / STDERR (Screen)● Syslog● Jabber● Anything else you write

Page 24: Stop Being A Caveman! use Log::Log4perl;

Appender Location: Log to FileChange From Screen to File

log4perl.logger = INFO, Screen

log4perl.appender.Screen = Log::Dispatch::File

log4perl.appender.Screen.Filename = myfile.log

log4perl.appender.Screen.layout = SimpleLayout

Page 25: Stop Being A Caveman! use Log::Log4perl;

Appender NameShould Make Sense!

log4perl.logger = INFO, FileLog

log4perl.appender.FileLog = Log::Dispatch::File

log4perl.appender.FileLog.Filename = myfile.log

log4perl.appender.FileLog.layout = SimpleLayout

Page 26: Stop Being A Caveman! use Log::Log4perl;

Logging To Multiple LocationsChange to File and Screen with Two Appenders

log4perl.logger = INFO, Screen, FileLog

log4perl.appender.Screen = Log::Dispatch::Screen

log4perl.appender.Screen.layout = SimpleLayout

log4perl.appender.FileLog = Log::Dispatch::File

log4perl.appender.FileLog.filename = myfile.log

log4perl.appender.FileLog.layout = SimpleLayout

Page 27: Stop Being A Caveman! use Log::Log4perl;

Changing The Log Format

log4perl.logger = INFO, Screen

log4perl.appender.Screen = Log::Dispatch::Screen

log4perl.appender.Screen.layout = PatternLayout

log4perl.appender.Screen.layout.ConversionPattern=%F %L: %m%n

Page 28: Stop Being A Caveman! use Log::Log4perl;

Available Placeholders (16 total)

%c Category of the logging event. %C Fully qualified package (or class) name of the caller %d Current date in yyyy/MM/dd hh:mm:ss format %F File where the logging event occurred %H Hostname %l Fully qualified name of the calling method followed by the callers source the file name and line number between parentheses. %L Line number within the file where the log statement was issued %m The message to be logged %M Method or function where the logging request was issued %n Newline (OS-independent) %p Priority of the logging event %P pid of the current process %r Number of milliseconds elapsed from program start to logging event %x The topmost NDC (see below) %X{key} The entry 'key' of the MDC (see below) %% A literal percent (%) sign

Page 29: Stop Being A Caveman! use Log::Log4perl;

Custom Placeholders

# Define a conversion specifier (cspec) in the config file:

log4perl.logger = INFO, Screen

log4perl.appender.Screen = Log::Dispatch::Screen

log4perl.appender.Screen.layout = PatternLayout

log4perl.appender.Screen.layout.ConversionPattern=%O: %F %L %m%n

log4perl.PatternLayout.cspec.O = sub { return "OS $^O" }

Page 30: Stop Being A Caveman! use Log::Log4perl;

Perl Code In Config File# Programmatically get the filename and layout

log4perl.logger = INFO, FileLog

log4perl.appender.FileLog = Log::Dispatch::File

log4perl.appender.FileLog.Filename = \

sub { getFileName(); }

log4perl.appender.FileLog.layout = \

sub { getLayout(); }

Page 31: Stop Being A Caveman! use Log::Log4perl;

Code in the Config File: Notes

● We can put any code into the config file● This code is run within the main namespace● Some might consider this a security risk

– This feature can be disabled with: $Log::Log4perl::ALLOW_CODE_IN_CONFIG_FILE = 0;

Page 32: Stop Being A Caveman! use Log::Log4perl;

Take a Break

Everyone take a break, and allow Patrick a few moments to catch up

Page 33: Stop Being A Caveman! use Log::Log4perl;

Putting Categories to UseGoing Beyond the System Defined Root Logger

● One of Log4perl's key features is categories– Enable extra logging for just one portion of your

application– Remainder of application produces typical output

● Category name: often the name of the current package / class

● You've seen the default, root category– To use your own, pass a parameter into get_logger()

$logger = get_logger( $category_name );

Page 34: Stop Being A Caveman! use Log::Log4perl;

Using Categories: Config File

# This is the root category / logger

log4perl.logger = WARN, Screen

# Create a new category like so:

log4perl.logger.CategoryName = DEBUG, Screen

Page 35: Stop Being A Caveman! use Log::Log4perl;

Using Categories: Class ExampleSkywalker Class Hierarchy

Page 36: Stop Being A Caveman! use Log::Log4perl;

Log Using Multiple Categories● Leia knows what she wants● Vader is set in his ways● We can put these two at a normal log level of “warn”● Luke has issues● He should be put at a log level of “debug”

Page 37: Stop Being A Caveman! use Log::Log4perl;

Multiple Categories ExampleTwo categories: Log Skywalkers to Screen

log4perl.logger.Skywalker = WARN, Screen

log4perl.logger.Skywalker.Luke = DEBUG, Screen

log4perl.appender.Screen = Log::Dispatch::Screen

log4perl.appender.Screen.layout = SimpleLayout

Page 38: Stop Being A Caveman! use Log::Log4perl;

Multiple Categories ExampleLog base class to File, sub class to Screen and File

log4perl.logger.Skywalker = WARN, FileLog

log4perl.logger.Skywalker.Luke = DEBUG, Screen

log4perl.appender.FileLog = Log::Dispatch::File

log4perl.appender.FileLog.layout = SimpleLayout

log4perl.appender.FileLog.Filename = myfile.log

log4perl.appender.Screen = Log::Dispatch::Screen

log4perl.appender.Screen.layout = SimpleLayout

Page 39: Stop Being A Caveman! use Log::Log4perl;

Tell Log4perl Your CategoryPass in Your Class Name

● In package Skywalker: my $logger = get_logger( 'Skywalker' );

● In package Skywalker::Leia: my $logger = get_logger( 'Skywalker::Leia' );

● In package Skywalker::Luke: my $logger =

get_logger( 'Skywalker::Luke' );

● Or just... my $logger = get_logger( __PACKAGE__ );

Page 40: Stop Being A Caveman! use Log::Log4perl;

Now, Pay Attention!

Page 41: Stop Being A Caveman! use Log::Log4perl;

Important Logging Behavior

● Once a logger decides to log a message, it does a few things

● The message is first logged using each appender attached to that logger

● Then, the message is unconditionally logged using every appender attached to the logger's parents

Page 42: Stop Being A Caveman! use Log::Log4perl;

Important Logging BehaviorExample Config File

log4perl.logger = ERROR, Syslog

log4perl.logger.Skywalker.Luke = DEBUG, Screen

log4perl.appender.Syslog = Log::Dispatch::Syslog

log4perl.appender.Syslog.layout = SimpleLayout

log4perl.appender.Screen = Log::Dispatch::Screen

log4perl.appender.Screen.layout = SimpleLayout

Page 43: Stop Being A Caveman! use Log::Log4perl;

Important Logging Behavior

ERROR(inherited)

Log::Dispatch::Syslog

Skywalker

Skywalker::Luke Skywalker::Leia

ERROR(inherited)

DEBUG

Log::Dispatch::Screen

root logger

ERROR

Page 44: Stop Being A Caveman! use Log::Log4perl;

What This Means

Lets take a look at how logging will work throughout the hierarchy

Page 45: Stop Being A Caveman! use Log::Log4perl;

Logging Behavior: root logger Category root logger (when no category is defined) Properties Defines level: ERROR, location: Syslog

Code $logger->error( $light_saber );

Result Logs $light_saber to a syslog

Page 46: Stop Being A Caveman! use Log::Log4perl;

Logging Behavior:Skywalker, Skywalker::Leia

Category Skywalker and Skywalker::Leia Properties Inherits ERROR and Syslog from root logger

Code $logger->error( $light_saber );

Result Logs $light_saber to syslog

Page 47: Stop Being A Caveman! use Log::Log4perl;

Logging Behavior: Skywalker::Luke

Category Skywalker::Luke

Properties Defines level: DEBUG, location: Screen

Code $logger->error( $light_saber );

Result Logs $light_saber to the screen Logs $light_saber to syslog

Page 48: Stop Being A Caveman! use Log::Log4perl;

Logging Behavior: Skywalker::Luke

Category Skywalker::Luke

Properties Defines level: DEBUG, location: Screen

Code $logger->debug( $light_saber );

Result (even though parents are at ERROR) Logs $light_saber to the screen Logs $light_saber to syslog

Page 49: Stop Being A Caveman! use Log::Log4perl;

Logging Behavior

● Might be unnecessarily duplicating the logs– Luke's debug messages all going to syslog

● Take advantage of Log4perl!– Continue to log all debugging messages to the screen– Be more picky about what gets logged to syslog

● Should all of Skywalker::Luke's debugging messages be in our system logs?

– Remember, Luke has a lot of issues

Page 50: Stop Being A Caveman! use Log::Log4perl;

Preventing Duplicate Logs

● If this behavior isn't what you want, change it:– Set the additivity of a category to zero

● Prevents messages from bubbling up● Do this to the Skywalker::Luke category

– Set the threshold of an appender to some log level● Defines a minimum log level for oncoming messages● Do this to the root or parent category● Can also set a system-wide default threshold

Page 51: Stop Being A Caveman! use Log::Log4perl;

Setting AdditivityPrevent The Message From Bubbling Uplog4perl.logger = ERROR, Syslog

log4perl.logger.Skywalker.Luke = ERROR, Screen

log4perl.additivity.Skywalker.Luke = 0

log4perl.appender.Syslog = Log::Dispatch::Syslog

log4perl.appender.Syslog.layout = SimpleLayout

log4perl.appender.Screen = Log::Dispatch::Screen

log4perl.appender.Screen.layout = SimpleLayout

Page 52: Stop Being A Caveman! use Log::Log4perl;

Setting a ThresholdDefine minimum log level of ERRORlog4perl.logger = ERROR, Syslog

log4perl.logger.Skywalker.Luke = DEBUG, Screen

log4perl.appender.Syslog = Log::Dispatch::Syslog

log4perl.appender.Syslog.layout = SimpleLayout

log4perl.appender.Syslog.Threshold = ERROR

log4perl.appender.Screen = Log::Dispatch::Screen

log4perl.appender.Screen.layout = SimpleLayout

Page 53: Stop Being A Caveman! use Log::Log4perl;

One Last Look

● If a logger decides to fire, it sends the message to all of it's appenders

● The logger then has the message bubble up the hierarchy to hit all the other appenders on the way up

Page 54: Stop Being A Caveman! use Log::Log4perl;

Important Logging Behavior

This behavior effects our earlier examples!

Page 55: Stop Being A Caveman! use Log::Log4perl;

Preventing Duplicate LogsTwo categories: Log Skywalkers to Screen

# Does this previous example do what you think?

log4perl.logger.Skywalker = WARN, Screen

log4perl.logger.Skywalker.Luke = DEBUG, Screen

log4perl.appender.Screen = Log::Dispatch::Screen

log4perl.appender.Screen.layout = SimpleLayout

Page 56: Stop Being A Caveman! use Log::Log4perl;

Preventing Duplicate LogsUse Additivity To Your Advantage

log4perl.logger.Skywalker = WARN, Screen

log4perl.logger.Skywalker.Luke = DEBUG, Screen

log4perl.additivity.Skywalker.Luke = 0

log4perl.appender.Screen = Log::Dispatch::Screen

log4perl.appender.Screen.layout = SimpleLayout

Page 57: Stop Being A Caveman! use Log::Log4perl;

Preventing Duplicate Logs: FiltersYoda Filter: Do or do not, there is no “try”

log4perl.logger.Skywalker.Luke = DEBUG, Screen

log4perl.appender.Screen = Log::Dispatch::Screen

log4perl.appender.Screen.layout = SimpleLayout

log4perl.appender.Screen.filter = MyFilter

log4perl.filter.MyFilter = sub { /try/i }

log4perl.filter.MyFilter.AcceptOnMatch = false

Page 58: Stop Being A Caveman! use Log::Log4perl;

this door 0wnz j00

Page 59: Stop Being A Caveman! use Log::Log4perl;

Performance Penalties

● Logging has a (small) price tag– Decision to log is made at runtime

● Calls are optimized to run as fast as possible● There are still things you can do to help

Page 60: Stop Being A Caveman! use Log::Log4perl;

Bad Performance Example

# Current Log Level: WARN# (doesn't actually log)

use Data::Dumper;$logger->debug( “Contents: ”, Dumper( %config ));

Page 61: Stop Being A Caveman! use Log::Log4perl;

Optimizing Performance: Example 1

# Pass in a subroutine reference

$logger->debug( “Contents: ”, sub { use Data::Dumper; Dumper( %config ) });

Page 62: Stop Being A Caveman! use Log::Log4perl;

Optimizing Performance: Example 2

# Is it necessary to pass any parameters at all?

if ( $logger->is_debug ) { $logger->debug( “Array Contents: ”, @big_array );}

Page 63: Stop Being A Caveman! use Log::Log4perl;

Log4perl

● Log4perl has a boatload of features– Different log levels– Multiple logging destinations– Multiple categories

● There's more!

Page 64: Stop Being A Caveman! use Log::Log4perl;

Resources● Log4perl Homepage

http://log4perl.sourceforge.net

● Log4perl Documentation

http://log4perl.sourceforge.net/releases/LogLog4perl/docs/html/Log/Log4perl.htm

● Perl.com Article: Retire Your Debugger

http://www.perl.com/pub/a/2002/09/11/log4perl.html

● Most Recent Version of this Presentation

http://openthought.org

Page 65: Stop Being A Caveman! use Log::Log4perl;

Thank You

Page 66: Stop Being A Caveman! use Log::Log4perl;

More Cool Stuff(You've reached the bonus slides!)

Page 67: Stop Being A Caveman! use Log::Log4perl;

Automatically Rotate Logs

# Rotate logs daily, keep no more than 5 files log4perl.logger = WARN, Logfile log4perl.appender.Logfile = Log::Dispatch::FileRotate log4perl.appender.Logfile.filename = /var/log/log4perl.log log4perl.appender.Logfile.max = 5 log4perl.appender.Logfile.DatePattern = yyyy-MM-dd log4perl.appender.Logfile.TZ = EST log4perl.appender.Logfile.layout = SimpleLayout

Page 68: Stop Being A Caveman! use Log::Log4perl;

Reloading The Config

# To load the config, we originally wrote:

Log::Log4perl::init( “config.conf” );

# We can also check the config at regular intervals:

Log::Log4perl::init_and_watch( “config.conf”, 60 );

Page 69: Stop Being A Caveman! use Log::Log4perl;

Remote Config

# We can also use:

my $config = “http://openthought.org/config.pl”;

Log::Log4perl::init( $config );

# (this doesn't work with init_and_watch... yet)

Page 70: Stop Being A Caveman! use Log::Log4perl;

Decisions Based on Log LevelApplication Which Sends Email

my $email_address;

if ( $logger->is_debug ) { $email_address = “test_account”;}else { $email_address = “real_account”;}

send_email( $email_address );

Page 71: Stop Being A Caveman! use Log::Log4perl;

More Decisions Based On Log LevelDatabase Application

if ( $logger->is_debug ) { $logger->debug( dumper(%data) ); return; # Don't even touch the database}elsif ( $logger->is_info ) { $database = “Test”;}else { $database = “Production”}

$self->insert_into_database( %data );