Usage of the logging module

See this easy examples.

Simple logging

Simple logging

use LoxBerry::Log;
 
# Create a logging object
my $log = LoxBerry::Log->new ( name => 'daemon' );
 
# We start the log. It will print and store some metadata like time, version numbers, and the string as log title 
LOGSTART "Daemon started";
 
# This are the logging shortcuts, ascending from lowest to highest:
LOGDEB "This is debugging";               # Loglevel 7
LOGINF "Infos in your log";               # Loglevel 6
LOGOK "Everything is OK";                 # Loglevel 5
LOGWARN "Hmmm, seems to be a Warning";    # Loglevel 4
LOGERR "Error, that's not good";          # Loglevel 3
LOGCRIT "Critical, no fun";               # Loglevel 2
 
# You may want to change the log title to be more specific, e.g. after reading your config file
LOGTITLE "Daemon for backup started";
 
 
# To indicate, that your script has finished (with errors or not), close the logging session
LOGEND "Operation finished sucessfully.";

For this example, a logfile is created in your plugin log folder. It's name is the timestamp and name 'daemon' (e.g. "20171222_093157_235_daemon.log) - you can create different logs for different tasks - therefore provide different names.

For simple logging you possibly be ok with LOGINF, LOGERR and LOGDEB. It is common practice to use a LOGCRIT if your script needs to terminate early because of an unrecoverable error. 

Are line feeds (\n) required?

No, LoxBerry::Log automatically appends the linefeed.

Do I need to "if" away the debug messages?

You don't need to care about log levels at all! Simply use the severity keywords (LOGDEB, LOGINF, LOGOK and so on, as you need it. LogBerry::Log entries are filtered by the Plugin loglevel that is defined by the user at the Plugins system widget (where you install plugins). Therefore, you even don't need to provide your own loglevel setting in the plugin. Default log level after a plugin installation is 3 (Errors or more critical).

If you want to change or override the log level set by the user, simply use this, after you have created your log object:

$log->loglevel(5);

But we advise you not to hardcode the loglevel. Let the user decide.

For your first logging steps, you can stop reading here, and start logging NOW. You always can test your logfiles in the Log Manager widget.

I want to pipe a system() output to the log

Nothing easier than that!

You always can request the logfile name to use outside of LoxBerry::Log:

LOGINF "Current directory entries:";
 
my $logfile = $log->filename();
system("ls -l >> $logfile");
 
LOGOK "All files listed.";

From LoxBerry V1.2.5 the logging feature does not keep open the logfile. At any time you can pipe output to that filename.

For plugins on LoxBerry < V1.2.5 it is required to always close the file before every pipe:

LOGINF "Current directory entries:";
 
my $logfile = $log->close();
system("ls -l >> $logfile");
 
$log->open();
LOGOK "All files listed.";

The "old" syntax (2st codeblock) is still supported in V1.2.5, no code needs to be changed.

I want to use a command that directly writes to a filehandle

Simply query the logfile filehandle:

my $fh = $log->filehandle;

I need two log objects in one session

You are a logging king! Therefore, you can use multiple logfiles in one session. 

As we have two logfiles now, you need to directly talk to the log objects.

If you use the log objects directly, it is required to call the log functions in brackets, e.g. $log->OK("Message") instead of LOGOK "Message"

Simple logging

use LoxBerry::Log;
 
# Create a logging object
my $logone = LoxBerry::Log->new ( name => 'daemon' );
$logone->START("Daemon log started.");
 
# Not enough - create a second
my $logtwo = LoxBerry::Log->new (name => 'saruman' );
$logtwo->START("Saruman log started.");
 
# Now we start to log, ascending from lowest to highest:
$logone->DEB("This is debugging");
$logtwo->INF("Infos in your log");
$logone->OK("Everything is OK");
$logtwo->WARN("Hmmm, seems to be a Warning");
$logone->ERR("Error, that's not good");
# Be aware, the object functions do not use the LOG prefix.
# But the easy logging keywords still work - with the first logfile.
# Goes to $log
LOGCRIT "Critical, no fun";
LOGALERT "Alert, ring ring!";
LOGEMERGE "Emergency, for really really hard issues";
 
# If you log in bulks, you can switch the default logfile:
$logtwo->default;
LOGOK "This now goes to $logtwo";

How can I hand over the same log from script to script

You mean, "beyond the limit"?

# Script 1
my $logfile = $log->close;
system("myscript2.pl $logfile");
 
# Script 2
# Do some CGI or GetOpt stuff to get the parameter
my $log = LoxBerry::Log->new ( name => "daemon", filename => $filename, append => 1 );

Providing the same name, the filename got from the first script, and the append setting, LoxBerry::Log will continue to log to the same log in your script number 2.

Starting with LoxBerry V1.2.5, there is an easier way to hand over a logfile:

# Script 1
LOGINF "Preparing handover to script 2..."; 
my $dbkey = $log->dbkey;
system("myscript2.pl $dbkey");
 
# Script 2
# Do some CGI or GetOpt stuff to get the parameter
my $log = LoxBerry::Log->new ( dbkey => $dbkey );
LOGOK "Script 2 is now running in the same logfile";

The second script recovers all the options set in the first script. No LOGEND is needed in Script 1, and no LOGSTART is needed in Script 2. Script 2 is set to append=1 automatically, independent of the setting in script 1.

For this handover, it is not allowed to trigger LOGEND in script 1, as this would finalize the logging session.

I want also output to STDOUT or STDERR

That's possible!

Simple logging

use LoxBerry::Log;
 
# Create a logging object
my $log = LoxBerry::Log->new ( name => 'daemon' );
 
# Enable STDERR
$log->stderr(1);
 
# Enable STDOUT
$log->stdout(1);
 
