mirror of
https://github.com/Seldaek/monolog.git
synced 2025-08-08 14:16:42 +02:00
@@ -178,6 +178,7 @@ Formatters
|
||||
----------
|
||||
|
||||
- _LineFormatter_: Formats a log record into a one-line string.
|
||||
- _HtmlFormatter_: Used to format log records into a human readable html table, mainly suitable for emails.
|
||||
- _NormalizerFormatter_: Normalizes objects/resources down to strings so a record can easily be serialized/encoded.
|
||||
- _ScalarFormatter_: Used to format log records into an associative array of scalar values.
|
||||
- _JsonFormatter_: Encodes a log record into json.
|
||||
@@ -196,6 +197,7 @@ Processors
|
||||
- _MemoryPeakUsageProcessor_: Adds the peak memory usage to a log record.
|
||||
- _ProcessIdProcessor_: Adds the process id to a log record.
|
||||
- _UidProcessor_: Adds a unique identifier to a log record.
|
||||
- _GitProcessor_: Adds the current git branch and commit to a log record.
|
||||
|
||||
Utilities
|
||||
---------
|
||||
|
@@ -47,6 +47,7 @@ class ElasticaFormatter extends NormalizerFormatter
|
||||
public function format(array $record)
|
||||
{
|
||||
$record = parent::format($record);
|
||||
|
||||
return $this->getDocument($record);
|
||||
}
|
||||
|
||||
@@ -71,7 +72,7 @@ class ElasticaFormatter extends NormalizerFormatter
|
||||
/**
|
||||
* Convert a log message into an Elastica Document
|
||||
*
|
||||
* @param array $record Log message
|
||||
* @param array $record Log message
|
||||
* @return Document
|
||||
*/
|
||||
protected function getDocument($record)
|
||||
@@ -80,6 +81,7 @@ class ElasticaFormatter extends NormalizerFormatter
|
||||
$document->setData($record);
|
||||
$document->setType($this->type);
|
||||
$document->setIndex($this->index);
|
||||
|
||||
return $document;
|
||||
}
|
||||
}
|
||||
|
@@ -10,14 +10,16 @@
|
||||
|
||||
namespace Monolog\Formatter;
|
||||
|
||||
use Monolog\Logger;
|
||||
|
||||
/**
|
||||
* Formats incoming records into a HTML table
|
||||
* Formats incoming records into an HTML table
|
||||
*
|
||||
* This is especially useful for html email logging
|
||||
*
|
||||
* @author Tiago Brito <tlfbrito@gmail.com>
|
||||
*/
|
||||
class HtmlEmailFormatter extends NormalizerFormatter
|
||||
class HtmlFormatter extends NormalizerFormatter
|
||||
{
|
||||
/**
|
||||
* Translates Monolog log levels to html color priorities.
|
||||
@@ -44,14 +46,14 @@ class HtmlEmailFormatter extends NormalizerFormatter
|
||||
/**
|
||||
* Creates an HTML table row
|
||||
*
|
||||
* @param $th string Row header content
|
||||
* @param string $td Row standard cell content
|
||||
* @param string $th Row header content
|
||||
* @param string $td Row standard cell content
|
||||
* @return string
|
||||
*/
|
||||
private function addRow($th, $td = ' ')
|
||||
{
|
||||
$th = htmlspecialchars($th);
|
||||
$td = '<pre>'.htmlspecialchars($td).'</pre>';
|
||||
$th = htmlspecialchars($th, ENT_NOQUOTES, 'UTF-8');
|
||||
$td = '<pre>'.htmlspecialchars($td, ENT_NOQUOTES, 'UTF-8').'</pre>';
|
||||
|
||||
return "<tr style=\"padding: 4px;spacing: 0;text-align: left;\">\n<th style=\"background: #cccccc\" width=\"100px\">$th:</th>\n<td style=\"padding: 4px;spacing: 0;text-align: left;background: #eeeeee\">".$td."</td>\n</tr>";
|
||||
}
|
||||
@@ -59,14 +61,14 @@ class HtmlEmailFormatter extends NormalizerFormatter
|
||||
/**
|
||||
* Create a HTML h1 tag
|
||||
*
|
||||
* @param $title string Text to be in the h1
|
||||
* @param $level integer Error level
|
||||
* @param string $title Text to be in the h1
|
||||
* @param integer $level Error level
|
||||
* @return string
|
||||
*/
|
||||
private function addTitle($title, $level)
|
||||
{
|
||||
$title = htmlspecialchars($title);
|
||||
|
||||
$title = htmlspecialchars($title, ENT_NOQUOTES, 'UTF-8');
|
||||
|
||||
return '<h1 style="background: '.$this->logLevels[$level].';color: #ffffff;padding: 5px;">'.$title.'</h1>';
|
||||
}
|
||||
/**
|
||||
@@ -77,15 +79,18 @@ class HtmlEmailFormatter extends NormalizerFormatter
|
||||
*/
|
||||
public function format(array $record)
|
||||
{
|
||||
$output = $this->addTitle($this->convertToString($record['level_name']), $record['level']);
|
||||
$output = $this->addTitle($record['level_name'], $record['level']);
|
||||
$output .= '<table cellspacing="1" width="100%">';
|
||||
|
||||
$output .= $this->addRow('Message', $this->convertToString($record['message']));
|
||||
$output .= $this->addRow('Generated at', $this->convertToString($record['datetime']));
|
||||
$output .= $this->addRow('Level', $this->convertToString($record['level']));
|
||||
$output .= $this->addRow('Channel', $this->convertToString($record['channel']));
|
||||
$output .= $this->addRow('Context', $this->convertToString($record['context']));
|
||||
$output .= $this->addRow('Extra', $this->convertToString($record['extra']));
|
||||
$output .= $this->addRow('Message', (string) $record['message']);
|
||||
$output .= $this->addRow('Time', $record['datetime']->format('Y-m-d\TH:i:s.uO'));
|
||||
$output .= $this->addRow('Channel', $record['channel']);
|
||||
if ($record['context']) {
|
||||
$output .= $this->addRow('Context', $this->convertToString($record['context']));
|
||||
}
|
||||
if ($record['extra']) {
|
||||
$output .= $this->addRow('Extra', $this->convertToString($record['extra']));
|
||||
}
|
||||
|
||||
return $output.'</table>';
|
||||
}
|
@@ -34,7 +34,7 @@ class ScalarFormatter extends NormalizerFormatter
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
protected function normalizeValue($value)
|
||||
|
@@ -39,9 +39,9 @@ class DynamoDbHandler extends AbstractProcessingHandler
|
||||
|
||||
/**
|
||||
* @param DynamoDbClient $client
|
||||
* @param string $table
|
||||
* @param integer $level
|
||||
* @param boolean $bubble
|
||||
* @param string $table
|
||||
* @param integer $level
|
||||
* @param boolean $bubble
|
||||
*/
|
||||
public function __construct(DynamoDbClient $client, $table, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
@@ -70,7 +70,7 @@ class DynamoDbHandler extends AbstractProcessingHandler
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $record
|
||||
* @param array $record
|
||||
* @return array
|
||||
*/
|
||||
protected function filterEmptyFields(array $record)
|
||||
|
@@ -46,10 +46,10 @@ class ElasticSearchHandler extends AbstractProcessingHandler
|
||||
protected $options = array();
|
||||
|
||||
/**
|
||||
* @param Client $client Elastica Client object
|
||||
* @param array $options Handler configuration
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
|
||||
* @param Client $client Elastica Client object
|
||||
* @param array $options Handler configuration
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
|
||||
*/
|
||||
public function __construct(Client $client, array $options = array(), $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
@@ -112,7 +112,7 @@ class ElasticSearchHandler extends AbstractProcessingHandler
|
||||
|
||||
/**
|
||||
* Use Elasticsearch bulk API to send list of documents
|
||||
* @param array $documents
|
||||
* @param array $documents
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function bulkSend(array $documents)
|
||||
|
@@ -73,7 +73,8 @@ class StreamHandler extends AbstractProcessingHandler
|
||||
fwrite($this->stream, (string) $record['formatted']);
|
||||
}
|
||||
|
||||
private function customErrorHandler($code, $msg) {
|
||||
private function customErrorHandler($code, $msg)
|
||||
{
|
||||
$this->errorMessage = preg_replace('{^fopen\(.*?\): }', '', $msg);
|
||||
}
|
||||
}
|
||||
|
64
src/Monolog/Processor/GitProcessor.php
Normal file
64
src/Monolog/Processor/GitProcessor.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog\Processor;
|
||||
|
||||
use Monolog\Logger;
|
||||
|
||||
/**
|
||||
* Injects Git branch and Git commit SHA in all records
|
||||
*
|
||||
* @author Nick Otter
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class GitProcessor
|
||||
{
|
||||
private $level;
|
||||
private static $cache;
|
||||
|
||||
public function __construct($level = Logger::DEBUG)
|
||||
{
|
||||
$this->level = $level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $record
|
||||
* @return array
|
||||
*/
|
||||
public function __invoke(array $record)
|
||||
{
|
||||
// return if the level is not high enough
|
||||
if ($record['level'] < $this->level) {
|
||||
return $record;
|
||||
}
|
||||
|
||||
$record['extra']['git'] = self::getGitInfo();
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
private static function getGitInfo()
|
||||
{
|
||||
if (self::$cache) {
|
||||
return self::$cache;
|
||||
}
|
||||
|
||||
$branches = `git branch -v --no-abbrev`;
|
||||
if (preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) {
|
||||
return self::$cache = array(
|
||||
'branch' => $matches[1],
|
||||
'commit' => $matches[2],
|
||||
);
|
||||
}
|
||||
|
||||
return self::$cache = array();
|
||||
}
|
||||
}
|
118
src/Monolog/Registry.php
Normal file
118
src/Monolog/Registry.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Monolog log registry
|
||||
*
|
||||
* Allows to get `Logger` instances in the global scope
|
||||
* via static method calls on this class.
|
||||
*
|
||||
* <code>
|
||||
* $application = new Monolog\Logger('application');
|
||||
* $api = new Monolog\Logger('api');
|
||||
*
|
||||
* Monolog\Registry::addLogger($application);
|
||||
* Monolog\Registry::addLogger($api);
|
||||
*
|
||||
* function testLogger()
|
||||
* {
|
||||
* Monolog\Registry::api()->addError('Sent to $api Logger instance');
|
||||
* Monolog\Registry::application()->addError('Sent to $application Logger instance');
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @author Tomas Tatarko <tomas@tatarko.sk>
|
||||
*/
|
||||
class Registry
|
||||
{
|
||||
/**
|
||||
* List of all loggers in the registry (ba named indexes)
|
||||
*
|
||||
* @var Logger[]
|
||||
*/
|
||||
private static $loggers = array();
|
||||
|
||||
/**
|
||||
* Adds new logging channel to the registry
|
||||
*
|
||||
* @param Logger $logger Instance of the logging channel
|
||||
* @param string $name Name of the logging channel ($logger->getName() by default)
|
||||
* @param boolean $overwrite Overwrite instance in the registry if the given name already exists?
|
||||
* @throws \InvalidArgumentException If $overwrite set to false and named Logger instance already exists
|
||||
*/
|
||||
public static function addLogger(Logger $logger, $name = null, $overwrite = false)
|
||||
{
|
||||
$name = $name ?: $logger->getName();
|
||||
|
||||
if (isset(self::$loggers[$name]) && !$overwrite) {
|
||||
throw new InvalidArgumentException('Logger with the given name already exists');
|
||||
}
|
||||
|
||||
self::$loggers[$name] = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes instance from registry by name or instance
|
||||
*
|
||||
* @param string|Logger $logger Name or logger instance
|
||||
*/
|
||||
public static function removeLogger($logger)
|
||||
{
|
||||
if ($logger instanceof Logger) {
|
||||
if (false !== ($idx = array_search($logger, self::$loggers, true))) {
|
||||
unset(self::$loggers[$idx]);
|
||||
}
|
||||
} else {
|
||||
unset(self::$loggers[$logger]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the registry
|
||||
*/
|
||||
public static function clear()
|
||||
{
|
||||
self::$loggers = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets Logger instance from the registry
|
||||
*
|
||||
* @param string $name Name of the requested Logger instance
|
||||
* @return Logger Requested instance of Logger
|
||||
* @throws \InvalidArgumentException If named Logger instance is not in the registry
|
||||
*/
|
||||
public static function getInstance($name)
|
||||
{
|
||||
if (!isset(self::$loggers[$name])) {
|
||||
throw new InvalidArgumentException(sprintf('Requested "%s" logger instance is not in the registry', $name));
|
||||
}
|
||||
|
||||
return self::$loggers[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets Logger instance from the registry via static method call
|
||||
*
|
||||
* @param string $name Name of the requested Logger instance
|
||||
* @param array $arguments Arguments passed to static method call
|
||||
* @return Logger Requested instance of Logger
|
||||
* @throws \InvalidArgumentException If named Logger instance is not in the registry
|
||||
*/
|
||||
public static function __callStatic($name, $arguments)
|
||||
{
|
||||
return self::getInstance($name);
|
||||
}
|
||||
}
|
29
tests/Monolog/Processor/GitProcessorTest.php
Normal file
29
tests/Monolog/Processor/GitProcessorTest.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog\Processor;
|
||||
|
||||
use Monolog\TestCase;
|
||||
|
||||
class GitProcessorTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Monolog\Processor\GitProcessor::__invoke
|
||||
*/
|
||||
public function testProcessor()
|
||||
{
|
||||
$processor = new GitProcessor();
|
||||
$record = $processor($this->getRecord());
|
||||
|
||||
$this->assertArrayHasKey('git', $record['extra']);
|
||||
$this->assertTrue(!is_array($record['extra']['git']['branch']));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user