germania-kg/logger

Our Company's default logging solution: Pimple Service Provider for Logging with Monolog

4.4.4 2022-05-30 13:43 UTC

README

Germania KG · Logger

Default logging solution for our websites: Service Provider for Logging with Monolog 1 and 2.

Packagist PHP version Build Status Scrutinizer Code Quality Code Coverage Build Status

Installation with Composer

The major release 4 requires PHP 7.2+. The older release 3 supports Monolog 2.

$ composer require germania-kg/logger

Basics

Class LoggerServiceProvider is a Pimple ServiceProviderInterface and can be registered to any Pimple DI container (or array or \ArrayAccess). Its constructor requires the App or Logger name. – Optionally, the $_SERVER context may pe passed. An optional third parameter turns on IP address anonymizing:

<?php
use Germania\Logger\LoggerServiceProvider;

// Have your Pimple or Slim3 Container at hand
$dic = new \Pimple\Container;
$dic->register( new LoggerServiceProvider( "My App" );
               
// Alternatively, pass custom server data environment,
// and/or disable IP address anonymization               
$dic->register( new LoggerServiceProvider( "My App", $_SERVER, false ));

Pimple is not required.

The service providers cope with Arrays and \ArrayAccess instances as well.

Work with an array as base for another, more modern DI container. The register method amends and returns the passed array:

$dic = array();
$dic = (new LoggerServiceProvider( "My App" ))->register($dic)

Or pass another DI container which implements \ArrayAccess:

$dic = new MyContainer();
(new LoggerServiceProvider( "My App" ))->register($dic);

Services provided

This Monolog Logger instance is your PSR-3 Logger:

<?php
use Psr\Log\LoggerInterface;
use Monolog\Logger as MonologLogger;

// These are equal and refer to the same instance:
$logger = $dic[LoggerInterface::class];
$logger = $dic[MonologLogger::class];

// Deprecated service names
$logger = $dic['Monolog.Psr3Logger'];
$logger = $dic['Logger'];

echo get_class($logger);
// Monolog\Logger

This Monolog Handlers array is empty per default; it will be filled by one or more of the specialised Service Providers below.

Unless you want to add other handlers than those configured by the specialised Service providers you won't need to use these.

$handlers = $dic['Monolog.Handlers'];
print_r($handlers); // Array ...

This Monolog Processors array contains per default just Monolog's WebProcessor with ip, method and url extra context variables.

Unless you want to add other processors than those configured by the specialised Service providers you won't need to use these.

$processors = $dic['Monolog.Processors'];
print_r($processors); // Array ...

Adding processors to handlers

Monolog handlers are provided by Pimple services. Grab the handler instance and add another Monolog Processor by extending the service definition:

$dic->extend( \Monolog\Handler\RotatingFileHandler::class, function($handler, $dic) {
  $handler->pushProcessor( new \Monolog\Processor\IntrospectionProcessor );
  return $handler;
});

Specialised Service Providers

Log to Logfile

Class FileLoggerServiceProvider requires a logfile path. Optionally, you may pass a custom maximum number of logfiles (default: 30).

To set the loglevel, pass Monolog Loglevel constant or PSR-3 LogLevel (e.g. Monolog\Logger::DEBUG or \Psr\Log\LogLevel::INFO). Default is Monolog\Logger::DEBUG.

<?php
use Germania\Logger\FileLoggerServiceProvider;

// Use with Pimple
$dic = new \Pimple\Container();
$dic->register( new FileLoggerServiceProvider( "log/app.log" ));
$dic->register( new FileLoggerServiceProvider( "log/app.log", 30, \Monolog\Logger::DEBUG));

// Use with \ArrayAccess
$dic = new \Pimple\Container();
(new FileLoggerServiceProvider( "log/app.log" ))->register($dic);

// Use with array
$dic = array();
$dic = (new FileLoggerServiceProvider( "log/app.log" ))->register($dic);

Retrieve the Monolog handler

This handler is an instance of \Monolog\Handler\RotatingFileHandler

$handler = $dic['Monolog.Handlers.RotatingFileHandler'];
$handler = $dic[\Monolog\Handler\RotatingFileHandler::class];

Log to StdErr (stream)

Class StreamLoggerServiceProvider accepts optional parameters for an output stream (default: php://stderr) and a loglevel, either Monolog Loglevel constant or PSR-3 LogLevel (e.g. Monolog\Logger::DEBUG or \Psr\Log\LogLevel::INFO). Default is Monolog\Logger::DEBUG.

<?php
use Germania\Logger\StreamLoggerServiceProvider;

// Use with Pimple
$dic = new \Pimple\Container();
$dic->register( new StreamLoggerServiceProvider );
$dic->register( new StreamLoggerServiceProvider("php://stderr", \Monolog\Logger::WARNING) );

// Use with \ArrayAccess
$dic = new \Pimple\Container();
(new StreamLoggerServiceProvider())->register($dic);

// Use with array
$dic = array();
$dic = (new StreamLoggerServiceProvider())->register($dic);

Retrieve the Monolog handler

This handler is an instance of \Monolog\Handler\StreamHandler

$handler = $dic['Monolog.Handlers.StreamHandler'];
$handler = $dic[\Monolog\Handler\StreamHandler::class];

Log using SwiftMailer

This service requires service definitions for SwiftMailer and SwiftMailer.HtmlMessage. Germania KG's germania-kg/mailer will provide those.

$ composer require germania-kg/mailer

Class SwiftMailerLoggerServiceProvider accepts optional parameters for outer log level and inner loglevel, both either Monolog Loglevel constant or PSR-3 LogLevel (e.g. Monolog\Logger::DEBUG or \Psr\Log\LogLevel::INFO).

The outer loglevel (default: Monolog\Logger::WARNING) will trigger Monolog's FingersCrossedHandler which in turn uses Monolog's BufferHandler to send an log messages digest using Monolog's SwiftMailerHandler. Any log message in the email sent will be of inner loglevel upwards (default: Monolog\Logger::DEBUG)

<?php
use Germania\Logger\SwiftMailerLoggerServiceProvider;

// Use with Pimple
$dic = new \Pimple\Container();
$dic->register( new SwiftMailerLoggerServiceProvider );
$dic->register( new SwiftMailerLoggerServiceProvider( \Monolog\Logger::WARNING ));

// Use with \ArrayAccess
$dic = new \Pimple\Container();
(new SwiftMailerLoggerServiceProvider)->register($dic);

// Use with array
$dic = array();
$dic = (new SwiftMailerLoggerServiceProvider)->register($dic);

Retrieve the Monolog handler

Despite its name, the handler is actually an instance of Monolog\Handler\FingersCrossedHandler which wraps an instance of Monolog\Handler\BufferHandler which wraps an instance of Monolog\Handler\SwiftMailerHandler

$handler = $dic['Monolog.Handlers.SwiftMailerHandler'];
$handler = $dic[\Monolog\Handler\SwiftMailerHandler::class];

Log using CLImate Logger

This requires CLImate, available with Composer: league/climate

$ composer require league/climate

Class ClimateLoggerServiceProvider requires a Monolog Loglevel constant or PSR-3 LogLevel (e.g. Monolog\Logger::DEBUG or \Psr\Log\LogLevel::INFO).

<?php
use Germania\Logger\ClimateLoggerServiceProvider;

// Use with Pimple
$dic = new \Pimple\Container();
$dic->register( new ClimateLoggerServiceProvider( \Monolog\Logger::DEBUG ));

// Use with \ArrayAccess
$dic = new \Pimple\Container();
(new ClimateLoggerServiceProvider( \Monolog\Logger::DEBUG ))->register($dic);

// Use with array
$dic = array();
$dic = (new ClimateLoggerServiceProvider( \Monolog\Logger::DEBUG ))->register($dic);

Retrieve the Monolog handler

N.B. This is actually a Monolog\Handler\PsrHandlerinstance which wraps a Climate Logger League\CLImate\Logger

$handler = $dic['Climate.PsrLogger.MonologHandler'];

Log using BrowserConsole Logger

Class BrowserConsoleLoggerServiceProvider optionally accepts a Monolog Loglevel constant or PSR-3 LogLevel (e.g. Monolog\Logger::DEBUG or \Psr\Log\LogLevel::INFO). If left out or set to null, logging to browser console will be skipped.

<?php
use Germania\Logger\BrowserConsoleLoggerServiceProvider;

// Use with Pimple
$dic = new \Pimple\Container();
$dic->register( new BrowserConsoleLoggerServiceProvider );
$dic->register( new BrowserConsoleLoggerServiceProvider( \Monolog\Logger::INFO ));

// Use with \ArrayAccess
$dic = new \Pimple\Container();
(new ClimateLoggerServiceProvider)->register($dic);

// Use with array
$dic = array();
$dic = (new ClimateLoggerServiceProvider)->register($dic);

Retrieve the Monolog handler

The handler is an instance of Monolog\Handler\BrowserConsoleHandler

$handler = $dic['Monolog.Handlers.BrowserConsoleHandler'];
$handler = $dic[\Monolog\Handler\BrowserConsoleHandler::class];

Log to Microsoft Teams

Sends nicely formatted log messages to Microsoft Teams using Monolog's HtmlFormatter.

This requires CMDISP's monolog-microsoft-teams package, available via Composer: cmdisp/monolog-microsoft-teams.

$ composer require cmdisp/monolog-microsoft-teams "^1.2"

Class TeamsLoggerServiceProvider requires a Incoming Webhook URL string, and optionally a Monolog Loglevel constant or PSR-3 LogLevel (e.g. Monolog\Logger::DEBUG or \Psr\Log\LogLevel::INFO). Registering this ServiceProvider to a Pimple DI container will silently skip if the Webhook URL is empty.

<?php
use Germania\Logger\TeamsLoggerServiceProvider;
use Monolog\Logger;

$incoming_webhook_url="https://outlook.office.com/webhook/many-many-letters";

// Use with Pimple
$dic = new \Pimple\Container();
$dic->register( new TeamsLoggerServiceProvider( $incoming_webhook_url ));
$dic->register( new TeamsLoggerServiceProvider( $incoming_webhook_url, \Monolog\Logger::NOTICE ));

// Use with \ArrayAccess
$dic = new \Pimple\Container();
(new TeamsLoggerServiceProvider( $incoming_webhook_url ))->register($dic);

// Use with array
$dic = array();
$dic = (new TeamsLoggerServiceProvider( $incoming_webhook_url ))->register($dic);

Deprecation notice

Class Germania\Logger\HtmlFormattedTeamsLogHandler was an extension of the CMDISP\MonologMicrosoftTeams\TeamsLogHandler class and provided better log message formatting. As of the v1.1 release of CMDISP's monolog-microsoft-teams package, this extension is not needed any longer and will be removed as of major release 5.

Retrieve the Monolog handler

The handler is an instance of \CMDISP\MonologMicrosoftTeams\TeamsLogHandler

$handler = $dic['Monolog.Handlers.TeamsHandler'];
$handler = $dic[\CMDISP\MonologMicrosoftTeams\TeamsLogHandler::class];

Log to Slack channel

Class SlackLoggerServiceProvider requires Slack token, channel, and username. It optionally accepts a Monolog Loglevel constant or PSR-3 LogLevel (e.g. Monolog\Logger::DEBUG or \Psr\Log\LogLevel::INFO).

For more information on using Slack as Logger, see these links:

<?php
use Germania\Logger\SlackLoggerServiceProvider;



// Use with Pimple
$dic = new \Pimple\Container();
$dic->register( new SlackLoggerServiceProvider(
  $slack_token,
  $slack_channel,
  $slack_username,
  \Monolog\Logger::CRITICAL
));

// Use with \ArrayAccess
$dic = new \Pimple\Container();
(new SlackLoggerServiceProvider( ... ))->register($dic);

// Use with array
$dic = array();
$dic = (new SlackLoggerServiceProvider( ... ))->register($dic);

Retrieve the Monolog handler

The handler is an instance of \Monolog\Handler\SlackHandler

$handler = $dic['Monolog.Handlers.SlackHandler'];
$handler = $dic[\Monolog\Handler\SlackHandler::class];

Usage Example

<?php
use Germania\Logger\LoggerServiceProvider;
use Germania\Logger\FileLoggerServiceProvider;
use Monolog\Logger as Monolog;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;

// 1. Basic setup: Pimple
$dic = new \Pimple\Container();

$log_name     = "My App";
$anonymize_ip = true;
$server_data  = $_SERVER;

$dic->register( new LoggerServiceProvider(
  $log_name,
  $server_data,
  $anonymize_ip
));

// 2. The 'LoggerServiceProvider' alone won't do anything.
//    So, adding a specialized Service Provider is needed:
$max_files_count = 30;
$dic->register( new FileLoggerServiceProvider("log/app.log", 30, Monolog::DEBUG ));
$dic->register( new FileLoggerServiceProvider("log/app.log", 30, LogLevel::DEBUG ));

// 3. Now you can grab your PSR-3 Logger:
$logger = $dic[LoggerInterface::class];
$logger->info("Hooray!");

Development and Unit tests

$ git clone https://github.com/GermaniaKG/Logger.git
$ cd Logger
$ composer install

Either copy phpunit.xml.dist to phpunit.xml and adapt to your needs, or leave as is. Run PhpUnit test or composer scripts like this:

$ composer test
# or
$ vendor/bin/phpunit