# Disable writing to the logfile
$log->nofile(1);

Default is:

  • nofile = 0 (→ will write a logfile)
  • stderr = 0 (→ no stderr output)
  • stdout = 0 (→ no stdout output)

These three settings are independent to each other - none of the settings disables another setting. Example: strerr=1 and stdout=1 will print each line twice in the console.

This especially may be handy during plugin development, to get the errors directly to STDERR instead of checking new logfiles all the time.

You can set these settings also directly in the new constructor, so you can use LoxBerry::Log even if you don't need a logfile at all! ( stderr => 1, nofile => 1);

Do not use stdout=1 in web scripts, as the break the html and will lead to a server ERROR 500. 

Log Title (V1.2.5 and above)

The message sent with the LOGSTART event sets the log title that is displayed in the logfile overview.

You might have situations where you want a more specific title, but the LOGSTART event is too early (e.g. config file parsing is later in your script). 

Therefore, you can use the $log→logtitle function, or the LOGTITLE shortcut, to change the message listed in the logfile overview. This event is not written to the logfile.

Simple logging

use LoxBerry::Log;
 
# Create a logging object
my $log = LoxBerry::Log->new ( name => 'daemon' );
LOGSTART "Daemon Processing";
 
# ... read something from the config file ...
 
LOGTITLE "Daemon Processing for $process";

The auto-raise function

Our recommendations:

  • Use the levels LOGERR, LOGWARN, LOGOK, LOGINF for normal logging
  • Use level LOGDEB for your debugging messages.
  • Use the level LOGCRIT if your program has to terminate early.
  • Do currently not use LOGALERT and LOGEMERGE
  • Do not use higher, untruthfully severity as needed just because you want to give nice information. If the user requests more information, he will configure a higher loglevel.

Auto-raise is a nice feature:

  • If your program has to terminate, send a LOGCRIT entry.
  • In this case, loglevel automatically switches to 6.
  • After LOGCRIT, you can give the user some more information about the state with every severity up to 6, ignoring the loglevel set by the user.

Put a timestamp to every log file

You can add a timestamp to every log entry if you add an addtime => 1 parameter to the constructor:

Simple logging

# Create a logging object
my $log = LoxBerry::Log->new ( name => 'daemon', addtime => 1 );

You are a LoxBerry-Core developer (not Plugin developer)

In the Plugin environment, most things are assumed automatically. For logging with LoxBerry-Core, a bit more information is needed in the constructor:

Simple logging

use LoxBerry::Log;
 
# Create a logging object
my $log = LoxBerry::Log->new ( name => 'cronjob', package => 'Update', loglevel => 7);
 
# Now we start to log, ascending from lowest to highest:
LOGSTART "Update by cron job";
LOGDEB "This is debugging";
LOGINF "Infos in your log";
LOGOK "Everything is OK";
# that's equal....

If no logdir parameter is used, log files are stored directly in $lbslogdir.

If you provide a logdir setting, the log is created in that directory with naming <currtime>_name.log.

If you always want to log to the same file, omit the logdir setting, and provide the filename parameter. To append to the same log, use append => 1

Additionally to the name that can be used for different logfiles, LoxBerry::Log defines logging packages with the package parameter. This can be, for example, "Plugin updates" or "System". The name is a second layer to have different log sources in a package. Plugins have a package as well, but this is automatically set to the plugin name. For core developers, the package and name are mandatory parameters.

Create an easy system log object that always appends to an existing (or new) log

Simple logging

use LoxBerry::Log;
 
# Create a logging object
my $log = LoxBerry::Log->new ( 
        name => 'cronjob', 
        package => 'Update',  
        loglevel => 7,
        filename => "$lbslogdir/mylogfile.log",
        append => 1,
);
# Now we start to log, ascending from lowest to highest:
LOGSTART "Update by cron job"; 
LOGDEB "This is debugging";
LOGINF "Infos in your log";
LOGOK "Everything is OK";
# that's equal....
LOGEND "Finished";

Log files in your user interface 

LoxBerry Compatibility

The following features are available beginning with LoxBerry V1.2.1. Set this minimum version in your plugin.cfg

Logfile button

You can use the function logfile_button_html to display a button to the logfile in your webinterface:

use LoxBerry::Web;
print LoxBerry::Web::logfile_button_html( NAME => 'cronjob' );

A click to the button will show the latest logfile you created above with LoxBerry::Log::new ( name ⇒ 'cronjob' );

With several parameters you can customize the design of the button, or you may directly call a specific filename instead of a group name.

See LoxBerry::Web::logfile_button_html for details.

Loglist button

If you want to provide not only a button to a single log, but want to present a list of all of your logfiles to your users, you can create a button to a list of your logfiles:

use LoxBerry::Web;
print LoxBerry::Web::loglist_button_html(); # List all logfiles
print LoxBerry::Web::loglist_button_html( NAME => 'cronjob' ); # List all logfiles of group name 'cronjob'

The first example lists all logfile you created with LoxBerry::Log (or LBLog from PHP) within your plugin.

The second example only lists the logfiles of the group name 'cronjob'. 

You also can modify the design of the button with additional parameters. See LoxBerry::Web::loglist_button_html.

If you don't want a button, but directly link to the loglist (e.g. in the Navigation Bar), you can call loglist_url.  It returns the complete URL to the loglist.

Again, you can link to all logs of your plugin, or filter by the group name.

use LoxBerry::Web;
my $url = LoxBerry::Web::loglist_url(); # Link to all logfiles
my $url = LoxBerry::Web::loglist_url( NAME => 'cronjob' ); # Link to all logfiles of group name 'cronjob'

You can use the link url in the navigation bar, or provide your own styled link somewhere in your webinterface.