update v 1.0.7.5
This commit is contained in:
52
vendor/monolog/monolog/.php_cs
vendored
52
vendor/monolog/monolog/.php_cs
vendored
@@ -1,15 +1,59 @@
|
||||
<?php
|
||||
|
||||
$finder = Symfony\CS\Finder\DefaultFinder::create()
|
||||
$header = <<<EOF
|
||||
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.
|
||||
EOF;
|
||||
|
||||
$finder = Symfony\CS\Finder::create()
|
||||
->files()
|
||||
->name('*.php')
|
||||
->exclude('Fixtures')
|
||||
->in(__DIR__.'/src')
|
||||
->in(__DIR__.'/tests')
|
||||
;
|
||||
|
||||
return Symfony\CS\Config\Config::create()
|
||||
->fixers(array(
|
||||
'psr0', 'encoding', 'short_tag', 'braces', 'elseif', 'eof_ending', 'function_declaration', 'indentation', 'line_after_namespace', 'linefeed', 'lowercase_constants', 'lowercase_keywords', 'multiple_use', 'php_closing_tag', 'trailing_spaces', 'visibility', 'duplicate_semicolon', 'extra_empty_lines', 'include', 'namespace_no_leading_whitespace', 'object_operator', 'operators_spaces', 'phpdoc_params', 'return', 'single_array_no_trailing_comma', 'spaces_cast', 'standardize_not_equal', 'ternary_spaces', 'unused_use', 'whitespacy_lines',
|
||||
return Symfony\CS\Config::create()
|
||||
->setUsingCache(true)
|
||||
//->setUsingLinter(false)
|
||||
->setRiskyAllowed(true)
|
||||
->setRules(array(
|
||||
'@PSR2' => true,
|
||||
'binary_operator_spaces' => true,
|
||||
'blank_line_before_return' => true,
|
||||
'header_comment' => array('header' => $header),
|
||||
'include' => true,
|
||||
'long_array_syntax' => true,
|
||||
'method_separation' => true,
|
||||
'no_blank_lines_after_class_opening' => true,
|
||||
'no_blank_lines_after_phpdoc' => true,
|
||||
'no_blank_lines_between_uses' => true,
|
||||
'no_duplicate_semicolons' => true,
|
||||
'no_extra_consecutive_blank_lines' => true,
|
||||
'no_leading_import_slash' => true,
|
||||
'no_leading_namespace_whitespace' => true,
|
||||
'no_trailing_comma_in_singleline_array' => true,
|
||||
'no_unused_imports' => true,
|
||||
'object_operator_without_whitespace' => true,
|
||||
'phpdoc_align' => true,
|
||||
'phpdoc_indent' => true,
|
||||
'phpdoc_no_access' => true,
|
||||
'phpdoc_no_package' => true,
|
||||
'phpdoc_order' => true,
|
||||
'phpdoc_scalar' => true,
|
||||
'phpdoc_trim' => true,
|
||||
'phpdoc_type_to_var' => true,
|
||||
'psr0' => true,
|
||||
'single_blank_line_before_namespace' => true,
|
||||
'spaces_cast' => true,
|
||||
'standardize_not_equals' => true,
|
||||
'ternary_operator_spaces' => true,
|
||||
'trailing_comma_in_multiline_array' => true,
|
||||
'whitespacy_lines' => true,
|
||||
))
|
||||
->finder($finder)
|
||||
;
|
||||
|
||||
34
vendor/monolog/monolog/CHANGELOG.mdown
vendored
34
vendor/monolog/monolog/CHANGELOG.mdown
vendored
@@ -1,3 +1,37 @@
|
||||
### 1.19.0 (2016-04-12)
|
||||
|
||||
* Break: StreamHandler will not close streams automatically that it does not own. If you pass in a stream (not a path/url), then it will not close it for you. You can retrieve those using getStream() if needed
|
||||
* Added DeduplicationHandler to remove duplicate records from notifications across multiple requests, useful for email or other notifications on errors
|
||||
* Added ability to use `%message%` and other LineFormatter replacements in the subject line of emails sent with NativeMailHandler and SwiftMailerHandler
|
||||
* Fixed HipChatHandler handling of long messages
|
||||
|
||||
### 1.18.2 (2016-04-02)
|
||||
|
||||
* Fixed ElasticaFormatter to use more precise dates
|
||||
* Fixed GelfMessageFormatter sending too long messages
|
||||
|
||||
### 1.18.1 (2016-03-13)
|
||||
|
||||
* Fixed SlackHandler bug where slack dropped messages randomly
|
||||
* Fixed RedisHandler issue when using with the PHPRedis extension
|
||||
* Fixed AmqpHandler content-type being incorrectly set when using with the AMQP extension
|
||||
* Fixed BrowserConsoleHandler regression
|
||||
|
||||
### 1.18.0 (2016-03-01)
|
||||
|
||||
* Added optional reduction of timestamp precision via `Logger->useMicrosecondTimestamps(false)`, disabling it gets you a bit of performance boost but reduces the precision to the second instead of microsecond
|
||||
* Added possibility to skip some extra stack frames in IntrospectionProcessor if you have some library wrapping Monolog that is always adding frames
|
||||
* Added `Logger->withName` to clone a logger (keeping all handlers) with a new name
|
||||
* Added FluentdFormatter for the Fluentd unix socket protocol
|
||||
* Added HandlerWrapper base class to ease the creation of handler wrappers, just extend it and override as needed
|
||||
* Added support for replacing context sub-keys using `%context.*%` in LineFormatter
|
||||
* Added support for `payload` context value in RollbarHandler
|
||||
* Added setRelease to RavenHandler to describe the application version, sent with every log
|
||||
* Added support for `fingerprint` context value in RavenHandler
|
||||
* Fixed JSON encoding errors that would gobble up the whole log record, we now handle those more gracefully by dropping chars as needed
|
||||
* Fixed write timeouts in SocketHandler and derivatives, set to 10sec by default, lower it with `setWritingTimeout()`
|
||||
* Fixed PHP7 compatibility with regard to Exception/Throwable handling in a few places
|
||||
|
||||
### 1.17.2 (2015-10-14)
|
||||
|
||||
* Fixed ErrorHandler compatibility with non-Monolog PSR-3 loggers
|
||||
|
||||
2
vendor/monolog/monolog/LICENSE
vendored
2
vendor/monolog/monolog/LICENSE
vendored
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2011-2015 Jordi Boggiano
|
||||
Copyright (c) 2011-2016 Jordi Boggiano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
7
vendor/monolog/monolog/composer.json
vendored
7
vendor/monolog/monolog/composer.json
vendored
@@ -23,7 +23,7 @@
|
||||
"ruflin/elastica": ">=0.90 <3.0",
|
||||
"doctrine/couchdb": "~1.0@dev",
|
||||
"aws/aws-sdk-php": "^2.4.9",
|
||||
"videlalvaro/php-amqplib": "~2.4",
|
||||
"php-amqplib/php-amqplib": "~2.4",
|
||||
"swiftmailer/swiftmailer": "~5.3",
|
||||
"php-console/php-console": "^3.1.3",
|
||||
"phpunit/phpunit-mock-objects": "2.3.0",
|
||||
@@ -35,9 +35,10 @@
|
||||
"raven/raven": "Allow sending log messages to a Sentry server",
|
||||
"doctrine/couchdb": "Allow sending log messages to a CouchDB server",
|
||||
"ruflin/elastica": "Allow sending log messages to an Elastic Search server",
|
||||
"videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
|
||||
"php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
|
||||
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
|
||||
"ext-mongo": "Allow sending log messages to a MongoDB server",
|
||||
"mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver",
|
||||
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
|
||||
"rollbar/rollbar": "Allow sending log messages to Rollbar",
|
||||
"php-console/php-console": "Allow sending log messages to Google Chrome"
|
||||
@@ -53,7 +54,7 @@
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.16.x-dev"
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
3
vendor/monolog/monolog/doc/01-usage.md
vendored
3
vendor/monolog/monolog/doc/01-usage.md
vendored
@@ -189,6 +189,9 @@ $logger->pushHandler($firephp);
|
||||
$securityLogger = new Logger('security');
|
||||
$securityLogger->pushHandler($stream);
|
||||
$securityLogger->pushHandler($firephp);
|
||||
|
||||
// Or clone the first one to only change the channel
|
||||
$securityLogger = $logger->withName('security');
|
||||
```
|
||||
|
||||
## Customizing the log format
|
||||
|
||||
@@ -85,6 +85,16 @@
|
||||
when it happens you will have the full information, including debug and info
|
||||
records. This provides you with all the information you need, but only when
|
||||
you need it.
|
||||
- _DeduplicationHandler_: Useful if you are sending notifications or emails
|
||||
when critical errors occur. It takes a logger as parameter and will
|
||||
accumulate log records of all levels until the end of the request (or
|
||||
`flush()` is called). At that point it delivers all records to the handler
|
||||
it wraps, but only if the records are unique over a given time period
|
||||
(60seconds by default). If the records are duplicates they are simply
|
||||
discarded. The main use of this is in case of critical failure like if your
|
||||
database is unreachable for example all your requests will fail and that
|
||||
can result in a lot of notifications being sent. Adding this handler reduces
|
||||
the amount of notifications to a manageable level.
|
||||
- _WhatFailureGroupHandler_: This handler extends the _GroupHandler_ ignoring
|
||||
exceptions raised by each child handler. This allows you to ignore issues
|
||||
where a remote tcp connection may have died but you do not want your entire
|
||||
@@ -105,6 +115,8 @@
|
||||
- _PsrHandler_: Can be used to forward log records to an existing PSR-3 logger
|
||||
- _TestHandler_: Used for testing, it records everything that is sent to it and
|
||||
has accessors to read out the information.
|
||||
- _HandlerWrapper_: A simple handler wrapper you can inherit from to create
|
||||
your own wrappers easily.
|
||||
|
||||
## Formatters
|
||||
|
||||
@@ -124,6 +136,7 @@
|
||||
|
||||
## Processors
|
||||
|
||||
- _PsrLogMessageProcessor_: Processes a log record's message according to PSR-3 rules, replacing `{foo}` with the value from `$context['foo']`.
|
||||
- _IntrospectionProcessor_: Adds the line/file/class/method from which the log call originated.
|
||||
- _WebProcessor_: Adds the current request URI, request method and client IP to a log record.
|
||||
- _MemoryUsageProcessor_: Adds the current memory usage to a log record.
|
||||
|
||||
@@ -41,10 +41,9 @@ class ChromePHPFormatter implements FormatterInterface
|
||||
{
|
||||
// Retrieve the line and file if set and remove them from the formatted extra
|
||||
$backtrace = 'unknown';
|
||||
if (isset($record['extra']['file']) && isset($record['extra']['line'])) {
|
||||
if (isset($record['extra']['file'], $record['extra']['line'])) {
|
||||
$backtrace = $record['extra']['file'].' : '.$record['extra']['line'];
|
||||
unset($record['extra']['file']);
|
||||
unset($record['extra']['line']);
|
||||
unset($record['extra']['file'], $record['extra']['line']);
|
||||
}
|
||||
|
||||
$message = array('message' => $record['message']);
|
||||
|
||||
@@ -36,7 +36,9 @@ class ElasticaFormatter extends NormalizerFormatter
|
||||
*/
|
||||
public function __construct($index, $type)
|
||||
{
|
||||
parent::__construct(\DateTime::ISO8601);
|
||||
// elasticsearch requires a ISO 8601 format date with optional millisecond precision.
|
||||
parent::__construct('Y-m-d\TH:i:s.uP');
|
||||
|
||||
$this->index = $index;
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
85
vendor/monolog/monolog/src/Monolog/Formatter/FluentdFormatter.php
vendored
Normal file
85
vendor/monolog/monolog/src/Monolog/Formatter/FluentdFormatter.php
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
<?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\Formatter;
|
||||
|
||||
/**
|
||||
* Class FluentdFormatter
|
||||
*
|
||||
* Serializes a log message to Fluentd unix socket protocol
|
||||
*
|
||||
* Fluentd config:
|
||||
*
|
||||
* <source>
|
||||
* type unix
|
||||
* path /var/run/td-agent/td-agent.sock
|
||||
* </source>
|
||||
*
|
||||
* Monolog setup:
|
||||
*
|
||||
* $logger = new Monolog\Logger('fluent.tag');
|
||||
* $fluentHandler = new Monolog\Handler\SocketHandler('unix:///var/run/td-agent/td-agent.sock');
|
||||
* $fluentHandler->setFormatter(new Monolog\Formatter\FluentdFormatter());
|
||||
* $logger->pushHandler($fluentHandler);
|
||||
*
|
||||
* @author Andrius Putna <fordnox@gmail.com>
|
||||
*/
|
||||
class FluentdFormatter implements FormatterInterface
|
||||
{
|
||||
/**
|
||||
* @var bool $levelTag should message level be a part of the fluentd tag
|
||||
*/
|
||||
protected $levelTag = false;
|
||||
|
||||
public function __construct($levelTag = false)
|
||||
{
|
||||
if (!function_exists('json_encode')) {
|
||||
throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s FluentdUnixFormatter');
|
||||
}
|
||||
|
||||
$this->levelTag = (bool) $levelTag;
|
||||
}
|
||||
|
||||
public function isUsingLevelsInTag()
|
||||
{
|
||||
return $this->levelTag;
|
||||
}
|
||||
|
||||
public function format(array $record)
|
||||
{
|
||||
$tag = $record['channel'];
|
||||
if ($this->levelTag) {
|
||||
$tag .= '.' . strtolower($record['level_name']);
|
||||
}
|
||||
|
||||
$message = array(
|
||||
'message' => $record['message'],
|
||||
'extra' => $record['extra'],
|
||||
);
|
||||
|
||||
if (!$this->levelTag) {
|
||||
$message['level'] = $record['level'];
|
||||
$message['level_name'] = $record['level_name'];
|
||||
}
|
||||
|
||||
return json_encode(array($tag, $record['datetime']->getTimestamp(), $message));
|
||||
}
|
||||
|
||||
public function formatBatch(array $records)
|
||||
{
|
||||
$message = '';
|
||||
foreach ($records as $record) {
|
||||
$message .= $this->format($record);
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,8 @@ use Gelf\Message;
|
||||
*/
|
||||
class GelfMessageFormatter extends NormalizerFormatter
|
||||
{
|
||||
const MAX_LENGTH = 32766;
|
||||
|
||||
/**
|
||||
* @var string the name of the system for the Gelf log message
|
||||
*/
|
||||
@@ -79,24 +81,48 @@ class GelfMessageFormatter extends NormalizerFormatter
|
||||
->setHost($this->systemName)
|
||||
->setLevel($this->logLevels[$record['level']]);
|
||||
|
||||
// start count with message length + system name length + 200 for padding / metadata
|
||||
$len = 200 + strlen((string) $record['message']) + strlen($this->systemName);
|
||||
|
||||
if ($len > self::MAX_LENGTH) {
|
||||
$message->setShortMessage(substr($record['message'], 0, self::MAX_LENGTH - 200));
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
if (isset($record['channel'])) {
|
||||
$message->setFacility($record['channel']);
|
||||
$len += strlen($record['channel']);
|
||||
}
|
||||
if (isset($record['extra']['line'])) {
|
||||
$message->setLine($record['extra']['line']);
|
||||
$len += 10;
|
||||
unset($record['extra']['line']);
|
||||
}
|
||||
if (isset($record['extra']['file'])) {
|
||||
$message->setFile($record['extra']['file']);
|
||||
$len += strlen($record['extra']['file']);
|
||||
unset($record['extra']['file']);
|
||||
}
|
||||
|
||||
foreach ($record['extra'] as $key => $val) {
|
||||
$message->setAdditional($this->extraPrefix . $key, is_scalar($val) ? $val : $this->toJson($val));
|
||||
$val = is_scalar($val) ? $val : $this->toJson($val);
|
||||
$len += strlen($this->extraPrefix . $key . $val);
|
||||
if ($len > self::MAX_LENGTH) {
|
||||
$message->setAdditional($this->extraPrefix . $key, substr($val, 0, self::MAX_LENGTH - $len));
|
||||
break;
|
||||
}
|
||||
$message->setAdditional($this->extraPrefix . $key, $val);
|
||||
}
|
||||
|
||||
foreach ($record['context'] as $key => $val) {
|
||||
$message->setAdditional($this->contextPrefix . $key, is_scalar($val) ? $val : $this->toJson($val));
|
||||
$val = is_scalar($val) ? $val : $this->toJson($val);
|
||||
$len += strlen($this->contextPrefix . $key . $val);
|
||||
if ($len > self::MAX_LENGTH) {
|
||||
$message->setAdditional($this->contextPrefix . $key, substr($val, 0, self::MAX_LENGTH - $len));
|
||||
break;
|
||||
}
|
||||
$message->setAdditional($this->contextPrefix . $key, $val);
|
||||
}
|
||||
|
||||
if (null === $message->getFile() && isset($record['context']['exception']['file'])) {
|
||||
|
||||
@@ -24,7 +24,7 @@ class HtmlFormatter extends NormalizerFormatter
|
||||
/**
|
||||
* Translates Monolog log levels to html color priorities.
|
||||
*/
|
||||
private $logLevels = array(
|
||||
protected $logLevels = array(
|
||||
Logger::DEBUG => '#cccccc',
|
||||
Logger::INFO => '#468847',
|
||||
Logger::NOTICE => '#3a87ad',
|
||||
@@ -64,8 +64,8 @@ class HtmlFormatter extends NormalizerFormatter
|
||||
/**
|
||||
* Create a HTML h1 tag
|
||||
*
|
||||
* @param string $title Text to be in the h1
|
||||
* @param integer $level Error level
|
||||
* @param string $title Text to be in the h1
|
||||
* @param int $level Error level
|
||||
* @return string
|
||||
*/
|
||||
private function addTitle($title, $level)
|
||||
@@ -74,6 +74,7 @@ class HtmlFormatter extends NormalizerFormatter
|
||||
|
||||
return '<h1 style="background: '.$this->logLevels[$level].';color: #ffffff;padding: 5px;" class="monolog-output">'.$title.'</h1>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a log record.
|
||||
*
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace Monolog\Formatter;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Encodes whatever record data is passed to it as json
|
||||
*
|
||||
@@ -18,13 +20,17 @@ namespace Monolog\Formatter;
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class JsonFormatter implements FormatterInterface
|
||||
class JsonFormatter extends NormalizerFormatter
|
||||
{
|
||||
const BATCH_MODE_JSON = 1;
|
||||
const BATCH_MODE_NEWLINES = 2;
|
||||
|
||||
protected $batchMode;
|
||||
protected $appendNewline;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $includeStacktraces = false;
|
||||
|
||||
/**
|
||||
* @param int $batchMode
|
||||
@@ -64,7 +70,7 @@ class JsonFormatter implements FormatterInterface
|
||||
*/
|
||||
public function format(array $record)
|
||||
{
|
||||
return json_encode($record) . ($this->appendNewline ? "\n" : '');
|
||||
return $this->toJson($this->normalize($record), true) . ($this->appendNewline ? "\n" : '');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,6 +88,14 @@ class JsonFormatter implements FormatterInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $include
|
||||
*/
|
||||
public function includeStacktraces($include = true)
|
||||
{
|
||||
$this->includeStacktraces = $include;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a JSON-encoded array of records.
|
||||
*
|
||||
@@ -90,7 +104,7 @@ class JsonFormatter implements FormatterInterface
|
||||
*/
|
||||
protected function formatBatchJson(array $records)
|
||||
{
|
||||
return json_encode($records);
|
||||
return $this->toJson($this->normalize($records), true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,4 +127,76 @@ class JsonFormatter implements FormatterInterface
|
||||
|
||||
return implode("\n", $records);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes given $data.
|
||||
*
|
||||
* @param mixed $data
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function normalize($data)
|
||||
{
|
||||
if (is_array($data) || $data instanceof \Traversable) {
|
||||
$normalized = array();
|
||||
|
||||
$count = 1;
|
||||
foreach ($data as $key => $value) {
|
||||
if ($count++ >= 1000) {
|
||||
$normalized['...'] = 'Over 1000 items, aborting normalization';
|
||||
break;
|
||||
}
|
||||
$normalized[$key] = $this->normalize($value);
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
if ($data instanceof Exception) {
|
||||
return $this->normalizeException($data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes given exception with or without its own stack trace based on
|
||||
* `includeStacktraces` property.
|
||||
*
|
||||
* @param Exception|Throwable $e
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function normalizeException($e)
|
||||
{
|
||||
// TODO 2.0 only check for Throwable
|
||||
if (!$e instanceof Exception && !$e instanceof \Throwable) {
|
||||
throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.get_class($e));
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'class' => get_class($e),
|
||||
'message' => $e->getMessage(),
|
||||
'code' => $e->getCode(),
|
||||
'file' => $e->getFile().':'.$e->getLine(),
|
||||
);
|
||||
|
||||
if ($this->includeStacktraces) {
|
||||
$trace = $e->getTrace();
|
||||
foreach ($trace as $frame) {
|
||||
if (isset($frame['file'])) {
|
||||
$data['trace'][] = $frame['file'].':'.$frame['line'];
|
||||
} else {
|
||||
// We should again normalize the frames, because it might contain invalid items
|
||||
$data['trace'][] = $this->normalize($frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($previous = $e->getPrevious()) {
|
||||
$data['previous'] = $this->normalizeException($previous);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Monolog\Formatter;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Formats incoming records into a one-line string
|
||||
*
|
||||
@@ -78,6 +76,13 @@ class LineFormatter extends NormalizerFormatter
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($vars['context'] as $var => $val) {
|
||||
if (false !== strpos($output, '%context.'.$var.'%')) {
|
||||
$output = str_replace('%context.'.$var.'%', $this->stringify($val), $output);
|
||||
unset($vars['context'][$var]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->ignoreEmptyContextAndExtra) {
|
||||
if (empty($vars['context'])) {
|
||||
unset($vars['context']);
|
||||
@@ -114,8 +119,13 @@ class LineFormatter extends NormalizerFormatter
|
||||
return $this->replaceNewlines($this->convertToString($value));
|
||||
}
|
||||
|
||||
protected function normalizeException(Exception $e)
|
||||
protected function normalizeException($e)
|
||||
{
|
||||
// TODO 2.0 only check for Throwable
|
||||
if (!$e instanceof \Exception && !$e instanceof \Throwable) {
|
||||
throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.get_class($e));
|
||||
}
|
||||
|
||||
$previousText = '';
|
||||
if ($previous = $e->getPrevious()) {
|
||||
do {
|
||||
|
||||
@@ -22,7 +22,7 @@ class LogglyFormatter extends JsonFormatter
|
||||
* Overrides the default batch mode to new lines for compatibility with the
|
||||
* Loggly bulk API.
|
||||
*
|
||||
* @param integer $batchMode
|
||||
* @param int $batchMode
|
||||
*/
|
||||
public function __construct($batchMode = self::BATCH_MODE_NEWLINES, $appendNewline = false)
|
||||
{
|
||||
|
||||
@@ -45,16 +45,16 @@ class LogstashFormatter extends NormalizerFormatter
|
||||
protected $contextPrefix;
|
||||
|
||||
/**
|
||||
* @var integer logstash format version to use
|
||||
* @var int logstash format version to use
|
||||
*/
|
||||
protected $version;
|
||||
|
||||
/**
|
||||
* @param string $applicationName the application that sends the data, used as the "type" field of logstash
|
||||
* @param string $systemName the system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine
|
||||
* @param string $extraPrefix prefix for extra keys inside logstash "fields"
|
||||
* @param string $contextPrefix prefix for context keys inside logstash "fields", defaults to ctxt_
|
||||
* @param integer $version the logstash format version to use, defaults to 0
|
||||
* @param string $applicationName the application that sends the data, used as the "type" field of logstash
|
||||
* @param string $systemName the system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine
|
||||
* @param string $extraPrefix prefix for extra keys inside logstash "fields"
|
||||
* @param string $contextPrefix prefix for context keys inside logstash "fields", defaults to ctxt_
|
||||
* @param int $version the logstash format version to use, defaults to 0
|
||||
*/
|
||||
public function __construct($applicationName, $systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_', $version = self::V0)
|
||||
{
|
||||
@@ -92,7 +92,7 @@ class LogstashFormatter extends NormalizerFormatter
|
||||
$message = array(
|
||||
'@timestamp' => $record['datetime'],
|
||||
'@source' => $this->systemName,
|
||||
'@fields' => array()
|
||||
'@fields' => array(),
|
||||
);
|
||||
if (isset($record['message'])) {
|
||||
$message['@message'] = $record['message'];
|
||||
|
||||
@@ -90,13 +90,14 @@ class NormalizerFormatter implements FormatterInterface
|
||||
}
|
||||
|
||||
if (is_object($data)) {
|
||||
if ($data instanceof Exception) {
|
||||
// TODO 2.0 only check for Throwable
|
||||
if ($data instanceof Exception || (PHP_VERSION_ID > 70000 && $data instanceof \Throwable)) {
|
||||
return $this->normalizeException($data);
|
||||
}
|
||||
|
||||
// non-serializable objects that implement __toString stringified
|
||||
if (method_exists($data, '__toString') && !$data instanceof \JsonSerializable) {
|
||||
$value = (string) $data;
|
||||
$value = $data->__toString();
|
||||
} else {
|
||||
// the rest is json-serialized in some way
|
||||
$value = $this->toJson($data, true);
|
||||
@@ -112,8 +113,13 @@ class NormalizerFormatter implements FormatterInterface
|
||||
return '[unknown('.gettype($data).')]';
|
||||
}
|
||||
|
||||
protected function normalizeException(Exception $e)
|
||||
protected function normalizeException($e)
|
||||
{
|
||||
// TODO 2.0 only check for Throwable
|
||||
if (!$e instanceof Exception && !$e instanceof \Throwable) {
|
||||
throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.get_class($e));
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'class' => get_class($e),
|
||||
'message' => $e->getMessage(),
|
||||
@@ -138,23 +144,72 @@ class NormalizerFormatter implements FormatterInterface
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JSON representation of a value
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param bool $ignoreErrors
|
||||
* @throws \RuntimeException if encoding fails and errors are not ignored
|
||||
* @return string
|
||||
*/
|
||||
protected function toJson($data, $ignoreErrors = false)
|
||||
{
|
||||
// suppress json_encode errors since it's twitchy with some inputs
|
||||
if ($ignoreErrors) {
|
||||
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
return @json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
return @json_encode($data);
|
||||
return @$this->jsonEncode($data);
|
||||
}
|
||||
|
||||
$json = $this->jsonEncode($data);
|
||||
|
||||
if ($json === false) {
|
||||
$json = $this->handleJsonError(json_last_error(), $data);
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $data
|
||||
* @return string JSON encoded data or null on failure
|
||||
*/
|
||||
private function jsonEncode($data)
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
$json = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
} else {
|
||||
$json = json_encode($data);
|
||||
return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
return json_encode($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a json_encode failure.
|
||||
*
|
||||
* If the failure is due to invalid string encoding, try to clean the
|
||||
* input and encode again. If the second encoding iattempt fails, the
|
||||
* inital error is not encoding related or the input can't be cleaned then
|
||||
* raise a descriptive exception.
|
||||
*
|
||||
* @param int $code return code of json_last_error function
|
||||
* @param mixed $data data that was meant to be encoded
|
||||
* @throws \RuntimeException if failure can't be corrected
|
||||
* @return string JSON encoded data after error correction
|
||||
*/
|
||||
private function handleJsonError($code, $data)
|
||||
{
|
||||
if ($code !== JSON_ERROR_UTF8) {
|
||||
$this->throwEncodeError($code, $data);
|
||||
}
|
||||
|
||||
if (is_string($data)) {
|
||||
$this->detectAndCleanUtf8($data);
|
||||
} elseif (is_array($data)) {
|
||||
array_walk_recursive($data, array($this, 'detectAndCleanUtf8'));
|
||||
} else {
|
||||
$this->throwEncodeError($code, $data);
|
||||
}
|
||||
|
||||
$json = $this->jsonEncode($data);
|
||||
|
||||
if ($json === false) {
|
||||
$this->throwEncodeError(json_last_error(), $data);
|
||||
}
|
||||
@@ -165,8 +220,8 @@ class NormalizerFormatter implements FormatterInterface
|
||||
/**
|
||||
* Throws an exception according to a given code with a customized message
|
||||
*
|
||||
* @param int $code return code of json_last_error function
|
||||
* @param mixed $data data that was meant to be encoded
|
||||
* @param int $code return code of json_last_error function
|
||||
* @param mixed $data data that was meant to be encoded
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function throwEncodeError($code, $data)
|
||||
@@ -190,4 +245,36 @@ class NormalizerFormatter implements FormatterInterface
|
||||
|
||||
throw new \RuntimeException('JSON encoding failed: '.$msg.'. Encoding: '.var_export($data, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect invalid UTF-8 string characters and convert to valid UTF-8.
|
||||
*
|
||||
* Valid UTF-8 input will be left unmodified, but strings containing
|
||||
* invalid UTF-8 codepoints will be reencoded as UTF-8 with an assumed
|
||||
* original encoding of ISO-8859-15. This conversion may result in
|
||||
* incorrect output if the actual encoding was not ISO-8859-15, but it
|
||||
* will be clean UTF-8 output and will not rely on expensive and fragile
|
||||
* detection algorithms.
|
||||
*
|
||||
* Function converts the input in place in the passed variable so that it
|
||||
* can be used as a callback for array_walk_recursive.
|
||||
*
|
||||
* @param mixed &$data Input to check and convert if needed
|
||||
* @private
|
||||
*/
|
||||
public function detectAndCleanUtf8(&$data)
|
||||
{
|
||||
if (is_string($data) && !preg_match('//u', $data)) {
|
||||
$data = preg_replace_callback(
|
||||
'/[\x80-\xFF]+/',
|
||||
function ($m) { return utf8_encode($m[0]); },
|
||||
$data
|
||||
);
|
||||
$data = str_replace(
|
||||
array('¤', '¦', '¨', '´', '¸', '¼', '½', '¾'),
|
||||
array('€', 'Š', 'š', 'Ž', 'ž', 'Œ', 'œ', 'Ÿ'),
|
||||
$data
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ abstract class AbstractHandler implements HandlerInterface
|
||||
protected $processors = array();
|
||||
|
||||
/**
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param int $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($level = Logger::DEBUG, $bubble = true)
|
||||
@@ -118,7 +118,7 @@ abstract class AbstractHandler implements HandlerInterface
|
||||
/**
|
||||
* Sets minimum logging level at which this handler will be triggered.
|
||||
*
|
||||
* @param integer $level
|
||||
* @param int|string $level Level or level name
|
||||
* @return self
|
||||
*/
|
||||
public function setLevel($level)
|
||||
@@ -131,7 +131,7 @@ abstract class AbstractHandler implements HandlerInterface
|
||||
/**
|
||||
* Gets minimum logging level at which this handler will be triggered.
|
||||
*
|
||||
* @return integer
|
||||
* @return int
|
||||
*/
|
||||
public function getLevel()
|
||||
{
|
||||
|
||||
@@ -54,7 +54,7 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler
|
||||
|
||||
/**
|
||||
* @param mixed $facility
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param int $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($facility = LOG_USER, $level = Logger::DEBUG, $bubble = true)
|
||||
@@ -70,6 +70,15 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler
|
||||
$this->facilities['local5'] = LOG_LOCAL5;
|
||||
$this->facilities['local6'] = LOG_LOCAL6;
|
||||
$this->facilities['local7'] = LOG_LOCAL7;
|
||||
} else {
|
||||
$this->facilities['local0'] = 128; // LOG_LOCAL0
|
||||
$this->facilities['local1'] = 136; // LOG_LOCAL1
|
||||
$this->facilities['local2'] = 144; // LOG_LOCAL2
|
||||
$this->facilities['local3'] = 152; // LOG_LOCAL3
|
||||
$this->facilities['local4'] = 160; // LOG_LOCAL4
|
||||
$this->facilities['local5'] = 168; // LOG_LOCAL5
|
||||
$this->facilities['local6'] = 176; // LOG_LOCAL6
|
||||
$this->facilities['local7'] = 184; // LOG_LOCAL7
|
||||
}
|
||||
|
||||
// convert textual description of facility to syslog constant
|
||||
|
||||
@@ -55,7 +55,64 @@ class AmqpHandler extends AbstractProcessingHandler
|
||||
protected function write(array $record)
|
||||
{
|
||||
$data = $record["formatted"];
|
||||
$routingKey = $this->getRoutingKey($record);
|
||||
|
||||
if ($this->exchange instanceof AMQPExchange) {
|
||||
$this->exchange->publish(
|
||||
$data,
|
||||
$routingKey,
|
||||
0,
|
||||
array(
|
||||
'delivery_mode' => 2,
|
||||
'content_type' => 'application/json',
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$this->exchange->basic_publish(
|
||||
$this->createAmqpMessage($data),
|
||||
$this->exchangeName,
|
||||
$routingKey
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function handleBatch(array $records)
|
||||
{
|
||||
if ($this->exchange instanceof AMQPExchange) {
|
||||
parent::handleBatch($records);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($records as $record) {
|
||||
if (!$this->isHandling($record)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$record = $this->processRecord($record);
|
||||
$data = $this->getFormatter()->format($record);
|
||||
|
||||
$this->exchange->batch_basic_publish(
|
||||
$this->createAmqpMessage($data),
|
||||
$this->exchangeName,
|
||||
$this->getRoutingKey($record)
|
||||
);
|
||||
}
|
||||
|
||||
$this->exchange->publish_batch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the routing key for the AMQP exchange
|
||||
*
|
||||
* @param array $record
|
||||
* @return string
|
||||
*/
|
||||
private function getRoutingKey(array $record)
|
||||
{
|
||||
$routingKey = sprintf(
|
||||
'%s.%s',
|
||||
// TODO 2.0 remove substr call
|
||||
@@ -63,29 +120,22 @@ class AmqpHandler extends AbstractProcessingHandler
|
||||
$record['channel']
|
||||
);
|
||||
|
||||
if ($this->exchange instanceof AMQPExchange) {
|
||||
$this->exchange->publish(
|
||||
$data,
|
||||
strtolower($routingKey),
|
||||
0,
|
||||
array(
|
||||
'delivery_mode' => 2,
|
||||
'Content-type' => 'application/json'
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$this->exchange->basic_publish(
|
||||
new AMQPMessage(
|
||||
(string) $data,
|
||||
array(
|
||||
'delivery_mode' => 2,
|
||||
'content_type' => 'application/json'
|
||||
)
|
||||
),
|
||||
$this->exchangeName,
|
||||
strtolower($routingKey)
|
||||
);
|
||||
}
|
||||
return strtolower($routingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @return AMQPMessage
|
||||
*/
|
||||
private function createAmqpMessage($data)
|
||||
{
|
||||
return new AMQPMessage(
|
||||
(string) $data,
|
||||
array(
|
||||
'delivery_mode' => 2,
|
||||
'content_type' => 'application/json',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,7 +31,6 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
|
||||
* Example of formatted string:
|
||||
*
|
||||
* You can do [[blue text]]{color: blue} or [[green background]]{background-color: green; color: white}
|
||||
*
|
||||
*/
|
||||
protected function getDefaultFormatter()
|
||||
{
|
||||
@@ -47,9 +46,9 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
|
||||
self::$records[] = $record;
|
||||
|
||||
// Register shutdown handler if not already done
|
||||
if (PHP_SAPI !== 'cli' && !self::$initialized) {
|
||||
if (!self::$initialized) {
|
||||
self::$initialized = true;
|
||||
register_shutdown_function(array('Monolog\Handler\BrowserConsoleHandler', 'send'));
|
||||
$this->registerShutdownFunction();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,26 +58,16 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
|
||||
*/
|
||||
public static function send()
|
||||
{
|
||||
$htmlTags = true;
|
||||
// Check content type
|
||||
foreach (headers_list() as $header) {
|
||||
if (stripos($header, 'content-type:') === 0) {
|
||||
// This handler only works with HTML and javascript outputs
|
||||
// text/javascript is obsolete in favour of application/javascript, but still used
|
||||
if (stripos($header, 'application/javascript') !== false || stripos($header, 'text/javascript') !== false) {
|
||||
$htmlTags = false;
|
||||
} elseif (stripos($header, 'text/html') === false) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
$format = self::getResponseFormat();
|
||||
if ($format === 'unknown') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (count(self::$records)) {
|
||||
if ($htmlTags) {
|
||||
echo '<script>' , self::generateScript() , '</script>';
|
||||
} else {
|
||||
echo self::generateScript();
|
||||
if ($format === 'html') {
|
||||
self::writeOutput('<script>' . self::generateScript() . '</script>');
|
||||
} elseif ($format === 'js') {
|
||||
self::writeOutput(self::generateScript());
|
||||
}
|
||||
self::reset();
|
||||
}
|
||||
@@ -92,6 +81,55 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
|
||||
self::$records = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for register_shutdown_function to allow overriding
|
||||
*/
|
||||
protected function registerShutdownFunction()
|
||||
{
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
register_shutdown_function(array('Monolog\Handler\BrowserConsoleHandler', 'send'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for echo to allow overriding
|
||||
*
|
||||
* @param string $str
|
||||
*/
|
||||
protected static function writeOutput($str)
|
||||
{
|
||||
echo $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the format of the response
|
||||
*
|
||||
* If Content-Type is set to application/javascript or text/javascript -> js
|
||||
* If Content-Type is set to text/html, or is unset -> html
|
||||
* If Content-Type is anything else -> unknown
|
||||
*
|
||||
* @return string One of 'js', 'html' or 'unknown'
|
||||
*/
|
||||
protected static function getResponseFormat()
|
||||
{
|
||||
// Check content type
|
||||
foreach (headers_list() as $header) {
|
||||
if (stripos($header, 'content-type:') === 0) {
|
||||
// This handler only works with HTML and javascript outputs
|
||||
// text/javascript is obsolete in favour of application/javascript, but still used
|
||||
if (stripos($header, 'application/javascript') !== false || stripos($header, 'text/javascript') !== false) {
|
||||
return 'js';
|
||||
}
|
||||
if (stripos($header, 'text/html') === false) {
|
||||
return 'unknown';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 'html';
|
||||
}
|
||||
|
||||
private static function generateScript()
|
||||
{
|
||||
$script = array();
|
||||
|
||||
@@ -32,8 +32,8 @@ class BufferHandler extends AbstractHandler
|
||||
|
||||
/**
|
||||
* @param HandlerInterface $handler Handler.
|
||||
* @param integer $bufferLimit How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param int $bufferLimit How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
|
||||
* @param int $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 Boolean $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded
|
||||
*/
|
||||
|
||||
@@ -17,6 +17,8 @@ use Monolog\Logger;
|
||||
/**
|
||||
* Handler sending logs to the ChromePHP extension (http://www.chromephp.com/)
|
||||
*
|
||||
* This also works out of the box with Firefox 43+
|
||||
*
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
class ChromePHPHandler extends AbstractProcessingHandler
|
||||
@@ -30,6 +32,11 @@ class ChromePHPHandler extends AbstractProcessingHandler
|
||||
* Header name
|
||||
*/
|
||||
const HEADER_NAME = 'X-ChromeLogger-Data';
|
||||
|
||||
/**
|
||||
* Regular expression to detect supported browsers (matches any Chrome, or Firefox 43+)
|
||||
*/
|
||||
const USER_AGENT_REGEX = '{\b(?:Chrome/\d+(?:\.\d+)*|Firefox/(?:4[3-9]|[5-9]\d|\d{3,})(?:\.\d)*)\b}';
|
||||
|
||||
protected static $initialized = false;
|
||||
|
||||
@@ -51,7 +58,7 @@ class ChromePHPHandler extends AbstractProcessingHandler
|
||||
protected static $sendHeaders = true;
|
||||
|
||||
/**
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param int $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($level = Logger::DEBUG, $bubble = true)
|
||||
@@ -175,7 +182,7 @@ class ChromePHPHandler extends AbstractProcessingHandler
|
||||
return false;
|
||||
}
|
||||
|
||||
return preg_match('{\bChrome/\d+[\.\d+]*\b}', $_SERVER['HTTP_USER_AGENT']);
|
||||
return preg_match(self::USER_AGENT_REGEX, $_SERVER['HTTP_USER_AGENT']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -54,7 +54,7 @@ class CouchDBHandler extends AbstractProcessingHandler
|
||||
'ignore_errors' => true,
|
||||
'max_redirects' => 0,
|
||||
'header' => 'Content-type: application/json',
|
||||
)
|
||||
),
|
||||
));
|
||||
|
||||
if (false === @file_get_contents($url, null, $context)) {
|
||||
|
||||
@@ -21,37 +21,37 @@ use Monolog\Logger;
|
||||
*/
|
||||
class CubeHandler extends AbstractProcessingHandler
|
||||
{
|
||||
private $udpConnection = null;
|
||||
private $httpConnection = null;
|
||||
private $scheme = null;
|
||||
private $host = null;
|
||||
private $port = null;
|
||||
private $udpConnection;
|
||||
private $httpConnection;
|
||||
private $scheme;
|
||||
private $host;
|
||||
private $port;
|
||||
private $acceptedSchemes = array('http', 'udp');
|
||||
|
||||
/**
|
||||
* Create a Cube handler
|
||||
*
|
||||
* @throws \UnexpectedValueException when given url is not a valid url.
|
||||
* A valid url must consists of three parts : protocol://host:port
|
||||
* Only valid protocol used by Cube are http and udp
|
||||
* A valid url must consist of three parts : protocol://host:port
|
||||
* Only valid protocols used by Cube are http and udp
|
||||
*/
|
||||
public function __construct($url, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
$urlInfos = parse_url($url);
|
||||
$urlInfo = parse_url($url);
|
||||
|
||||
if (!isset($urlInfos['scheme']) || !isset($urlInfos['host']) || !isset($urlInfos['port'])) {
|
||||
if (!isset($urlInfo['scheme'], $urlInfo['host'], $urlInfo['port'])) {
|
||||
throw new \UnexpectedValueException('URL "'.$url.'" is not valid');
|
||||
}
|
||||
|
||||
if (!in_array($urlInfos['scheme'], $this->acceptedSchemes)) {
|
||||
if (!in_array($urlInfo['scheme'], $this->acceptedSchemes)) {
|
||||
throw new \UnexpectedValueException(
|
||||
'Invalid protocol (' . $urlInfos['scheme'] . ').'
|
||||
'Invalid protocol (' . $urlInfo['scheme'] . ').'
|
||||
. ' Valid options are ' . implode(', ', $this->acceptedSchemes));
|
||||
}
|
||||
|
||||
$this->scheme = $urlInfos['scheme'];
|
||||
$this->host = $urlInfos['host'];
|
||||
$this->port = $urlInfos['port'];
|
||||
$this->scheme = $urlInfo['scheme'];
|
||||
$this->host = $urlInfo['host'];
|
||||
$this->port = $urlInfo['port'];
|
||||
|
||||
parent::__construct($level, $bubble);
|
||||
}
|
||||
@@ -59,7 +59,8 @@ class CubeHandler extends AbstractProcessingHandler
|
||||
/**
|
||||
* Establish a connection to an UDP socket
|
||||
*
|
||||
* @throws \LogicException when unable to connect to the socket
|
||||
* @throws \LogicException when unable to connect to the socket
|
||||
* @throws MissingExtensionException when there is no socket extension
|
||||
*/
|
||||
protected function connectUdp()
|
||||
{
|
||||
@@ -79,6 +80,7 @@ class CubeHandler extends AbstractProcessingHandler
|
||||
|
||||
/**
|
||||
* Establish a connection to a http server
|
||||
* @throws \LogicException when no curl extension
|
||||
*/
|
||||
protected function connectHttp()
|
||||
{
|
||||
@@ -140,10 +142,10 @@ class CubeHandler extends AbstractProcessingHandler
|
||||
|
||||
curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']');
|
||||
curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, array(
|
||||
'Content-Type: application/json',
|
||||
'Content-Length: ' . strlen('['.$data.']'))
|
||||
);
|
||||
'Content-Type: application/json',
|
||||
'Content-Length: ' . strlen('['.$data.']'),
|
||||
));
|
||||
|
||||
Curl\Util::execute($ch, 5, false);
|
||||
Curl\Util::execute($this->httpConnection, 5, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class Util
|
||||
/**
|
||||
* Executes a CURL request with optional retries and exception on failure
|
||||
*
|
||||
* @param resource $ch curl handler
|
||||
* @param resource $ch curl handler
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function execute($ch, $retries = 5, $closeAfterDone = true)
|
||||
|
||||
169
vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php
vendored
Normal file
169
vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
<?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\Handler;
|
||||
|
||||
use Monolog\Logger;
|
||||
|
||||
/**
|
||||
* Simple handler wrapper that deduplicates log records across multiple requests
|
||||
*
|
||||
* It also includes the BufferHandler functionality and will buffer
|
||||
* all messages until the end of the request or flush() is called.
|
||||
*
|
||||
* This works by storing all log records' messages above $deduplicationLevel
|
||||
* to the file specified by $deduplicationStore. When further logs come in at the end of the
|
||||
* request (or when flush() is called), all those above $deduplicationLevel are checked
|
||||
* against the existing stored logs. If they match and the timestamps in the stored log is
|
||||
* not older than $time seconds, the new log record is discarded. If no log record is new, the
|
||||
* whole data set is discarded.
|
||||
*
|
||||
* This is mainly useful in combination with Mail handlers or things like Slack or HipChat handlers
|
||||
* that send messages to people, to avoid spamming with the same message over and over in case of
|
||||
* a major component failure like a database server being down which makes all requests fail in the
|
||||
* same way.
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class DeduplicationHandler extends BufferHandler
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $deduplicationStore;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $deduplicationLevel;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $time;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $gc = false;
|
||||
|
||||
/**
|
||||
* @param HandlerInterface $handler Handler.
|
||||
* @param string $deduplicationStore The file/path where the deduplication log should be kept
|
||||
* @param int $deduplicationLevel The minimum logging level for log records to be looked at for deduplication purposes
|
||||
* @param int $time The period (in seconds) during which duplicate entries should be suppressed after a given log is sent through
|
||||
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
|
||||
*/
|
||||
public function __construct(HandlerInterface $handler, $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, $time = 60, $bubble = true)
|
||||
{
|
||||
parent::__construct($handler, 0, Logger::DEBUG, $bubble, false);
|
||||
|
||||
$this->deduplicationStore = $deduplicationStore === null ? sys_get_temp_dir() . '/monolog-dedup-' . substr(md5(__FILE__), 0, 20) .'.log' : $deduplicationStore;
|
||||
$this->deduplicationLevel = Logger::toMonologLevel($deduplicationLevel);
|
||||
$this->time = $time;
|
||||
}
|
||||
|
||||
public function flush()
|
||||
{
|
||||
if ($this->bufferSize === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$passthru = null;
|
||||
|
||||
foreach ($this->buffer as $record) {
|
||||
if ($record['level'] >= $this->deduplicationLevel) {
|
||||
|
||||
$passthru = $passthru || !$this->isDuplicate($record);
|
||||
if ($passthru) {
|
||||
$this->appendRecord($record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// default of null is valid as well as if no record matches duplicationLevel we just pass through
|
||||
if ($passthru === true || $passthru === null) {
|
||||
$this->handler->handleBatch($this->buffer);
|
||||
}
|
||||
|
||||
$this->clear();
|
||||
|
||||
if ($this->gc) {
|
||||
$this->collectLogs();
|
||||
}
|
||||
}
|
||||
|
||||
private function isDuplicate(array $record)
|
||||
{
|
||||
if (!file_exists($this->deduplicationStore)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$store = file($this->deduplicationStore, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
if (!is_array($store)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$yesterday = time() - 86400;
|
||||
$timestampValidity = $record['datetime']->getTimestamp() - $this->time;
|
||||
$expectedMessage = preg_replace('{[\r\n].*}', '', $record['message']);
|
||||
|
||||
for ($i = count($store) - 1; $i >= 0; $i--) {
|
||||
list($timestamp, $level, $message) = explode(':', $store[$i], 3);
|
||||
|
||||
if ($level === $record['level_name'] && $message === $expectedMessage && $timestamp > $timestampValidity) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($timestamp < $yesterday) {
|
||||
$this->gc = true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function collectLogs()
|
||||
{
|
||||
if (!file_exists($this->deduplicationStore)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$handle = fopen($this->deduplicationStore, 'rw+');
|
||||
flock($handle, LOCK_EX);
|
||||
$validLogs = array();
|
||||
|
||||
$timestampValidity = time() - $this->time;
|
||||
|
||||
while (!feof($handle)) {
|
||||
$log = fgets($handle);
|
||||
if (substr($log, 0, 10) >= $timestampValidity) {
|
||||
$validLogs[] = $log;
|
||||
}
|
||||
}
|
||||
|
||||
ftruncate($handle, 0);
|
||||
rewind($handle);
|
||||
foreach ($validLogs as $log) {
|
||||
fwrite($handle, $log);
|
||||
}
|
||||
|
||||
flock($handle, LOCK_UN);
|
||||
fclose($handle);
|
||||
|
||||
$this->gc = false;
|
||||
}
|
||||
|
||||
private function appendRecord(array $record)
|
||||
{
|
||||
file_put_contents($this->deduplicationStore, $record['datetime']->getTimestamp() . ':' . $record['level_name'] . ':' . preg_replace('{[\r\n].*}', '', $record['message']) . "\n", FILE_APPEND);
|
||||
}
|
||||
}
|
||||
@@ -39,8 +39,8 @@ class DynamoDbHandler extends AbstractProcessingHandler
|
||||
/**
|
||||
* @param DynamoDbClient $client
|
||||
* @param string $table
|
||||
* @param integer $level
|
||||
* @param boolean $bubble
|
||||
* @param int $level
|
||||
* @param bool $bubble
|
||||
*/
|
||||
public function __construct(DynamoDbClient $client, $table, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
@@ -64,7 +64,7 @@ class DynamoDbHandler extends AbstractProcessingHandler
|
||||
|
||||
$this->client->putItem(array(
|
||||
'TableName' => $this->table,
|
||||
'Item' => $formatted
|
||||
'Item' => $formatted,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class ElasticSearchHandler extends AbstractProcessingHandler
|
||||
/**
|
||||
* @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 int $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)
|
||||
|
||||
@@ -28,8 +28,8 @@ class ErrorLogHandler extends AbstractProcessingHandler
|
||||
protected $expandNewlines;
|
||||
|
||||
/**
|
||||
* @param integer $messageType Says where the error should go.
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param int $messageType Says where the error should go.
|
||||
* @param int $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 Boolean $expandNewlines If set to true, newlines in the message will be expanded to be take multiple log entries
|
||||
*/
|
||||
|
||||
@@ -31,7 +31,7 @@ class FilterHandler extends AbstractHandler
|
||||
protected $handler;
|
||||
|
||||
/**
|
||||
* Minimum level for logs that are passes to handler
|
||||
* Minimum level for logs that are passed to handler
|
||||
*
|
||||
* @var int[]
|
||||
*/
|
||||
@@ -70,8 +70,8 @@ class FilterHandler extends AbstractHandler
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided
|
||||
* @param int $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array
|
||||
* @param int|string|array $minLevelOrList A list of levels to accept or a minimum level or level name if maxLevel is provided
|
||||
* @param int|string $maxLevel Maximum level or level name to accept, only used if $minLevelOrList is not an array
|
||||
*/
|
||||
public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY)
|
||||
{
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
*
|
||||
* (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\Handler\FingersCrossed;
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ class FleepHookHandler extends SocketHandler
|
||||
private function buildContent($record)
|
||||
{
|
||||
$dataArray = array(
|
||||
'message' => $record['formatted']
|
||||
'message' => $record['formatted'],
|
||||
);
|
||||
|
||||
return http_build_query($dataArray);
|
||||
|
||||
@@ -33,15 +33,15 @@ class GelfHandler extends AbstractProcessingHandler
|
||||
|
||||
/**
|
||||
* @param PublisherInterface|IMessagePublisher|Publisher $publisher a publisher object
|
||||
* @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 int $level The minimum logging level at which this handler will be triggered
|
||||
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
|
||||
*/
|
||||
public function __construct($publisher, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
parent::__construct($level, $bubble);
|
||||
|
||||
if (!$publisher instanceof Publisher && !$publisher instanceof IMessagePublisher && !$publisher instanceof PublisherInterface) {
|
||||
throw new InvalidArgumentException("Invalid publisher, expected a Gelf\Publisher, Gelf\IMessagePublisher or Gelf\PublisherInterface instance");
|
||||
throw new InvalidArgumentException('Invalid publisher, expected a Gelf\Publisher, Gelf\IMessagePublisher or Gelf\PublisherInterface instance');
|
||||
}
|
||||
|
||||
$this->publisher = $publisher;
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace Monolog\Handler;
|
||||
|
||||
use Monolog\Formatter\FormatterInterface;
|
||||
|
||||
/**
|
||||
* Forwards records to multiple handlers
|
||||
*
|
||||
@@ -77,4 +79,16 @@ class GroupHandler extends AbstractHandler
|
||||
$handler->handleBatch($records);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setFormatter(FormatterInterface $formatter)
|
||||
{
|
||||
foreach ($this->handlers as $handler) {
|
||||
$handler->setFormatter($formatter);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
106
vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php
vendored
Normal file
106
vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
<?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\Handler;
|
||||
|
||||
use Monolog\Formatter\FormatterInterface;
|
||||
|
||||
/**
|
||||
* This simple wrapper class can be used to extend handlers functionality.
|
||||
*
|
||||
* Example: A filtering handle. Inherit from this class, override isHandling() like this
|
||||
*
|
||||
* public function isHandling(array $record)
|
||||
* {
|
||||
* if ($record meets certain conditions) {
|
||||
* return false;
|
||||
* }
|
||||
* return $this->handler->isHandling($record);
|
||||
* }
|
||||
*
|
||||
* @author Alexey Karapetov <alexey@karapetov.com>
|
||||
*/
|
||||
class HandlerWrapper implements HandlerInterface
|
||||
{
|
||||
/**
|
||||
* @var HandlerInterface
|
||||
*/
|
||||
private $handler;
|
||||
|
||||
/**
|
||||
* HandlerWrapper constructor.
|
||||
* @param HandlerInterface $handler
|
||||
*/
|
||||
public function __construct(HandlerInterface $handler)
|
||||
{
|
||||
$this->handler = $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isHandling(array $record)
|
||||
{
|
||||
return $this->handler->isHandling($record);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handle(array $record)
|
||||
{
|
||||
return $this->handler->handle($record);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handleBatch(array $records)
|
||||
{
|
||||
return $this->handler->handleBatch($records);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function pushProcessor($callback)
|
||||
{
|
||||
$this->handler->pushProcessor($callback);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function popProcessor()
|
||||
{
|
||||
return $this->handler->popProcessor();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setFormatter(FormatterInterface $formatter)
|
||||
{
|
||||
$this->handler->setFormatter($formatter);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormatter()
|
||||
{
|
||||
return $this->handler->getFormatter();
|
||||
}
|
||||
}
|
||||
@@ -84,16 +84,16 @@ class HipChatHandler extends SocketHandler
|
||||
private $version;
|
||||
|
||||
/**
|
||||
* @param string $token HipChat API Token
|
||||
* @param string $room The room that should be alerted of the message (Id or Name)
|
||||
* @param string $name Name used in the "from" field. Not used for v2
|
||||
* @param bool $notify Trigger a notification in clients or not
|
||||
* @param int $level The minimum logging level at which this handler will be triggered
|
||||
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
|
||||
* @param bool $useSSL Whether to connect via SSL.
|
||||
* @param string $format The format of the messages (default to text, can be set to html if you have html in the messages)
|
||||
* @param string $host The HipChat server hostname.
|
||||
* @param string $version The HipChat API version (default HipChatHandler::API_V1)
|
||||
* @param string $token HipChat API Token
|
||||
* @param string $room The room that should be alerted of the message (Id or Name)
|
||||
* @param string $name Name used in the "from" field.
|
||||
* @param bool $notify Trigger a notification in clients or not
|
||||
* @param int $level The minimum logging level at which this handler will be triggered
|
||||
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
|
||||
* @param bool $useSSL Whether to connect via SSL.
|
||||
* @param string $format The format of the messages (default to text, can be set to html if you have html in the messages)
|
||||
* @param string $host The HipChat server hostname.
|
||||
* @param string $version The HipChat API version (default HipChatHandler::API_V1)
|
||||
*/
|
||||
public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $format = 'text', $host = 'api.hipchat.com', $version = self::API_V1)
|
||||
{
|
||||
@@ -143,10 +143,23 @@ class HipChatHandler extends SocketHandler
|
||||
'color' => $this->getAlertColor($record['level']),
|
||||
);
|
||||
|
||||
if (!$this->validateStringLength($dataArray['message'], static::MAXIMUM_MESSAGE_LENGTH)) {
|
||||
if (function_exists('mb_substr')) {
|
||||
$dataArray['message'] = mb_substr($dataArray['message'], 0, static::MAXIMUM_MESSAGE_LENGTH).' [truncated]';
|
||||
} else {
|
||||
$dataArray['message'] = substr($dataArray['message'], 0, static::MAXIMUM_MESSAGE_LENGTH).' [truncated]';
|
||||
}
|
||||
}
|
||||
|
||||
// if we are using the legacy API then we need to send some additional information
|
||||
if ($this->version == self::API_V1) {
|
||||
$dataArray['room_id'] = $this->room;
|
||||
$dataArray['from'] = $this->name;
|
||||
}
|
||||
|
||||
// append the sender name if it is set
|
||||
// always append it if we use the v1 api (it is required in v1)
|
||||
if ($this->version == self::API_V1 || $this->name !== null) {
|
||||
$dataArray['from'] = (string) $this->name;
|
||||
}
|
||||
|
||||
return http_build_query($dataArray);
|
||||
@@ -179,7 +192,7 @@ class HipChatHandler extends SocketHandler
|
||||
/**
|
||||
* Assigns a color to each level of log records.
|
||||
*
|
||||
* @param integer $level
|
||||
* @param int $level
|
||||
* @return string
|
||||
*/
|
||||
protected function getAlertColor($level)
|
||||
@@ -303,7 +316,7 @@ class HipChatHandler extends SocketHandler
|
||||
array(
|
||||
'level' => $level,
|
||||
'level_name' => $levelName,
|
||||
'datetime' => $datetime
|
||||
'datetime' => $datetime,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -30,10 +30,10 @@ class IFTTTHandler extends AbstractProcessingHandler
|
||||
private $secretKey;
|
||||
|
||||
/**
|
||||
* @param string $eventName The name of the IFTTT Maker event that should be triggered
|
||||
* @param string $secretKey A valid IFTTT secret key
|
||||
* @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 string $eventName The name of the IFTTT Maker event that should be triggered
|
||||
* @param string $secretKey A valid IFTTT secret key
|
||||
* @param int $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($eventName, $secretKey, $level = Logger::ERROR, $bubble = true)
|
||||
{
|
||||
@@ -51,7 +51,7 @@ class IFTTTHandler extends AbstractProcessingHandler
|
||||
$postData = array(
|
||||
"value1" => $record["channel"],
|
||||
"value2" => $record["level_name"],
|
||||
"value3" => $record["message"]
|
||||
"value3" => $record["message"],
|
||||
);
|
||||
$postString = json_encode($postData);
|
||||
|
||||
@@ -61,7 +61,7 @@ class IFTTTHandler extends AbstractProcessingHandler
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $postString);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
|
||||
"Content-Type: application/json"
|
||||
"Content-Type: application/json",
|
||||
));
|
||||
|
||||
Curl\Util::execute($ch);
|
||||
|
||||
@@ -24,10 +24,10 @@ class LogEntriesHandler extends SocketHandler
|
||||
protected $logToken;
|
||||
|
||||
/**
|
||||
* @param string $token Log token supplied by LogEntries
|
||||
* @param boolean $useSSL Whether or not SSL encryption should be used.
|
||||
* @param int $level The minimum logging level to trigger this handler
|
||||
* @param boolean $bubble Whether or not messages that are handled should bubble up the stack.
|
||||
* @param string $token Log token supplied by LogEntries
|
||||
* @param bool $useSSL Whether or not SSL encryption should be used.
|
||||
* @param int $level The minimum logging level to trigger this handler
|
||||
* @param bool $bubble Whether or not messages that are handled should bubble up the stack.
|
||||
*
|
||||
* @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing
|
||||
*/
|
||||
|
||||
@@ -52,4 +52,16 @@ abstract class MailHandler extends AbstractProcessingHandler
|
||||
{
|
||||
$this->send((string) $record['formatted'], array($record));
|
||||
}
|
||||
|
||||
protected function getHighestRecord(array $records)
|
||||
{
|
||||
$highestRecord = null;
|
||||
foreach ($records as $record) {
|
||||
if ($highestRecord === null || $highestRecord['level'] < $record['level']) {
|
||||
$highestRecord = $record;
|
||||
}
|
||||
}
|
||||
|
||||
return $highestRecord;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class MandrillHandler extends MailHandler
|
||||
/**
|
||||
* @param string $apiKey A valid Mandrill API key
|
||||
* @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param int $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($apiKey, $message, $level = Logger::ERROR, $bubble = true)
|
||||
|
||||
@@ -31,8 +31,8 @@ class MongoDBHandler extends AbstractProcessingHandler
|
||||
|
||||
public function __construct($mongo, $database, $collection, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
if (!($mongo instanceof \MongoClient || $mongo instanceof \Mongo)) {
|
||||
throw new \InvalidArgumentException('MongoClient or Mongo instance required');
|
||||
if (!($mongo instanceof \MongoClient || $mongo instanceof \Mongo || $mongo instanceof \MongoDB\Client)) {
|
||||
throw new \InvalidArgumentException('MongoClient, Mongo or MongoDB\Client instance required');
|
||||
}
|
||||
|
||||
$this->mongoCollection = $mongo->selectCollection($database, $collection);
|
||||
@@ -42,7 +42,11 @@ class MongoDBHandler extends AbstractProcessingHandler
|
||||
|
||||
protected function write(array $record)
|
||||
{
|
||||
$this->mongoCollection->save($record["formatted"]);
|
||||
if ($this->mongoCollection instanceof \MongoDB\Collection) {
|
||||
$this->mongoCollection->insertOne($record["formatted"]);
|
||||
} else {
|
||||
$this->mongoCollection->save($record["formatted"]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace Monolog\Handler;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
|
||||
/**
|
||||
* NativeMailerHandler uses the mail() function to send the emails
|
||||
@@ -47,7 +48,7 @@ class NativeMailerHandler extends MailHandler
|
||||
|
||||
/**
|
||||
* The wordwrap length for the message
|
||||
* @var integer
|
||||
* @var int
|
||||
*/
|
||||
protected $maxColumnWidth;
|
||||
|
||||
@@ -67,8 +68,8 @@ class NativeMailerHandler extends MailHandler
|
||||
* @param string|array $to The receiver of the mail
|
||||
* @param string $subject The subject of the mail
|
||||
* @param string $from The sender of the mail
|
||||
* @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 int $level The minimum logging level at which this handler will be triggered
|
||||
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
|
||||
* @param int $maxColumnWidth The maximum column width that the message lines will have
|
||||
*/
|
||||
public function __construct($to, $subject, $from, $level = Logger::ERROR, $bubble = true, $maxColumnWidth = 70)
|
||||
@@ -101,7 +102,7 @@ class NativeMailerHandler extends MailHandler
|
||||
/**
|
||||
* Add parameters to the message
|
||||
*
|
||||
* @param string|array $parameters Custom added parameters
|
||||
* @param string|array $parameters Custom added parameters
|
||||
* @return self
|
||||
*/
|
||||
public function addParameter($parameters)
|
||||
@@ -122,8 +123,16 @@ class NativeMailerHandler extends MailHandler
|
||||
if ($this->getContentType() == 'text/html' && false === strpos($headers, 'MIME-Version:')) {
|
||||
$headers .= 'MIME-Version: 1.0' . "\r\n";
|
||||
}
|
||||
|
||||
$subject = $this->subject;
|
||||
if ($records) {
|
||||
$subjectFormatter = new LineFormatter($this->subject);
|
||||
$subject = $subjectFormatter->format($this->getHighestRecord($records));
|
||||
}
|
||||
|
||||
$parameters = implode(' ', $this->parameters);
|
||||
foreach ($this->to as $to) {
|
||||
mail($to, $this->subject, $content, $headers, implode(' ', $this->parameters));
|
||||
mail($to, $subject, $content, $headers, $parameters);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,16 +41,16 @@ class NewRelicHandler extends AbstractProcessingHandler
|
||||
* Some context and extra data is passed into the handler as arrays of values. Do we send them as is
|
||||
* (useful if we are using the API), or explode them for display on the NewRelic RPM website?
|
||||
*
|
||||
* @var boolean
|
||||
* @var bool
|
||||
*/
|
||||
protected $explodeArrays;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @param string $appName
|
||||
* @param boolean $explodeArrays
|
||||
* @param string $transactionName
|
||||
* @param string $appName
|
||||
* @param bool $explodeArrays
|
||||
* @param string $transactionName
|
||||
*/
|
||||
public function __construct(
|
||||
$level = Logger::ERROR,
|
||||
|
||||
@@ -24,7 +24,7 @@ use Monolog\Logger;
|
||||
class NullHandler extends AbstractHandler
|
||||
{
|
||||
/**
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param int $level The minimum logging level at which this handler will be triggered
|
||||
*/
|
||||
public function __construct($level = Logger::DEBUG)
|
||||
{
|
||||
|
||||
@@ -66,10 +66,10 @@ class PHPConsoleHandler extends AbstractProcessingHandler
|
||||
private $connector;
|
||||
|
||||
/**
|
||||
* @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details
|
||||
* @param Connector|null $connector Instance of \PhpConsole\Connector class (optional)
|
||||
* @param int $level
|
||||
* @param bool $bubble
|
||||
* @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details
|
||||
* @param Connector|null $connector Instance of \PhpConsole\Connector class (optional)
|
||||
* @param int $level
|
||||
* @param bool $bubble
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct(array $options = array(), Connector $connector = null, $level = Logger::DEBUG, $bubble = true)
|
||||
|
||||
@@ -68,16 +68,16 @@ class PushoverHandler extends SocketHandler
|
||||
* @param string $token Pushover api token
|
||||
* @param string|array $users Pushover user id or array of ids the message will be sent to
|
||||
* @param string $title Title sent to the Pushover API
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param int $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 Boolean $useSSL Whether to connect via SSL. Required when pushing messages to users that are not
|
||||
* the pushover.net app owner. OpenSSL is required for this option.
|
||||
* @param integer $highPriorityLevel The minimum logging level at which this handler will start
|
||||
* @param int $highPriorityLevel The minimum logging level at which this handler will start
|
||||
* sending "high priority" requests to the Pushover API
|
||||
* @param integer $emergencyLevel The minimum logging level at which this handler will start
|
||||
* @param int $emergencyLevel The minimum logging level at which this handler will start
|
||||
* sending "emergency" requests to the Pushover API
|
||||
* @param integer $retry The retry parameter specifies how often (in seconds) the Pushover servers will send the same notification to the user.
|
||||
* @param integer $expire The expire parameter specifies how many seconds your notification will continue to be retried for (every retry seconds).
|
||||
* @param int $retry The retry parameter specifies how often (in seconds) the Pushover servers will send the same notification to the user.
|
||||
* @param int $expire The expire parameter specifies how many seconds your notification will continue to be retried for (every retry seconds).
|
||||
*/
|
||||
public function __construct($token, $users, $title = null, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $highPriorityLevel = Logger::CRITICAL, $emergencyLevel = Logger::EMERGENCY, $retry = 30, $expire = 25200)
|
||||
{
|
||||
@@ -115,7 +115,7 @@ class PushoverHandler extends SocketHandler
|
||||
'user' => $this->user,
|
||||
'message' => $message,
|
||||
'title' => $this->title,
|
||||
'timestamp' => $timestamp
|
||||
'timestamp' => $timestamp,
|
||||
);
|
||||
|
||||
if (isset($record['level']) && $record['level'] >= $this->emergencyLevel) {
|
||||
@@ -176,7 +176,7 @@ class PushoverHandler extends SocketHandler
|
||||
|
||||
/**
|
||||
* Use the formatted message?
|
||||
* @param boolean $value
|
||||
* @param bool $value
|
||||
*/
|
||||
public function useFormattedMessage($value)
|
||||
{
|
||||
|
||||
@@ -38,6 +38,12 @@ class RavenHandler extends AbstractProcessingHandler
|
||||
Logger::EMERGENCY => Raven_Client::FATAL,
|
||||
);
|
||||
|
||||
/**
|
||||
* @var string should represent the current version of the calling
|
||||
* software. Can be any string (git commit, version number)
|
||||
*/
|
||||
private $release;
|
||||
|
||||
/**
|
||||
* @var Raven_Client the client object that sends the message to the server
|
||||
*/
|
||||
@@ -50,7 +56,7 @@ class RavenHandler extends AbstractProcessingHandler
|
||||
|
||||
/**
|
||||
* @param Raven_Client $ravenClient
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param int $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(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true)
|
||||
@@ -139,6 +145,10 @@ class RavenHandler extends AbstractProcessingHandler
|
||||
$options['tags'] = array_merge($options['tags'], $record['context']['tags']);
|
||||
unset($record['context']['tags']);
|
||||
}
|
||||
if (!empty($record['context']['fingerprint'])) {
|
||||
$options['fingerprint'] = $record['context']['fingerprint'];
|
||||
unset($record['context']['fingerprint']);
|
||||
}
|
||||
if (!empty($record['context']['logger'])) {
|
||||
$options['logger'] = $record['context']['logger'];
|
||||
unset($record['context']['logger']);
|
||||
@@ -165,6 +175,10 @@ class RavenHandler extends AbstractProcessingHandler
|
||||
$options['extra']['extra'] = $record['extra'];
|
||||
}
|
||||
|
||||
if (!empty($this->release) && !isset($options['release'])) {
|
||||
$options['release'] = $this->release;
|
||||
}
|
||||
|
||||
if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) {
|
||||
$options['extra']['message'] = $record['formatted'];
|
||||
$this->ravenClient->captureException($record['context']['exception'], $options);
|
||||
@@ -204,4 +218,14 @@ class RavenHandler extends AbstractProcessingHandler
|
||||
{
|
||||
return array('checksum', 'release');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*/
|
||||
public function setRelease($value)
|
||||
{
|
||||
$this->release = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,9 +34,9 @@ class RedisHandler extends AbstractProcessingHandler
|
||||
/**
|
||||
* @param \Predis\Client|\Redis $redis The redis instance
|
||||
* @param string $key The key name to push records to
|
||||
* @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 integer $capSize Number of entries to limit list size to
|
||||
* @param int $level The minimum logging level at which this handler will be triggered
|
||||
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
|
||||
* @param int $capSize Number of entries to limit list size to
|
||||
*/
|
||||
public function __construct($redis, $key, $level = Logger::DEBUG, $bubble = true, $capSize = false)
|
||||
{
|
||||
@@ -67,7 +67,7 @@ class RedisHandler extends AbstractProcessingHandler
|
||||
* Write and cap the collection
|
||||
* Writes the record to the redis list and caps its
|
||||
*
|
||||
* @param array $record associative record array
|
||||
* @param array $record associative record array
|
||||
* @return void
|
||||
*/
|
||||
protected function writeCapped(array $record)
|
||||
@@ -76,7 +76,7 @@ class RedisHandler extends AbstractProcessingHandler
|
||||
$this->redisClient->multi()
|
||||
->rpush($this->redisKey, $record["formatted"])
|
||||
->ltrim($this->redisKey, -$this->capSize, -1)
|
||||
->execute();
|
||||
->exec();
|
||||
} else {
|
||||
$redisKey = $this->redisKey;
|
||||
$capSize = $this->capSize;
|
||||
|
||||
@@ -18,6 +18,9 @@ use Monolog\Logger;
|
||||
/**
|
||||
* Sends errors to Rollbar
|
||||
*
|
||||
* If the context data contains a `payload` key, that is used as an array
|
||||
* of payload options to RollbarNotifier's report_message/report_exception methods.
|
||||
*
|
||||
* @author Paul Statezny <paulstatezny@gmail.com>
|
||||
*/
|
||||
class RollbarHandler extends AbstractProcessingHandler
|
||||
@@ -38,8 +41,8 @@ class RollbarHandler extends AbstractProcessingHandler
|
||||
|
||||
/**
|
||||
* @param RollbarNotifier $rollbarNotifier RollbarNotifier object constructed with valid token
|
||||
* @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 int $level The minimum logging level at which this handler will be triggered
|
||||
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
|
||||
*/
|
||||
public function __construct(RollbarNotifier $rollbarNotifier, $level = Logger::ERROR, $bubble = true)
|
||||
{
|
||||
@@ -72,10 +75,18 @@ class RollbarHandler extends AbstractProcessingHandler
|
||||
'datetime' => $record['datetime']->format('U'),
|
||||
);
|
||||
|
||||
$context = $record['context'];
|
||||
$payload = array();
|
||||
if (isset($context['payload'])) {
|
||||
$payload = $context['payload'];
|
||||
unset($context['payload']);
|
||||
}
|
||||
|
||||
$this->rollbarNotifier->report_message(
|
||||
$record['message'],
|
||||
$record['level_name'],
|
||||
array_merge($record['context'], $record['extra'], $extraData)
|
||||
array_merge($record['context'], $record['extra'], $extraData),
|
||||
$payload
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ class RotatingFileHandler extends StreamHandler
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @param integer $maxFiles The maximal amount of files to keep (0 means unlimited)
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param int $maxFiles The maximal amount of files to keep (0 means unlimited)
|
||||
* @param int $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 int|null $filePermission Optional file permissions (default (0644) are only for owner read/write)
|
||||
* @param Boolean $useLocking Try to lock log file before doing any writes
|
||||
@@ -115,7 +115,11 @@ class RotatingFileHandler extends StreamHandler
|
||||
|
||||
foreach (array_slice($logFiles, $this->maxFiles) as $file) {
|
||||
if (is_writable($file)) {
|
||||
// suppress errors here as unlink() might fail if two processes
|
||||
// are cleaning up/rotating at the same time
|
||||
set_error_handler(function ($errno, $errstr, $errfile, $errline) {});
|
||||
unlink($file);
|
||||
restore_error_handler();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,15 +70,16 @@ class SlackHandler extends SocketHandler
|
||||
private $lineFormatter;
|
||||
|
||||
/**
|
||||
* @param string $token Slack API token
|
||||
* @param string $channel Slack channel (encoded ID or name)
|
||||
* @param string $username Name of a bot
|
||||
* @param bool $useAttachment Whether the message should be added to Slack as attachment (plain text otherwise)
|
||||
* @param string|null $iconEmoji The emoji name to use (or null)
|
||||
* @param int $level The minimum logging level at which this handler will be triggered
|
||||
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
|
||||
* @param bool $useShortAttachment Whether the the context/extra messages added to Slack as attachments are in a short style
|
||||
* @param bool $includeContextAndExtra Whether the attachment should include context and extra data
|
||||
* @param string $token Slack API token
|
||||
* @param string $channel Slack channel (encoded ID or name)
|
||||
* @param string $username Name of a bot
|
||||
* @param bool $useAttachment Whether the message should be added to Slack as attachment (plain text otherwise)
|
||||
* @param string|null $iconEmoji The emoji name to use (or null)
|
||||
* @param int $level The minimum logging level at which this handler will be triggered
|
||||
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
|
||||
* @param bool $useShortAttachment Whether the the context/extra messages added to Slack as attachments are in a short style
|
||||
* @param bool $includeContextAndExtra Whether the attachment should include context and extra data
|
||||
* @throws MissingExtensionException If no OpenSSL PHP extension configured
|
||||
*/
|
||||
public function __construct($token, $channel, $username = 'Monolog', $useAttachment = true, $iconEmoji = null, $level = Logger::CRITICAL, $bubble = true, $useShortAttachment = false, $includeContextAndExtra = false)
|
||||
{
|
||||
@@ -95,7 +96,8 @@ class SlackHandler extends SocketHandler
|
||||
$this->useAttachment = $useAttachment;
|
||||
$this->useShortAttachment = $useShortAttachment;
|
||||
$this->includeContextAndExtra = $includeContextAndExtra;
|
||||
if ($this->includeContextAndExtra) {
|
||||
|
||||
if ($this->includeContextAndExtra && $this->useShortAttachment) {
|
||||
$this->lineFormatter = new LineFormatter;
|
||||
}
|
||||
}
|
||||
@@ -139,14 +141,14 @@ class SlackHandler extends SocketHandler
|
||||
'channel' => $this->channel,
|
||||
'username' => $this->username,
|
||||
'text' => '',
|
||||
'attachments' => array()
|
||||
'attachments' => array(),
|
||||
);
|
||||
|
||||
if ($this->useAttachment) {
|
||||
$attachment = array(
|
||||
'fallback' => $record['message'],
|
||||
'color' => $this->getAttachmentColor($record['level']),
|
||||
'fields' => array()
|
||||
'fields' => array(),
|
||||
);
|
||||
|
||||
if ($this->useShortAttachment) {
|
||||
@@ -158,7 +160,7 @@ class SlackHandler extends SocketHandler
|
||||
$attachment['fields'][] = array(
|
||||
'title' => 'Level',
|
||||
'value' => $record['level_name'],
|
||||
'short' => true
|
||||
'short' => true,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -168,7 +170,7 @@ class SlackHandler extends SocketHandler
|
||||
$attachment['fields'][] = array(
|
||||
'title' => "Extra",
|
||||
'value' => $this->stringify($record['extra']),
|
||||
'short' => $this->useShortAttachment
|
||||
'short' => $this->useShortAttachment,
|
||||
);
|
||||
} else {
|
||||
// Add all extra fields as individual fields in attachment
|
||||
@@ -176,7 +178,7 @@ class SlackHandler extends SocketHandler
|
||||
$attachment['fields'][] = array(
|
||||
'title' => $var,
|
||||
'value' => $val,
|
||||
'short' => $this->useShortAttachment
|
||||
'short' => $this->useShortAttachment,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -187,7 +189,7 @@ class SlackHandler extends SocketHandler
|
||||
$attachment['fields'][] = array(
|
||||
'title' => "Context",
|
||||
'value' => $this->stringify($record['context']),
|
||||
'short' => $this->useShortAttachment
|
||||
'short' => $this->useShortAttachment,
|
||||
);
|
||||
} else {
|
||||
// Add all context fields as individual fields in attachment
|
||||
@@ -195,7 +197,7 @@ class SlackHandler extends SocketHandler
|
||||
$attachment['fields'][] = array(
|
||||
'title' => $var,
|
||||
'value' => $val,
|
||||
'short' => $this->useShortAttachment
|
||||
'short' => $this->useShortAttachment,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -239,6 +241,10 @@ class SlackHandler extends SocketHandler
|
||||
protected function write(array $record)
|
||||
{
|
||||
parent::write($record);
|
||||
$res = $this->getResource();
|
||||
if (is_resource($res)) {
|
||||
@fread($res, 2048);
|
||||
}
|
||||
$this->closeSocket();
|
||||
}
|
||||
|
||||
@@ -266,8 +272,7 @@ class SlackHandler extends SocketHandler
|
||||
/**
|
||||
* Stringifies an array of key/value pairs to be used in attachment fields
|
||||
*
|
||||
* @param array $fields
|
||||
* @access protected
|
||||
* @param array $fields
|
||||
* @return string
|
||||
*/
|
||||
protected function stringify($fields)
|
||||
|
||||
@@ -25,13 +25,16 @@ class SocketHandler extends AbstractProcessingHandler
|
||||
private $connectionTimeout;
|
||||
private $resource;
|
||||
private $timeout = 0;
|
||||
private $writingTimeout = 10;
|
||||
private $lastSentBytes = null;
|
||||
private $persistent = false;
|
||||
private $errno;
|
||||
private $errstr;
|
||||
private $lastWritingAt;
|
||||
|
||||
/**
|
||||
* @param string $connectionString Socket connection string
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param int $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($connectionString, $level = Logger::DEBUG, $bubble = true)
|
||||
@@ -80,7 +83,7 @@ class SocketHandler extends AbstractProcessingHandler
|
||||
/**
|
||||
* Set socket connection to nbe persistent. It only has effect before the connection is initiated.
|
||||
*
|
||||
* @param boolean $persistent
|
||||
* @param bool $persistent
|
||||
*/
|
||||
public function setPersistent($persistent)
|
||||
{
|
||||
@@ -113,6 +116,17 @@ class SocketHandler extends AbstractProcessingHandler
|
||||
$this->timeout = (float) $seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set writing timeout. Only has effect during connection in the writing cycle.
|
||||
*
|
||||
* @param float $seconds 0 for no timeout
|
||||
*/
|
||||
public function setWritingTimeout($seconds)
|
||||
{
|
||||
$this->validateTimeout($seconds);
|
||||
$this->writingTimeout = (float) $seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current connection string
|
||||
*
|
||||
@@ -126,7 +140,7 @@ class SocketHandler extends AbstractProcessingHandler
|
||||
/**
|
||||
* Get persistent setting
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function isPersistent()
|
||||
{
|
||||
@@ -153,12 +167,22 @@ class SocketHandler extends AbstractProcessingHandler
|
||||
return $this->timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current local writing timeout
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getWritingTimeout()
|
||||
{
|
||||
return $this->writingTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the socket is currently available.
|
||||
*
|
||||
* UDP might appear to be connected but might fail when writing. See http://php.net/fsockopen for details.
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function isConnected()
|
||||
{
|
||||
@@ -232,6 +256,14 @@ class SocketHandler extends AbstractProcessingHandler
|
||||
return (string) $record['formatted'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return resource|null
|
||||
*/
|
||||
protected function getResource()
|
||||
{
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
private function connect()
|
||||
{
|
||||
$this->createSocketResource();
|
||||
@@ -262,6 +294,7 @@ class SocketHandler extends AbstractProcessingHandler
|
||||
{
|
||||
$length = strlen($data);
|
||||
$sent = 0;
|
||||
$this->lastSentBytes = $sent;
|
||||
while ($this->isConnected() && $sent < $length) {
|
||||
if (0 == $sent) {
|
||||
$chunk = $this->fwrite($data);
|
||||
@@ -276,9 +309,38 @@ class SocketHandler extends AbstractProcessingHandler
|
||||
if ($socketInfo['timed_out']) {
|
||||
throw new \RuntimeException("Write timed-out");
|
||||
}
|
||||
|
||||
if ($this->writingIsTimedOut($sent)) {
|
||||
throw new \RuntimeException("Write timed-out, no data sent for `{$this->writingTimeout}` seconds, probably we got disconnected (sent $sent of $length)");
|
||||
}
|
||||
}
|
||||
if (!$this->isConnected() && $sent < $length) {
|
||||
throw new \RuntimeException("End-of-file reached, probably we got disconnected (sent $sent of $length)");
|
||||
}
|
||||
}
|
||||
|
||||
private function writingIsTimedOut($sent)
|
||||
{
|
||||
$writingTimeout = (int) floor($this->writingTimeout);
|
||||
if (0 === $writingTimeout) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($sent !== $this->lastSentBytes) {
|
||||
$this->lastWritingAt = time();
|
||||
$this->lastSentBytes = $sent;
|
||||
|
||||
return false;
|
||||
} else {
|
||||
usleep(100);
|
||||
}
|
||||
|
||||
if ((time() - $this->lastWritingAt) >= $writingTimeout) {
|
||||
$this->closeSocket();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ class StreamHandler extends AbstractProcessingHandler
|
||||
|
||||
/**
|
||||
* @param resource|string $stream
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param int $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 int|null $filePermission Optional file permissions (default (0644) are only for owner read/write)
|
||||
* @param Boolean $useLocking Try to lock log file before doing any writes
|
||||
@@ -59,12 +59,22 @@ class StreamHandler extends AbstractProcessingHandler
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if (is_resource($this->stream)) {
|
||||
if ($this->url && is_resource($this->stream)) {
|
||||
fclose($this->stream);
|
||||
}
|
||||
$this->stream = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the currently active stream if it is open
|
||||
*
|
||||
* @return resource|null
|
||||
*/
|
||||
public function getStream()
|
||||
{
|
||||
return $this->stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace Monolog\Handler;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
|
||||
/**
|
||||
* SwiftMailerHandler uses Swift_Mailer to send the emails
|
||||
@@ -26,7 +27,7 @@ class SwiftMailerHandler extends MailHandler
|
||||
/**
|
||||
* @param \Swift_Mailer $mailer The mailer to use
|
||||
* @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param int $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(\Swift_Mailer $mailer, $message, $level = Logger::ERROR, $bubble = true)
|
||||
@@ -48,8 +49,8 @@ class SwiftMailerHandler extends MailHandler
|
||||
/**
|
||||
* Creates instance of Swift_Message to be sent
|
||||
*
|
||||
* @param string $content formatted email body to be sent
|
||||
* @param array $records Log records that formed the content
|
||||
* @param string $content formatted email body to be sent
|
||||
* @param array $records Log records that formed the content
|
||||
* @return \Swift_Message
|
||||
*/
|
||||
protected function buildMessage($content, array $records)
|
||||
@@ -66,6 +67,11 @@ class SwiftMailerHandler extends MailHandler
|
||||
throw new \InvalidArgumentException('Could not resolve message as instance of Swift_Message or a callable returning it');
|
||||
}
|
||||
|
||||
if ($records) {
|
||||
$subjectFormatter = new LineFormatter($message->getSubject());
|
||||
$message->setSubject($subjectFormatter->format($this->getHighestRecord($records)));
|
||||
}
|
||||
|
||||
$message->setBody($content);
|
||||
$message->setDate(time());
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class SyslogHandler extends AbstractSyslogHandler
|
||||
/**
|
||||
* @param string $ident
|
||||
* @param mixed $facility
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param int $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 int $logopts Option flags for the openlog() call, defaults to LOG_PID
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,7 @@ class SyslogUdpHandler extends AbstractSyslogHandler
|
||||
* @param string $host
|
||||
* @param int $port
|
||||
* @param mixed $facility
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
* @param int $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($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true)
|
||||
|
||||
@@ -18,50 +18,50 @@ namespace Monolog\Handler;
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* @method boolean hasEmergency($record)
|
||||
* @method boolean hasAlert($record)
|
||||
* @method boolean hasCritical($record)
|
||||
* @method boolean hasError($record)
|
||||
* @method boolean hasWarning($record)
|
||||
* @method boolean hasNotice($record)
|
||||
* @method boolean hasInfo($record)
|
||||
* @method boolean hasDebug($record)
|
||||
* @method bool hasEmergency($record)
|
||||
* @method bool hasAlert($record)
|
||||
* @method bool hasCritical($record)
|
||||
* @method bool hasError($record)
|
||||
* @method bool hasWarning($record)
|
||||
* @method bool hasNotice($record)
|
||||
* @method bool hasInfo($record)
|
||||
* @method bool hasDebug($record)
|
||||
*
|
||||
* @method boolean hasEmergencyRecords()
|
||||
* @method boolean hasAlertRecords()
|
||||
* @method boolean hasCriticalRecords()
|
||||
* @method boolean hasErrorRecords()
|
||||
* @method boolean hasWarningRecords()
|
||||
* @method boolean hasNoticeRecords()
|
||||
* @method boolean hasInfoRecords()
|
||||
* @method boolean hasDebugRecords()
|
||||
* @method bool hasEmergencyRecords()
|
||||
* @method bool hasAlertRecords()
|
||||
* @method bool hasCriticalRecords()
|
||||
* @method bool hasErrorRecords()
|
||||
* @method bool hasWarningRecords()
|
||||
* @method bool hasNoticeRecords()
|
||||
* @method bool hasInfoRecords()
|
||||
* @method bool hasDebugRecords()
|
||||
*
|
||||
* @method boolean hasEmergencyThatContains($message)
|
||||
* @method boolean hasAlertThatContains($message)
|
||||
* @method boolean hasCriticalThatContains($message)
|
||||
* @method boolean hasErrorThatContains($message)
|
||||
* @method boolean hasWarningThatContains($message)
|
||||
* @method boolean hasNoticeThatContains($message)
|
||||
* @method boolean hasInfoThatContains($message)
|
||||
* @method boolean hasDebugThatContains($message)
|
||||
* @method bool hasEmergencyThatContains($message)
|
||||
* @method bool hasAlertThatContains($message)
|
||||
* @method bool hasCriticalThatContains($message)
|
||||
* @method bool hasErrorThatContains($message)
|
||||
* @method bool hasWarningThatContains($message)
|
||||
* @method bool hasNoticeThatContains($message)
|
||||
* @method bool hasInfoThatContains($message)
|
||||
* @method bool hasDebugThatContains($message)
|
||||
*
|
||||
* @method boolean hasEmergencyThatMatches($message)
|
||||
* @method boolean hasAlertThatMatches($message)
|
||||
* @method boolean hasCriticalThatMatches($message)
|
||||
* @method boolean hasErrorThatMatches($message)
|
||||
* @method boolean hasWarningThatMatches($message)
|
||||
* @method boolean hasNoticeThatMatches($message)
|
||||
* @method boolean hasInfoThatMatches($message)
|
||||
* @method boolean hasDebugThatMatches($message)
|
||||
* @method bool hasEmergencyThatMatches($message)
|
||||
* @method bool hasAlertThatMatches($message)
|
||||
* @method bool hasCriticalThatMatches($message)
|
||||
* @method bool hasErrorThatMatches($message)
|
||||
* @method bool hasWarningThatMatches($message)
|
||||
* @method bool hasNoticeThatMatches($message)
|
||||
* @method bool hasInfoThatMatches($message)
|
||||
* @method bool hasDebugThatMatches($message)
|
||||
*
|
||||
* @method boolean hasEmergencyThatPasses($message)
|
||||
* @method boolean hasAlertThatPasses($message)
|
||||
* @method boolean hasCriticalThatPasses($message)
|
||||
* @method boolean hasErrorThatPasses($message)
|
||||
* @method boolean hasWarningThatPasses($message)
|
||||
* @method boolean hasNoticeThatPasses($message)
|
||||
* @method boolean hasInfoThatPasses($message)
|
||||
* @method boolean hasDebugThatPasses($message)
|
||||
* @method bool hasEmergencyThatPasses($message)
|
||||
* @method bool hasAlertThatPasses($message)
|
||||
* @method bool hasCriticalThatPasses($message)
|
||||
* @method bool hasErrorThatPasses($message)
|
||||
* @method bool hasWarningThatPasses($message)
|
||||
* @method bool hasNoticeThatPasses($message)
|
||||
* @method bool hasInfoThatPasses($message)
|
||||
* @method bool hasDebugThatPasses($message)
|
||||
*/
|
||||
class TestHandler extends AbstractProcessingHandler
|
||||
{
|
||||
@@ -73,6 +73,12 @@ class TestHandler extends AbstractProcessingHandler
|
||||
return $this->records;
|
||||
}
|
||||
|
||||
public function clear()
|
||||
{
|
||||
$this->records = array();
|
||||
$this->recordsByLevel = array();
|
||||
}
|
||||
|
||||
protected function hasRecordRecords($level)
|
||||
{
|
||||
return isset($this->recordsByLevel[$level]);
|
||||
|
||||
90
vendor/monolog/monolog/src/Monolog/Logger.php
vendored
90
vendor/monolog/monolog/src/Monolog/Logger.php
vendored
@@ -92,14 +92,14 @@ class Logger implements LoggerInterface
|
||||
* @var array $levels Logging levels
|
||||
*/
|
||||
protected static $levels = array(
|
||||
100 => 'DEBUG',
|
||||
200 => 'INFO',
|
||||
250 => 'NOTICE',
|
||||
300 => 'WARNING',
|
||||
400 => 'ERROR',
|
||||
500 => 'CRITICAL',
|
||||
550 => 'ALERT',
|
||||
600 => 'EMERGENCY',
|
||||
self::DEBUG => 'DEBUG',
|
||||
self::INFO => 'INFO',
|
||||
self::NOTICE => 'NOTICE',
|
||||
self::WARNING => 'WARNING',
|
||||
self::ERROR => 'ERROR',
|
||||
self::CRITICAL => 'CRITICAL',
|
||||
self::ALERT => 'ALERT',
|
||||
self::EMERGENCY => 'EMERGENCY',
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -128,6 +128,11 @@ class Logger implements LoggerInterface
|
||||
*/
|
||||
protected $processors;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $microsecondTimestamps = true;
|
||||
|
||||
/**
|
||||
* @param string $name The logging channel
|
||||
* @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc.
|
||||
@@ -148,10 +153,23 @@ class Logger implements LoggerInterface
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new cloned instance with the name changed
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function withName($name)
|
||||
{
|
||||
$new = clone $this;
|
||||
$new->name = $name;
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes a handler on to the stack.
|
||||
*
|
||||
* @param HandlerInterface $handler
|
||||
* @param HandlerInterface $handler
|
||||
* @return $this
|
||||
*/
|
||||
public function pushHandler(HandlerInterface $handler)
|
||||
@@ -180,7 +198,7 @@ class Logger implements LoggerInterface
|
||||
*
|
||||
* If a map is passed, keys will be ignored.
|
||||
*
|
||||
* @param HandlerInterface[] $handlers
|
||||
* @param HandlerInterface[] $handlers
|
||||
* @return $this
|
||||
*/
|
||||
public function setHandlers(array $handlers)
|
||||
@@ -204,7 +222,7 @@ class Logger implements LoggerInterface
|
||||
/**
|
||||
* Adds a processor on to the stack.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @param callable $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function pushProcessor($callback)
|
||||
@@ -239,10 +257,28 @@ class Logger implements LoggerInterface
|
||||
return $this->processors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Control the use of microsecond resolution timestamps in the 'datetime'
|
||||
* member of new records.
|
||||
*
|
||||
* Generating microsecond resolution timestamps by calling
|
||||
* microtime(true), formatting the result via sprintf() and then parsing
|
||||
* the resulting string via \DateTime::createFromFormat() can incur
|
||||
* a measurable runtime overhead vs simple usage of DateTime to capture
|
||||
* a second resolution timestamp in systems which generate a large number
|
||||
* of log events.
|
||||
*
|
||||
* @param bool $micro True to use microtime() to create timestamps
|
||||
*/
|
||||
public function useMicrosecondTimestamps($micro)
|
||||
{
|
||||
$this->microsecondTimestamps = (bool) $micro;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a log record.
|
||||
*
|
||||
* @param integer $level The logging level
|
||||
* @param int $level The logging level
|
||||
* @param string $message The log message
|
||||
* @param array $context The log context
|
||||
* @return Boolean Whether the record has been processed
|
||||
@@ -257,11 +293,14 @@ class Logger implements LoggerInterface
|
||||
|
||||
// check if any handler will handle this message so we can return early and save cycles
|
||||
$handlerKey = null;
|
||||
foreach ($this->handlers as $key => $handler) {
|
||||
reset($this->handlers);
|
||||
while ($handler = current($this->handlers)) {
|
||||
if ($handler->isHandling(array('level' => $level))) {
|
||||
$handlerKey = $key;
|
||||
$handlerKey = key($this->handlers);
|
||||
break;
|
||||
}
|
||||
|
||||
next($this->handlers);
|
||||
}
|
||||
|
||||
if (null === $handlerKey) {
|
||||
@@ -272,22 +311,33 @@ class Logger implements LoggerInterface
|
||||
static::$timezone = new \DateTimeZone(date_default_timezone_get() ?: 'UTC');
|
||||
}
|
||||
|
||||
if ($this->microsecondTimestamps) {
|
||||
$ts = \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), static::$timezone);
|
||||
} else {
|
||||
$ts = new \DateTime(null, static::$timezone);
|
||||
}
|
||||
$ts->setTimezone(static::$timezone);
|
||||
|
||||
$record = array(
|
||||
'message' => (string) $message,
|
||||
'context' => $context,
|
||||
'level' => $level,
|
||||
'level_name' => $levelName,
|
||||
'channel' => $this->name,
|
||||
'datetime' => \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), static::$timezone)->setTimezone(static::$timezone),
|
||||
'datetime' => $ts,
|
||||
'extra' => array(),
|
||||
);
|
||||
|
||||
foreach ($this->processors as $processor) {
|
||||
$record = call_user_func($processor, $record);
|
||||
}
|
||||
while (isset($this->handlers[$handlerKey]) &&
|
||||
false === $this->handlers[$handlerKey]->handle($record)) {
|
||||
$handlerKey++;
|
||||
|
||||
while ($handler = current($this->handlers)) {
|
||||
if (true === $handler->handle($record)) {
|
||||
break;
|
||||
}
|
||||
|
||||
next($this->handlers);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -402,7 +452,7 @@ class Logger implements LoggerInterface
|
||||
/**
|
||||
* Gets the name of the logging level.
|
||||
*
|
||||
* @param integer $level
|
||||
* @param int $level
|
||||
* @return string
|
||||
*/
|
||||
public static function getLevelName($level)
|
||||
@@ -432,7 +482,7 @@ class Logger implements LoggerInterface
|
||||
/**
|
||||
* Checks whether the Logger has a handler that listens on the given level
|
||||
*
|
||||
* @param integer $level
|
||||
* @param int $level
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isHandling($level)
|
||||
|
||||
@@ -30,15 +30,18 @@ class IntrospectionProcessor
|
||||
|
||||
private $skipClassesPartials;
|
||||
|
||||
private $skipStackFramesCount;
|
||||
|
||||
private $skipFunctions = array(
|
||||
'call_user_func',
|
||||
'call_user_func_array',
|
||||
);
|
||||
|
||||
public function __construct($level = Logger::DEBUG, array $skipClassesPartials = array())
|
||||
public function __construct($level = Logger::DEBUG, array $skipClassesPartials = array(), $skipStackFramesCount = 0)
|
||||
{
|
||||
$this->level = Logger::toMonologLevel($level);
|
||||
$this->skipClassesPartials = array_merge(array('Monolog\\'), $skipClassesPartials);
|
||||
$this->skipStackFramesCount = $skipStackFramesCount;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +55,7 @@ class IntrospectionProcessor
|
||||
return $record;
|
||||
}
|
||||
|
||||
$trace = debug_backtrace();
|
||||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
|
||||
// skip first since it's always the current method
|
||||
array_shift($trace);
|
||||
@@ -77,6 +80,8 @@ class IntrospectionProcessor
|
||||
break;
|
||||
}
|
||||
|
||||
$i += $this->skipStackFramesCount;
|
||||
|
||||
// we should have the call source now
|
||||
$record['extra'] = array_merge(
|
||||
$record['extra'],
|
||||
|
||||
@@ -19,18 +19,18 @@ namespace Monolog\Processor;
|
||||
abstract class MemoryProcessor
|
||||
{
|
||||
/**
|
||||
* @var boolean If true, get the real size of memory allocated from system. Else, only the memory used by emalloc() is reported.
|
||||
* @var bool If true, get the real size of memory allocated from system. Else, only the memory used by emalloc() is reported.
|
||||
*/
|
||||
protected $realUsage;
|
||||
|
||||
/**
|
||||
* @var boolean If true, then format memory size to human readable string (MB, KB, B depending on size)
|
||||
* @var bool If true, then format memory size to human readable string (MB, KB, B depending on size)
|
||||
*/
|
||||
protected $useFormatting;
|
||||
|
||||
/**
|
||||
* @param boolean $realUsage Set this to true to get the real size of memory allocated from system.
|
||||
* @param boolean $useFormatting If true, then format memory size to human readable string (MB, KB, B depending on size)
|
||||
* @param bool $realUsage Set this to true to get the real size of memory allocated from system.
|
||||
* @param bool $useFormatting If true, then format memory size to human readable string (MB, KB, B depending on size)
|
||||
*/
|
||||
public function __construct($realUsage = true, $useFormatting = true)
|
||||
{
|
||||
|
||||
@@ -24,6 +24,10 @@ class WebProcessor
|
||||
protected $serverData;
|
||||
|
||||
/**
|
||||
* Default fields
|
||||
*
|
||||
* Array is structured as [key in record.extra => key in $serverData]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $extraFields = array(
|
||||
@@ -36,7 +40,7 @@ class WebProcessor
|
||||
|
||||
/**
|
||||
* @param array|\ArrayAccess $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data
|
||||
* @param array|null $extraFields Extra field names to be added (all available by default)
|
||||
* @param array|null $extraFields Field names and the related key inside $serverData to be added. If not provided it defaults to: url, ip, http_method, server, referrer
|
||||
*/
|
||||
public function __construct($serverData = null, array $extraFields = null)
|
||||
{
|
||||
@@ -49,10 +53,14 @@ class WebProcessor
|
||||
}
|
||||
|
||||
if (null !== $extraFields) {
|
||||
foreach (array_keys($this->extraFields) as $fieldName) {
|
||||
if (!in_array($fieldName, $extraFields)) {
|
||||
unset($this->extraFields[$fieldName]);
|
||||
if (isset($extraFields[0])) {
|
||||
foreach (array_keys($this->extraFields) as $fieldName) {
|
||||
if (!in_array($fieldName, $extraFields)) {
|
||||
unset($this->extraFields[$fieldName]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->extraFields = $extraFields;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class Registry
|
||||
*
|
||||
* @param Logger $logger Instance of the logging channel
|
||||
* @param string|null $name Name of the logging channel ($logger->getName() by default)
|
||||
* @param boolean $overwrite Overwrite instance in the registry if the given name already exists?
|
||||
* @param bool $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)
|
||||
@@ -107,8 +107,8 @@ class Registry
|
||||
* 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
|
||||
* @return Logger Requested instance of Logger
|
||||
*/
|
||||
public static function getInstance($name)
|
||||
{
|
||||
@@ -124,8 +124,8 @@ class Registry
|
||||
*
|
||||
* @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
|
||||
* @return Logger Requested instance of Logger
|
||||
*/
|
||||
public static function __callStatic($name, $arguments)
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@ class ChromePHPFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'extra' => array('ip' => '127.0.0.1'),
|
||||
),
|
||||
'unknown',
|
||||
'error'
|
||||
'error',
|
||||
),
|
||||
$message
|
||||
);
|
||||
@@ -75,7 +75,7 @@ class ChromePHPFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'extra' => array('ip' => '127.0.0.1'),
|
||||
),
|
||||
'test : 14',
|
||||
'error'
|
||||
'error',
|
||||
),
|
||||
$message
|
||||
);
|
||||
@@ -104,7 +104,7 @@ class ChromePHPFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'meh',
|
||||
'log',
|
||||
'unknown',
|
||||
'log'
|
||||
'log',
|
||||
),
|
||||
$message
|
||||
);
|
||||
@@ -143,13 +143,13 @@ class ChromePHPFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'meh',
|
||||
'log',
|
||||
'unknown',
|
||||
'info'
|
||||
'info',
|
||||
),
|
||||
array(
|
||||
'foo',
|
||||
'log2',
|
||||
'unknown',
|
||||
'warn'
|
||||
'warn',
|
||||
),
|
||||
),
|
||||
$formatter->formatBatch($records)
|
||||
|
||||
@@ -42,7 +42,7 @@ class ElasticaFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
// expected values
|
||||
$expected = $msg;
|
||||
$expected['datetime'] = '1970-01-01T00:00:00+0000';
|
||||
$expected['datetime'] = '1970-01-01T00:00:00.000000+00:00';
|
||||
$expected['context'] = array(
|
||||
'class' => '[object] (stdClass: {})',
|
||||
'foo' => 7,
|
||||
|
||||
62
vendor/monolog/monolog/tests/Monolog/Formatter/FluentdFormatterTest.php
vendored
Normal file
62
vendor/monolog/monolog/tests/Monolog/Formatter/FluentdFormatterTest.php
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
<?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\Formatter;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\TestCase;
|
||||
|
||||
class FluentdFormatterTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Monolog\Formatter\FluentdFormatter::__construct
|
||||
* @covers Monolog\Formatter\FluentdFormatter::isUsingLevelsInTag
|
||||
*/
|
||||
public function testConstruct()
|
||||
{
|
||||
$formatter = new FluentdFormatter();
|
||||
$this->assertEquals(false, $formatter->isUsingLevelsInTag());
|
||||
$formatter = new FluentdFormatter(false);
|
||||
$this->assertEquals(false, $formatter->isUsingLevelsInTag());
|
||||
$formatter = new FluentdFormatter(true);
|
||||
$this->assertEquals(true, $formatter->isUsingLevelsInTag());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\FluentdFormatter::format
|
||||
*/
|
||||
public function testFormat()
|
||||
{
|
||||
$record = $this->getRecord(Logger::WARNING);
|
||||
$record['datetime'] = new \DateTime("@0");
|
||||
|
||||
$formatter = new FluentdFormatter();
|
||||
$this->assertEquals(
|
||||
'["test",0,{"message":"test","extra":[],"level":300,"level_name":"WARNING"}]',
|
||||
$formatter->format($record)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\FluentdFormatter::format
|
||||
*/
|
||||
public function testFormatWithTag()
|
||||
{
|
||||
$record = $this->getRecord(Logger::ERROR);
|
||||
$record['datetime'] = new \DateTime("@0");
|
||||
|
||||
$formatter = new FluentdFormatter(true);
|
||||
$this->assertEquals(
|
||||
'["test.error",0,{"message":"test","extra":[]}]',
|
||||
$formatter->format($record)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -108,7 +108,7 @@ class GelfMessageFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => 'pair'),
|
||||
'message' => 'log'
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = $formatter->format($record);
|
||||
@@ -145,11 +145,11 @@ class GelfMessageFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'context' => array('from' => 'logger', 'exception' => array(
|
||||
'class' => '\Exception',
|
||||
'file' => '/some/file/in/dir.php:56',
|
||||
'trace' => array('/some/file/1.php:23', '/some/file/2.php:3')
|
||||
'trace' => array('/some/file/1.php:23', '/some/file/2.php:3'),
|
||||
)),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array(),
|
||||
'message' => 'log'
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = $formatter->format($record);
|
||||
@@ -173,7 +173,7 @@ class GelfMessageFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => 'pair'),
|
||||
'message' => 'log'
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = $formatter->format($record);
|
||||
@@ -197,6 +197,36 @@ class GelfMessageFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals('pair', $message_array['_EXTkey']);
|
||||
}
|
||||
|
||||
public function testFormatWithLargeData()
|
||||
{
|
||||
$formatter = new GelfMessageFormatter();
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('exception' => str_repeat(' ', 32767)),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => str_repeat(' ', 32767)),
|
||||
'message' => 'log'
|
||||
);
|
||||
$message = $formatter->format($record);
|
||||
$messageArray = $message->toArray();
|
||||
|
||||
// 200 for padding + metadata
|
||||
$length = 200;
|
||||
|
||||
foreach ($messageArray as $key => $value) {
|
||||
if (!in_array($key, array('level', 'timestamp'))) {
|
||||
$length += strlen($value);
|
||||
}
|
||||
}
|
||||
|
||||
// in graylog2/gelf-php before 1.4.1 empty strings are filtered and won't be included in the message
|
||||
// though it should be sufficient to ensure that the entire message length does not exceed the maximum
|
||||
// length being allowed
|
||||
$this->assertLessThanOrEqual(32766, $length, 'The message length is no longer than the maximum allowed length');
|
||||
}
|
||||
|
||||
private function isLegacy()
|
||||
{
|
||||
return interface_exists('\Gelf\IMessagePublisher');
|
||||
|
||||
@@ -75,4 +75,48 @@ class JsonFormatterTest extends TestCase
|
||||
});
|
||||
$this->assertEquals(implode("\n", $expected), $formatter->formatBatch($records));
|
||||
}
|
||||
|
||||
public function testDefFormatWithException()
|
||||
{
|
||||
$formatter = new JsonFormatter();
|
||||
$exception = new \RuntimeException('Foo');
|
||||
$message = $formatter->format(array(
|
||||
'level_name' => 'CRITICAL',
|
||||
'channel' => 'core',
|
||||
'context' => array('exception' => $exception),
|
||||
'datetime' => new \DateTime(),
|
||||
'extra' => array(),
|
||||
'message' => 'foobar',
|
||||
));
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
$path = substr(json_encode($exception->getFile(), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), 1, -1);
|
||||
} else {
|
||||
$path = substr(json_encode($exception->getFile()), 1, -1);
|
||||
}
|
||||
$this->assertEquals('{"level_name":"CRITICAL","channel":"core","context":{"exception":{"class":"RuntimeException","message":"'.$exception->getMessage().'","code":'.$exception->getCode().',"file":"'.$path.':'.$exception->getLine().'"}},"datetime":'.json_encode(new \DateTime()).',"extra":[],"message":"foobar"}'."\n", $message);
|
||||
}
|
||||
|
||||
public function testDefFormatWithPreviousException()
|
||||
{
|
||||
$formatter = new JsonFormatter();
|
||||
$exception = new \RuntimeException('Foo', 0, new \LogicException('Wut?'));
|
||||
$message = $formatter->format(array(
|
||||
'level_name' => 'CRITICAL',
|
||||
'channel' => 'core',
|
||||
'context' => array('exception' => $exception),
|
||||
'datetime' => new \DateTime(),
|
||||
'extra' => array(),
|
||||
'message' => 'foobar',
|
||||
));
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
$pathPrevious = substr(json_encode($exception->getPrevious()->getFile(), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), 1, -1);
|
||||
$pathException = substr(json_encode($exception->getFile(), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), 1, -1);
|
||||
} else {
|
||||
$pathPrevious = substr(json_encode($exception->getPrevious()->getFile()), 1, -1);
|
||||
$pathException = substr(json_encode($exception->getFile()), 1, -1);
|
||||
}
|
||||
$this->assertEquals('{"level_name":"CRITICAL","channel":"core","context":{"exception":{"class":"RuntimeException","message":"'.$exception->getMessage().'","code":'.$exception->getCode().',"file":"'.$pathException.':'.$exception->getLine().'","previous":{"class":"LogicException","message":"'.$exception->getPrevious()->getMessage().'","code":'.$exception->getPrevious()->getCode().',"file":"'.$pathPrevious.':'.$exception->getPrevious()->getLine().'"}}},"datetime":'.json_encode(new \DateTime()).',"extra":[],"message":"foobar"}'."\n", $message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class LineFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'baz' => 'qux',
|
||||
'bool' => false,
|
||||
'null' => null,
|
||||
)
|
||||
),
|
||||
));
|
||||
$this->assertEquals('['.date('Y-m-d').'] meh.ERROR: foo {"foo":"bar","baz":"qux","bool":false,"null":null} []'."\n", $message);
|
||||
}
|
||||
@@ -91,6 +91,20 @@ class LineFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log '."\n", $message);
|
||||
}
|
||||
|
||||
public function testContextAndExtraReplacement()
|
||||
{
|
||||
$formatter = new LineFormatter('%context.foo% => %extra.foo%');
|
||||
$message = $formatter->format(array(
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('foo' => 'bar'),
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array('foo' => 'xbar'),
|
||||
'message' => 'log',
|
||||
));
|
||||
$this->assertEquals('bar => xbar', $message);
|
||||
}
|
||||
|
||||
public function testDefFormatWithObject()
|
||||
{
|
||||
$formatter = new LineFormatter(null, 'Y-m-d');
|
||||
|
||||
@@ -15,6 +15,13 @@ use Monolog\Logger;
|
||||
|
||||
class LogstashFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function tearDown()
|
||||
{
|
||||
\PHPUnit_Framework_Error_Warning::$enabled = true;
|
||||
|
||||
return parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\LogstashFormatter::format
|
||||
*/
|
||||
@@ -83,7 +90,7 @@ class LogstashFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => 'pair'),
|
||||
'message' => 'log'
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
@@ -116,7 +123,7 @@ class LogstashFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => 'pair'),
|
||||
'message' => 'log'
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
@@ -146,7 +153,7 @@ class LogstashFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => 'pair'),
|
||||
'message' => 'log'
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
@@ -223,7 +230,7 @@ class LogstashFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => 'pair'),
|
||||
'message' => 'log'
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
@@ -252,7 +259,7 @@ class LogstashFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => 'pair'),
|
||||
'message' => 'log'
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
@@ -278,7 +285,7 @@ class LogstashFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => 'pair'),
|
||||
'message' => 'log'
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
@@ -286,4 +293,41 @@ class LogstashFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertArrayHasKey('type', $message);
|
||||
$this->assertEquals('app', $message['type']);
|
||||
}
|
||||
|
||||
public function testFormatWithLatin9Data()
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.5.0', '<')) {
|
||||
// Ignore the warning that will be emitted by PHP <5.5.0
|
||||
\PHPUnit_Framework_Error_Warning::$enabled = false;
|
||||
}
|
||||
$formatter = new LogstashFormatter('test', 'hostname');
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => '¯\_(ツ)_/¯',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array(
|
||||
'user_agent' => "\xD6WN; FBCR/OrangeEspa\xF1a; Vers\xE3o/4.0; F\xE4rist",
|
||||
),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
|
||||
$this->assertEquals("1970-01-01T00:00:00.000000+00:00", $message['@timestamp']);
|
||||
$this->assertEquals('log', $message['@message']);
|
||||
$this->assertEquals('¯\_(ツ)_/¯', $message['@fields']['channel']);
|
||||
$this->assertContains('¯\_(ツ)_/¯', $message['@tags']);
|
||||
$this->assertEquals(Logger::ERROR, $message['@fields']['level']);
|
||||
$this->assertEquals('test', $message['@type']);
|
||||
$this->assertEquals('hostname', $message['@source']);
|
||||
if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
|
||||
$this->assertEquals('ÖWN; FBCR/OrangeEspaña; Versão/4.0; Färist', $message['@fields']['user_agent']);
|
||||
} else {
|
||||
// PHP <5.5 does not return false for an element encoding failure,
|
||||
// instead it emits a warning (possibly) and nulls the value.
|
||||
$this->assertEquals(null, $message['@fields']['user_agent']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
<?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\Formatter;
|
||||
|
||||
use Monolog\Logger;
|
||||
@@ -128,9 +137,9 @@ class MongoDBFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'property' => 'anything',
|
||||
'nest3' => array(
|
||||
'nest4' => 'value',
|
||||
'property' => 'nothing'
|
||||
)
|
||||
)
|
||||
'property' => 'nothing',
|
||||
),
|
||||
),
|
||||
),
|
||||
'level' => Logger::WARNING,
|
||||
'level_name' => Logger::getLevelName(Logger::WARNING),
|
||||
@@ -147,7 +156,7 @@ class MongoDBFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'nest2' => array(
|
||||
'property' => 'anything',
|
||||
'nest3' => '[...]',
|
||||
)
|
||||
),
|
||||
),
|
||||
$formattedResult['context']
|
||||
);
|
||||
@@ -165,8 +174,8 @@ class MongoDBFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'nest4' => array(
|
||||
'property' => 'nothing',
|
||||
),
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
'level' => Logger::WARNING,
|
||||
'level_name' => Logger::getLevelName(Logger::WARNING),
|
||||
@@ -186,9 +195,9 @@ class MongoDBFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'property' => 'anything',
|
||||
'nest4' => array(
|
||||
'property' => 'nothing',
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
),
|
||||
$formattedResult['context']
|
||||
);
|
||||
@@ -205,7 +214,7 @@ class MongoDBFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
$record = array(
|
||||
'message' => 'some log message',
|
||||
'context' => array(
|
||||
'nest2' => $someObject
|
||||
'nest2' => $someObject,
|
||||
),
|
||||
'level' => Logger::WARNING,
|
||||
'level_name' => Logger::getLevelName(Logger::WARNING),
|
||||
|
||||
@@ -16,6 +16,13 @@ namespace Monolog\Formatter;
|
||||
*/
|
||||
class NormalizerFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function tearDown()
|
||||
{
|
||||
\PHPUnit_Framework_Error_Warning::$enabled = true;
|
||||
|
||||
return parent::tearDown();
|
||||
}
|
||||
|
||||
public function testFormat()
|
||||
{
|
||||
$formatter = new NormalizerFormatter('Y-m-d');
|
||||
@@ -51,7 +58,7 @@ class NormalizerFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'inf' => 'INF',
|
||||
'-inf' => '-INF',
|
||||
'nan' => 'NaN',
|
||||
)
|
||||
),
|
||||
), $formatted);
|
||||
}
|
||||
|
||||
@@ -74,10 +81,19 @@ class NormalizerFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'message' => $e2->getMessage(),
|
||||
'code' => $e2->getCode(),
|
||||
'file' => $e2->getFile().':'.$e2->getLine(),
|
||||
)
|
||||
),
|
||||
), $formatted);
|
||||
}
|
||||
|
||||
public function testFormatToStringExceptionHandle()
|
||||
{
|
||||
$formatter = new NormalizerFormatter('Y-m-d');
|
||||
$this->setExpectedException('RuntimeException', 'Could not convert to string');
|
||||
$formatter->format(array(
|
||||
'myObject' => new TestToStringError(),
|
||||
));
|
||||
}
|
||||
|
||||
public function testBatchFormat()
|
||||
{
|
||||
$formatter = new NormalizerFormatter('Y-m-d');
|
||||
@@ -179,17 +195,101 @@ class NormalizerFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testThrowsOnInvalidEncoding()
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.5.0', '<')) {
|
||||
// Ignore the warning that will be emitted by PHP <5.5.0
|
||||
\PHPUnit_Framework_Error_Warning::$enabled = false;
|
||||
}
|
||||
$formatter = new NormalizerFormatter();
|
||||
$reflMethod = new \ReflectionMethod($formatter, 'toJson');
|
||||
$reflMethod->setAccessible(true);
|
||||
|
||||
// send an invalid unicode sequence
|
||||
$res = $reflMethod->invoke($formatter, array('message' => "\xB1\x31"));
|
||||
// send an invalid unicode sequence as a object that can't be cleaned
|
||||
$record = new \stdClass;
|
||||
$record->message = "\xB1\x31";
|
||||
$res = $reflMethod->invoke($formatter, $record);
|
||||
if (PHP_VERSION_ID < 50500 && $res === '{"message":null}') {
|
||||
throw new \RuntimeException('PHP 5.3/5.4 throw a warning and null the value instead of returning false entirely');
|
||||
}
|
||||
}
|
||||
|
||||
public function testConvertsInvalidEncodingAsLatin9()
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.5.0', '<')) {
|
||||
// Ignore the warning that will be emitted by PHP <5.5.0
|
||||
\PHPUnit_Framework_Error_Warning::$enabled = false;
|
||||
}
|
||||
$formatter = new NormalizerFormatter();
|
||||
$reflMethod = new \ReflectionMethod($formatter, 'toJson');
|
||||
$reflMethod->setAccessible(true);
|
||||
|
||||
$res = $reflMethod->invoke($formatter, array('message' => "\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE"));
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
|
||||
$this->assertSame('{"message":"€ŠšŽžŒœŸ"}', $res);
|
||||
} else {
|
||||
// PHP <5.5 does not return false for an element encoding failure,
|
||||
// instead it emits a warning (possibly) and nulls the value.
|
||||
$this->assertSame('{"message":null}', $res);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $in Input
|
||||
* @param mixed $expect Expected output
|
||||
* @covers Monolog\Formatter\NormalizerFormatter::detectAndCleanUtf8
|
||||
* @dataProvider providesDetectAndCleanUtf8
|
||||
*/
|
||||
public function testDetectAndCleanUtf8($in, $expect)
|
||||
{
|
||||
$formatter = new NormalizerFormatter();
|
||||
$formatter->detectAndCleanUtf8($in);
|
||||
$this->assertSame($expect, $in);
|
||||
}
|
||||
|
||||
public function providesDetectAndCleanUtf8()
|
||||
{
|
||||
$obj = new \stdClass;
|
||||
|
||||
return array(
|
||||
'null' => array(null, null),
|
||||
'int' => array(123, 123),
|
||||
'float' => array(123.45, 123.45),
|
||||
'bool false' => array(false, false),
|
||||
'bool true' => array(true, true),
|
||||
'ascii string' => array('abcdef', 'abcdef'),
|
||||
'latin9 string' => array("\xB1\x31\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE\xFF", '±1€ŠšŽžŒœŸÿ'),
|
||||
'unicode string' => array('¤¦¨´¸¼½¾€ŠšŽžŒœŸ', '¤¦¨´¸¼½¾€ŠšŽžŒœŸ'),
|
||||
'empty array' => array(array(), array()),
|
||||
'array' => array(array('abcdef'), array('abcdef')),
|
||||
'object' => array($obj, $obj),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $code
|
||||
* @param string $msg
|
||||
* @dataProvider providesHandleJsonErrorFailure
|
||||
*/
|
||||
public function testHandleJsonErrorFailure($code, $msg)
|
||||
{
|
||||
$formatter = new NormalizerFormatter();
|
||||
$reflMethod = new \ReflectionMethod($formatter, 'handleJsonError');
|
||||
$reflMethod->setAccessible(true);
|
||||
|
||||
$this->setExpectedException('RuntimeException', $msg);
|
||||
$reflMethod->invoke($formatter, $code, 'faked');
|
||||
}
|
||||
|
||||
public function providesHandleJsonErrorFailure()
|
||||
{
|
||||
return array(
|
||||
'depth' => array(JSON_ERROR_DEPTH, 'Maximum stack depth exceeded'),
|
||||
'state' => array(JSON_ERROR_STATE_MISMATCH, 'Underflow or the modes mismatch'),
|
||||
'ctrl' => array(JSON_ERROR_CTRL_CHAR, 'Unexpected control character found'),
|
||||
'default' => array(-1, 'Unknown error'),
|
||||
);
|
||||
}
|
||||
|
||||
public function testExceptionTraceWithArgs()
|
||||
{
|
||||
if (defined('HHVM_VERSION')) {
|
||||
@@ -268,3 +368,11 @@ class TestStreamFoo
|
||||
return $this->foo . ' - ' . (string) stream_get_contents($this->resource);
|
||||
}
|
||||
}
|
||||
|
||||
class TestToStringError
|
||||
{
|
||||
public function __toString()
|
||||
{
|
||||
throw new \RuntimeException('Could not convert to string');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
<?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\Formatter;
|
||||
|
||||
class ScalarFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
@@ -44,7 +54,7 @@ class ScalarFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'bam' => array(1, 2, 3),
|
||||
'bat' => array('foo' => 'bar'),
|
||||
'bap' => \DateTime::createFromFormat(\DateTime::ISO8601, '1970-01-01T00:00:00+0000'),
|
||||
'ban' => $exception
|
||||
'ban' => $exception,
|
||||
));
|
||||
|
||||
$this->assertSame(array(
|
||||
@@ -59,8 +69,8 @@ class ScalarFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'message' => $exception->getMessage(),
|
||||
'code' => $exception->getCode(),
|
||||
'file' => $exception->getFile() . ':' . $exception->getLine(),
|
||||
'trace' => $this->buildTrace($exception)
|
||||
))
|
||||
'trace' => $this->buildTrace($exception),
|
||||
)),
|
||||
), $formatted);
|
||||
}
|
||||
|
||||
@@ -68,11 +78,11 @@ class ScalarFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$context = array('file' => 'foo', 'line' => 1);
|
||||
$formatted = $this->formatter->format(array(
|
||||
'context' => $context
|
||||
'context' => $context,
|
||||
));
|
||||
|
||||
$this->assertSame(array(
|
||||
'context' => $this->encodeJson($context)
|
||||
'context' => $this->encodeJson($context),
|
||||
), $formatted);
|
||||
}
|
||||
|
||||
@@ -81,8 +91,8 @@ class ScalarFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
$exception = new \Exception('foo');
|
||||
$formatted = $this->formatter->format(array(
|
||||
'context' => array(
|
||||
'exception' => $exception
|
||||
)
|
||||
'exception' => $exception,
|
||||
),
|
||||
));
|
||||
|
||||
$this->assertSame(array(
|
||||
@@ -92,9 +102,9 @@ class ScalarFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
'message' => $exception->getMessage(),
|
||||
'code' => $exception->getCode(),
|
||||
'file' => $exception->getFile() . ':' . $exception->getLine(),
|
||||
'trace' => $this->buildTrace($exception)
|
||||
)
|
||||
))
|
||||
'trace' => $this->buildTrace($exception),
|
||||
),
|
||||
)),
|
||||
), $formatted);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,8 +65,8 @@ class AmqpHandlerTest extends TestCase
|
||||
0,
|
||||
array(
|
||||
'delivery_mode' => 2,
|
||||
'Content-type' => 'application/json'
|
||||
)
|
||||
'content_type' => 'application/json',
|
||||
),
|
||||
);
|
||||
|
||||
$handler->handle($record);
|
||||
@@ -117,8 +117,8 @@ class AmqpHandlerTest extends TestCase
|
||||
null,
|
||||
array(
|
||||
'delivery_mode' => 2,
|
||||
'content_type' => 'application/json'
|
||||
)
|
||||
'content_type' => 'application/json',
|
||||
),
|
||||
);
|
||||
|
||||
$handler->handle($record);
|
||||
|
||||
@@ -41,7 +41,7 @@ class ChromePHPHandlerTest extends TestCase
|
||||
'test',
|
||||
),
|
||||
'request_uri' => '',
|
||||
))))
|
||||
)))),
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $handler->getHeaders());
|
||||
@@ -81,7 +81,7 @@ class ChromePHPHandlerTest extends TestCase
|
||||
),
|
||||
),
|
||||
'request_uri' => '',
|
||||
))))
|
||||
)))),
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $handler->getHeaders());
|
||||
@@ -110,7 +110,7 @@ class ChromePHPHandlerTest extends TestCase
|
||||
'test',
|
||||
),
|
||||
'request_uri' => '',
|
||||
))))
|
||||
)))),
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $handler2->getHeaders());
|
||||
|
||||
165
vendor/monolog/monolog/tests/Monolog/Handler/DeduplicationHandlerTest.php
vendored
Normal file
165
vendor/monolog/monolog/tests/Monolog/Handler/DeduplicationHandlerTest.php
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
<?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\Handler;
|
||||
|
||||
use Monolog\TestCase;
|
||||
use Monolog\Logger;
|
||||
|
||||
class DeduplicationHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Monolog\Handler\DeduplicationHandler::flush
|
||||
*/
|
||||
public function testFlushPassthruIfAllRecordsUnderTrigger()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
@unlink(sys_get_temp_dir().'/monolog_dedup.log');
|
||||
$handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0);
|
||||
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
|
||||
$handler->flush();
|
||||
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
$this->assertTrue($test->hasDebugRecords());
|
||||
$this->assertFalse($test->hasWarningRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\DeduplicationHandler::flush
|
||||
* @covers Monolog\Handler\DeduplicationHandler::appendRecord
|
||||
*/
|
||||
public function testFlushPassthruIfEmptyLog()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
@unlink(sys_get_temp_dir().'/monolog_dedup.log');
|
||||
$handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0);
|
||||
|
||||
$handler->handle($this->getRecord(Logger::ERROR, 'Foo:bar'));
|
||||
$handler->handle($this->getRecord(Logger::CRITICAL, "Foo\nbar"));
|
||||
|
||||
$handler->flush();
|
||||
|
||||
$this->assertTrue($test->hasErrorRecords());
|
||||
$this->assertTrue($test->hasCriticalRecords());
|
||||
$this->assertFalse($test->hasWarningRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\DeduplicationHandler::flush
|
||||
* @covers Monolog\Handler\DeduplicationHandler::appendRecord
|
||||
* @covers Monolog\Handler\DeduplicationHandler::isDuplicate
|
||||
* @depends testFlushPassthruIfEmptyLog
|
||||
*/
|
||||
public function testFlushSkipsIfLogExists()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0);
|
||||
|
||||
$handler->handle($this->getRecord(Logger::ERROR, 'Foo:bar'));
|
||||
$handler->handle($this->getRecord(Logger::CRITICAL, "Foo\nbar"));
|
||||
|
||||
$handler->flush();
|
||||
|
||||
$this->assertFalse($test->hasErrorRecords());
|
||||
$this->assertFalse($test->hasCriticalRecords());
|
||||
$this->assertFalse($test->hasWarningRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\DeduplicationHandler::flush
|
||||
* @covers Monolog\Handler\DeduplicationHandler::appendRecord
|
||||
* @covers Monolog\Handler\DeduplicationHandler::isDuplicate
|
||||
* @depends testFlushPassthruIfEmptyLog
|
||||
*/
|
||||
public function testFlushPassthruIfLogTooOld()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0);
|
||||
|
||||
$record = $this->getRecord(Logger::ERROR);
|
||||
$record['datetime']->modify('+62seconds');
|
||||
$handler->handle($record);
|
||||
$record = $this->getRecord(Logger::CRITICAL);
|
||||
$record['datetime']->modify('+62seconds');
|
||||
$handler->handle($record);
|
||||
|
||||
$handler->flush();
|
||||
|
||||
$this->assertTrue($test->hasErrorRecords());
|
||||
$this->assertTrue($test->hasCriticalRecords());
|
||||
$this->assertFalse($test->hasWarningRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\DeduplicationHandler::flush
|
||||
* @covers Monolog\Handler\DeduplicationHandler::appendRecord
|
||||
* @covers Monolog\Handler\DeduplicationHandler::isDuplicate
|
||||
* @covers Monolog\Handler\DeduplicationHandler::collectLogs
|
||||
*/
|
||||
public function testGcOldLogs()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
@unlink(sys_get_temp_dir().'/monolog_dedup.log');
|
||||
$handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0);
|
||||
|
||||
// handle two records from yesterday, and one recent
|
||||
$record = $this->getRecord(Logger::ERROR);
|
||||
$record['datetime']->modify('-1day -10seconds');
|
||||
$handler->handle($record);
|
||||
$record2 = $this->getRecord(Logger::CRITICAL);
|
||||
$record2['datetime']->modify('-1day -10seconds');
|
||||
$handler->handle($record2);
|
||||
$record3 = $this->getRecord(Logger::CRITICAL);
|
||||
$record3['datetime']->modify('-30seconds');
|
||||
$handler->handle($record3);
|
||||
|
||||
// log is written as none of them are duplicate
|
||||
$handler->flush();
|
||||
$this->assertSame(
|
||||
$record['datetime']->getTimestamp() . ":ERROR:test\n" .
|
||||
$record2['datetime']->getTimestamp() . ":CRITICAL:test\n" .
|
||||
$record3['datetime']->getTimestamp() . ":CRITICAL:test\n",
|
||||
file_get_contents(sys_get_temp_dir() . '/monolog_dedup.log')
|
||||
);
|
||||
$this->assertTrue($test->hasErrorRecords());
|
||||
$this->assertTrue($test->hasCriticalRecords());
|
||||
$this->assertFalse($test->hasWarningRecords());
|
||||
|
||||
// clear test handler
|
||||
$test->clear();
|
||||
$this->assertFalse($test->hasErrorRecords());
|
||||
$this->assertFalse($test->hasCriticalRecords());
|
||||
|
||||
// log new records, duplicate log gets GC'd at the end of this flush call
|
||||
$handler->handle($record = $this->getRecord(Logger::ERROR));
|
||||
$handler->handle($record2 = $this->getRecord(Logger::CRITICAL));
|
||||
$handler->flush();
|
||||
|
||||
// log should now contain the new errors and the previous one that was recent enough
|
||||
$this->assertSame(
|
||||
$record3['datetime']->getTimestamp() . ":CRITICAL:test\n" .
|
||||
$record['datetime']->getTimestamp() . ":ERROR:test\n" .
|
||||
$record2['datetime']->getTimestamp() . ":CRITICAL:test\n",
|
||||
file_get_contents(sys_get_temp_dir() . '/monolog_dedup.log')
|
||||
);
|
||||
$this->assertTrue($test->hasErrorRecords());
|
||||
$this->assertTrue($test->hasCriticalRecords());
|
||||
$this->assertFalse($test->hasWarningRecords());
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass()
|
||||
{
|
||||
@unlink(sys_get_temp_dir().'/monolog_dedup.log');
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ class DynamoDbHandlerTest extends TestCase
|
||||
->method('__call')
|
||||
->with('putItem', array(array(
|
||||
'TableName' => 'foo',
|
||||
'Item' => $formatted
|
||||
'Item' => $formatted,
|
||||
)));
|
||||
|
||||
$handler->handle($record);
|
||||
|
||||
130
vendor/monolog/monolog/tests/Monolog/Handler/HandlerWrapperTest.php
vendored
Normal file
130
vendor/monolog/monolog/tests/Monolog/Handler/HandlerWrapperTest.php
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
<?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\Handler;
|
||||
|
||||
use Monolog\TestCase;
|
||||
|
||||
/**
|
||||
* @author Alexey Karapetov <alexey@karapetov.com>
|
||||
*/
|
||||
class HandlerWrapperTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var HandlerWrapper
|
||||
*/
|
||||
private $wrapper;
|
||||
|
||||
private $handler;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->handler = $this->getMock('Monolog\\Handler\\HandlerInterface');
|
||||
$this->wrapper = new HandlerWrapper($this->handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function trueFalseDataProvider()
|
||||
{
|
||||
return array(
|
||||
array(true),
|
||||
array(false),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $result
|
||||
* @dataProvider trueFalseDataProvider
|
||||
*/
|
||||
public function testIsHandling($result)
|
||||
{
|
||||
$record = $this->getRecord();
|
||||
$this->handler->expects($this->once())
|
||||
->method('isHandling')
|
||||
->with($record)
|
||||
->willReturn($result);
|
||||
|
||||
$this->assertEquals($result, $this->wrapper->isHandling($record));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $result
|
||||
* @dataProvider trueFalseDataProvider
|
||||
*/
|
||||
public function testHandle($result)
|
||||
{
|
||||
$record = $this->getRecord();
|
||||
$this->handler->expects($this->once())
|
||||
->method('handle')
|
||||
->with($record)
|
||||
->willReturn($result);
|
||||
|
||||
$this->assertEquals($result, $this->wrapper->handle($record));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $result
|
||||
* @dataProvider trueFalseDataProvider
|
||||
*/
|
||||
public function testHandleBatch($result)
|
||||
{
|
||||
$records = $this->getMultipleRecords();
|
||||
$this->handler->expects($this->once())
|
||||
->method('handleBatch')
|
||||
->with($records)
|
||||
->willReturn($result);
|
||||
|
||||
$this->assertEquals($result, $this->wrapper->handleBatch($records));
|
||||
}
|
||||
|
||||
public function testPushProcessor()
|
||||
{
|
||||
$processor = function () {};
|
||||
$this->handler->expects($this->once())
|
||||
->method('pushProcessor')
|
||||
->with($processor);
|
||||
|
||||
$this->assertEquals($this->wrapper, $this->wrapper->pushProcessor($processor));
|
||||
}
|
||||
|
||||
public function testPopProcessor()
|
||||
{
|
||||
$processor = function () {};
|
||||
$this->handler->expects($this->once())
|
||||
->method('popProcessor')
|
||||
->willReturn($processor);
|
||||
|
||||
$this->assertEquals($processor, $this->wrapper->popProcessor());
|
||||
}
|
||||
|
||||
public function testSetFormatter()
|
||||
{
|
||||
$formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface');
|
||||
$this->handler->expects($this->once())
|
||||
->method('setFormatter')
|
||||
->with($formatter);
|
||||
|
||||
$this->assertEquals($this->wrapper, $this->wrapper->setFormatter($formatter));
|
||||
}
|
||||
|
||||
public function testGetFormatter()
|
||||
{
|
||||
$formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface');
|
||||
$this->handler->expects($this->once())
|
||||
->method('getFormatter')
|
||||
->willReturn($formatter);
|
||||
|
||||
$this->assertEquals($formatter, $this->wrapper->getFormatter());
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ use Monolog\Logger;
|
||||
class HipChatHandlerTest extends TestCase
|
||||
{
|
||||
private $res;
|
||||
/** @var HipChatHandler */
|
||||
private $handler;
|
||||
|
||||
public function testWriteHeader()
|
||||
@@ -91,6 +92,18 @@ class HipChatHandlerTest extends TestCase
|
||||
$this->assertRegexp('/notify=0&message=test1&message_format=text&color=red&room_id=room1&from=Monolog$/', $content);
|
||||
}
|
||||
|
||||
public function testWriteContentV1WithoutName()
|
||||
{
|
||||
$this->createHandler('myToken', 'room1', null, false, 'hipchat.foo.bar', 'v1');
|
||||
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 1024);
|
||||
|
||||
$this->assertRegexp('/notify=0&message=test1&message_format=text&color=red&room_id=room1&from=$/', $content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWriteCustomHostHeader
|
||||
*/
|
||||
@@ -104,7 +117,7 @@ class HipChatHandlerTest extends TestCase
|
||||
*/
|
||||
public function testWriteContentV2($content)
|
||||
{
|
||||
$this->assertRegexp('/notify=false&message=test1&message_format=text&color=red$/', $content);
|
||||
$this->assertRegexp('/notify=false&message=test1&message_format=text&color=red&from=Monolog$/', $content);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +125,19 @@ class HipChatHandlerTest extends TestCase
|
||||
*/
|
||||
public function testWriteContentV2Notify($content)
|
||||
{
|
||||
$this->assertRegexp('/notify=true&message=test1&message_format=text&color=red$/', $content);
|
||||
$this->assertRegexp('/notify=true&message=test1&message_format=text&color=red&from=Monolog$/', $content);
|
||||
}
|
||||
|
||||
public function testWriteContentV2WithoutName()
|
||||
{
|
||||
$this->createHandler('myToken', 'room1', null, false, 'hipchat.foo.bar', 'v2');
|
||||
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 1024);
|
||||
|
||||
$this->assertRegexp('/notify=false&message=test1&message_format=text&color=red$/', $content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function testWriteWithComplexMessage()
|
||||
@@ -125,6 +150,16 @@ class HipChatHandlerTest extends TestCase
|
||||
$this->assertRegexp('/message=Backup\+of\+database\+%22example%22\+finished\+in\+16\+minutes\./', $content);
|
||||
}
|
||||
|
||||
public function testWriteTruncatesLongMessage()
|
||||
{
|
||||
$this->createHandler();
|
||||
$this->handler->handle($this->getRecord(Logger::CRITICAL, str_repeat('abcde', 2000)));
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 12000);
|
||||
|
||||
$this->assertRegexp('/message='.str_repeat('abcde', 1900).'\+%5Btruncated%5D/', $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideLevelColors
|
||||
*/
|
||||
@@ -174,7 +209,7 @@ class HipChatHandlerTest extends TestCase
|
||||
array(
|
||||
array('level' => Logger::WARNING, 'message' => 'Oh bugger!', 'level_name' => 'warning', 'datetime' => new \DateTime()),
|
||||
array('level' => Logger::NOTICE, 'message' => 'Something noticeable happened.', 'level_name' => 'notice', 'datetime' => new \DateTime()),
|
||||
array('level' => Logger::CRITICAL, 'message' => 'Everything is broken!', 'level_name' => 'critical', 'datetime' => new \DateTime())
|
||||
array('level' => Logger::CRITICAL, 'message' => 'Everything is broken!', 'level_name' => 'critical', 'datetime' => new \DateTime()),
|
||||
),
|
||||
'red',
|
||||
),
|
||||
|
||||
@@ -45,7 +45,7 @@ class LogEntriesHandlerTest extends TestCase
|
||||
$records = array(
|
||||
$this->getRecord(),
|
||||
$this->getRecord(),
|
||||
$this->getRecord()
|
||||
$this->getRecord(),
|
||||
);
|
||||
$this->createHandler();
|
||||
$this->handler->handleBatch($records);
|
||||
|
||||
@@ -12,9 +12,21 @@
|
||||
namespace Monolog\Handler;
|
||||
|
||||
use Monolog\TestCase;
|
||||
use Monolog\Logger;
|
||||
use InvalidArgumentException;
|
||||
|
||||
function mail($to, $subject, $message, $additional_headers = null, $additional_parameters = null)
|
||||
{
|
||||
$GLOBALS['mail'][] = func_get_args();
|
||||
}
|
||||
|
||||
class NativeMailerHandlerTest extends TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
$GLOBALS['mail'] = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
@@ -58,4 +70,42 @@ class NativeMailerHandlerTest extends TestCase
|
||||
$mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org');
|
||||
$mailer->setEncoding("utf-8\r\nFrom: faked@attacker.org");
|
||||
}
|
||||
|
||||
public function testSend()
|
||||
{
|
||||
$to = 'spammer@example.org';
|
||||
$subject = 'dear victim';
|
||||
$from = 'receiver@example.org';
|
||||
|
||||
$mailer = new NativeMailerHandler($to, $subject, $from);
|
||||
$mailer->handleBatch(array());
|
||||
|
||||
// batch is empty, nothing sent
|
||||
$this->assertEmpty($GLOBALS['mail']);
|
||||
|
||||
// non-empty batch
|
||||
$mailer->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz"));
|
||||
$this->assertNotEmpty($GLOBALS['mail']);
|
||||
$this->assertInternalType('array', $GLOBALS['mail']);
|
||||
$this->assertArrayHasKey('0', $GLOBALS['mail']);
|
||||
$params = $GLOBALS['mail'][0];
|
||||
$this->assertCount(5, $params);
|
||||
$this->assertSame($to, $params[0]);
|
||||
$this->assertSame($subject, $params[1]);
|
||||
$this->assertStringEndsWith(" test.ERROR: Foo Bar Baz [] []\n", $params[2]);
|
||||
$this->assertSame("From: $from\r\nContent-type: text/plain; charset=utf-8\r\n", $params[3]);
|
||||
$this->assertSame('', $params[4]);
|
||||
}
|
||||
|
||||
public function testMessageSubjectFormatting()
|
||||
{
|
||||
$mailer = new NativeMailerHandler('to@example.org', 'Alert: %level_name% %message%', 'from@example.org');
|
||||
$mailer->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz"));
|
||||
$this->assertNotEmpty($GLOBALS['mail']);
|
||||
$this->assertInternalType('array', $GLOBALS['mail']);
|
||||
$this->assertArrayHasKey('0', $GLOBALS['mail']);
|
||||
$params = $GLOBALS['mail'][0];
|
||||
$this->assertCount(5, $params);
|
||||
$this->assertSame('Alert: ERROR Foo Bar Baz', $params[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ use PHPUnit_Framework_MockObject_MockObject;
|
||||
*/
|
||||
class PHPConsoleHandlerTest extends TestCase
|
||||
{
|
||||
|
||||
/** @var Connector|PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $connector;
|
||||
/** @var DebugDispatcher|PHPUnit_Framework_MockObject_MockObject */
|
||||
@@ -103,7 +102,7 @@ class PHPConsoleHandlerTest extends TestCase
|
||||
protected function initLogger($handlerOptions = array(), $level = Logger::DEBUG)
|
||||
{
|
||||
return new Logger('test', array(
|
||||
new PHPConsoleHandler($handlerOptions, $this->connector, $level)
|
||||
new PHPConsoleHandler($handlerOptions, $this->connector, $level),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class PushoverHandlerTest extends TestCase
|
||||
|
||||
public function testWriteWithComplexTitle()
|
||||
{
|
||||
$this->createHandler('myToken', 'myUser', 'Backup finished - SQL1', Logger::EMERGENCY);
|
||||
$this->createHandler('myToken', 'myUser', 'Backup finished - SQL1');
|
||||
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 1024);
|
||||
|
||||
@@ -99,6 +99,18 @@ class RavenHandlerTest extends TestCase
|
||||
$this->assertEquals($release, $ravenClient->lastData['release']);
|
||||
}
|
||||
|
||||
public function testFingerprint()
|
||||
{
|
||||
$ravenClient = $this->getRavenClient();
|
||||
$handler = $this->getHandler($ravenClient);
|
||||
|
||||
$fingerprint = array('{{ default }}', 'other value');
|
||||
$record = $this->getRecord(Logger::INFO, 'test', array('fingerprint' => $fingerprint));
|
||||
$handler->handle($record);
|
||||
|
||||
$this->assertEquals($fingerprint, $ravenClient->lastData['fingerprint']);
|
||||
}
|
||||
|
||||
public function testUserContext()
|
||||
{
|
||||
$ravenClient = $this->getRavenClient();
|
||||
@@ -109,7 +121,7 @@ class RavenHandlerTest extends TestCase
|
||||
|
||||
$user = array(
|
||||
'id' => '123',
|
||||
'email' => 'test@test.com'
|
||||
'email' => 'test@test.com',
|
||||
);
|
||||
|
||||
$recordWithContext = $this->getRecord(Logger::INFO, 'test', array('user' => $user));
|
||||
@@ -192,6 +204,22 @@ class RavenHandlerTest extends TestCase
|
||||
$this->assertSame($formatter, $handler->getBatchFormatter());
|
||||
}
|
||||
|
||||
public function testRelease()
|
||||
{
|
||||
$ravenClient = $this->getRavenClient();
|
||||
$handler = $this->getHandler($ravenClient);
|
||||
$release = 'v42.42.42';
|
||||
$handler->setRelease($release);
|
||||
$record = $this->getRecord(Logger::INFO, 'test');
|
||||
$handler->handle($record);
|
||||
$this->assertEquals($release, $ravenClient->lastData['release']);
|
||||
|
||||
$localRelease = 'v41.41.41';
|
||||
$record = $this->getRecord(Logger::INFO, 'test', array('release' => $localRelease));
|
||||
$handler->handle($record);
|
||||
$this->assertEquals($localRelease, $ravenClient->lastData['release']);
|
||||
}
|
||||
|
||||
private function methodThatThrowsAnException()
|
||||
{
|
||||
throw new \Exception('This is an exception');
|
||||
|
||||
@@ -71,7 +71,7 @@ class RedisHandlerTest extends TestCase
|
||||
|
||||
public function testRedisHandleCapped()
|
||||
{
|
||||
$redis = $this->getMock('Redis', array('multi', 'rpush', 'ltrim', 'execute'));
|
||||
$redis = $this->getMock('Redis', array('multi', 'rpush', 'ltrim', 'exec'));
|
||||
|
||||
// Redis uses multi
|
||||
$redis->expects($this->once())
|
||||
@@ -87,7 +87,7 @@ class RedisHandlerTest extends TestCase
|
||||
->will($this->returnSelf());
|
||||
|
||||
$redis->expects($this->once())
|
||||
->method('execute')
|
||||
->method('exec')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
|
||||
|
||||
@@ -70,6 +70,13 @@ class SocketHandlerTest extends TestCase
|
||||
$this->assertEquals(10.25, $this->handler->getTimeout());
|
||||
}
|
||||
|
||||
public function testSetWritingTimeout()
|
||||
{
|
||||
$this->createHandler('localhost:1234');
|
||||
$this->handler->setWritingTimeout(10.25);
|
||||
$this->assertEquals(10.25, $this->handler->getWritingTimeout());
|
||||
}
|
||||
|
||||
public function testSetConnectionString()
|
||||
{
|
||||
$this->createHandler('tcp://localhost:9090');
|
||||
@@ -235,6 +242,26 @@ class SocketHandlerTest extends TestCase
|
||||
$this->assertTrue(is_resource($this->res));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testAvoidInfiniteLoopWhenNoDataIsWrittenForAWritingTimeoutSeconds()
|
||||
{
|
||||
$this->setMockHandler(array('fwrite', 'streamGetMetadata'));
|
||||
|
||||
$this->handler->expects($this->any())
|
||||
->method('fwrite')
|
||||
->will($this->returnValue(0));
|
||||
|
||||
$this->handler->expects($this->any())
|
||||
->method('streamGetMetadata')
|
||||
->will($this->returnValue(array('timed_out' => false)));
|
||||
|
||||
$this->handler->setWritingTimeout(1);
|
||||
|
||||
$this->writeRecord('Hello world');
|
||||
}
|
||||
|
||||
private function createHandler($connectionString)
|
||||
{
|
||||
$this->handler = new SocketHandler($connectionString);
|
||||
|
||||
@@ -35,10 +35,26 @@ class StreamHandlerTest extends TestCase
|
||||
/**
|
||||
* @covers Monolog\Handler\StreamHandler::close
|
||||
*/
|
||||
public function testClose()
|
||||
public function testCloseKeepsExternalHandlersOpen()
|
||||
{
|
||||
$handle = fopen('php://memory', 'a+');
|
||||
$handler = new StreamHandler($handle);
|
||||
$this->assertTrue(is_resource($handle));
|
||||
$handler->close();
|
||||
$this->assertTrue(is_resource($handle));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\StreamHandler::close
|
||||
*/
|
||||
public function testClose()
|
||||
{
|
||||
$handler = new StreamHandler('php://memory');
|
||||
$handler->handle($this->getRecord(Logger::WARNING, 'test'));
|
||||
$streamProp = new \ReflectionProperty('Monolog\Handler\StreamHandler', 'stream');
|
||||
$streamProp->setAccessible(true);
|
||||
$handle = $streamProp->getValue($handler);
|
||||
|
||||
$this->assertTrue(is_resource($handle));
|
||||
$handler->close();
|
||||
$this->assertFalse(is_resource($handle));
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
<?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\Handler;
|
||||
|
||||
use Monolog\Logger;
|
||||
@@ -63,7 +72,32 @@ class SwiftMailerHandlerTest extends TestCase
|
||||
$handler->handleBatch($records);
|
||||
}
|
||||
|
||||
public function testMessageHaveUniqueId() {
|
||||
public function testMessageSubjectFormatting()
|
||||
{
|
||||
// Wire Mailer to expect a specific Swift_Message with a customized Subject
|
||||
$messageTemplate = new \Swift_Message();
|
||||
$messageTemplate->setSubject('Alert: %level_name% %message%');
|
||||
$receivedMessage = null;
|
||||
|
||||
$this->mailer->expects($this->once())
|
||||
->method('send')
|
||||
->with($this->callback(function ($value) use (&$receivedMessage) {
|
||||
$receivedMessage = $value;
|
||||
return true;
|
||||
}));
|
||||
|
||||
$handler = new SwiftMailerHandler($this->mailer, $messageTemplate);
|
||||
|
||||
$records = array(
|
||||
$this->getRecord(Logger::EMERGENCY),
|
||||
);
|
||||
$handler->handleBatch($records);
|
||||
|
||||
$this->assertEquals('Alert: EMERGENCY test', $receivedMessage->getSubject());
|
||||
}
|
||||
|
||||
public function testMessageHaveUniqueId()
|
||||
{
|
||||
$messageTemplate = \Swift_Message::newInstance();
|
||||
$handler = new SwiftMailerHandler($this->mailer, $messageTemplate);
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class ZendMonitorHandlerTest extends TestCase
|
||||
{
|
||||
$record = $this->getRecord();
|
||||
$formatterResult = array(
|
||||
'message' => $record['message']
|
||||
'message' => $record['message'],
|
||||
);
|
||||
|
||||
$zendMonitor = $this->getMockBuilder('Monolog\Handler\ZendMonitorHandler')
|
||||
|
||||
@@ -33,6 +33,19 @@ class LoggerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals('ERROR', Logger::getLevelName(Logger::ERROR));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Logger::withName
|
||||
*/
|
||||
public function testWithName()
|
||||
{
|
||||
$first = new Logger('first', array($handler = new TestHandler()));
|
||||
$second = $first->withName('second');
|
||||
|
||||
$this->assertSame('first', $first->getName());
|
||||
$this->assertSame('second', $second->getName());
|
||||
$this->assertSame($handler, $second->popHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Logger::toMonologLevel
|
||||
*/
|
||||
@@ -303,6 +316,45 @@ class LoggerTest extends \PHPUnit_Framework_TestCase
|
||||
$logger->debug('test');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Logger::addRecord
|
||||
*/
|
||||
public function testHandlersNotCalledBeforeFirstHandlingWithAssocArray()
|
||||
{
|
||||
$handler1 = $this->getMock('Monolog\Handler\HandlerInterface');
|
||||
$handler1->expects($this->never())
|
||||
->method('isHandling')
|
||||
->will($this->returnValue(false))
|
||||
;
|
||||
$handler1->expects($this->once())
|
||||
->method('handle')
|
||||
->will($this->returnValue(false))
|
||||
;
|
||||
|
||||
$handler2 = $this->getMock('Monolog\Handler\HandlerInterface');
|
||||
$handler2->expects($this->once())
|
||||
->method('isHandling')
|
||||
->will($this->returnValue(true))
|
||||
;
|
||||
$handler2->expects($this->once())
|
||||
->method('handle')
|
||||
->will($this->returnValue(false))
|
||||
;
|
||||
|
||||
$handler3 = $this->getMock('Monolog\Handler\HandlerInterface');
|
||||
$handler3->expects($this->once())
|
||||
->method('isHandling')
|
||||
->will($this->returnValue(false))
|
||||
;
|
||||
$handler3->expects($this->never())
|
||||
->method('handle')
|
||||
;
|
||||
|
||||
$logger = new Logger(__METHOD__, array('last' => $handler3, 'second' => $handler2, 'first' => $handler1));
|
||||
|
||||
$logger->debug('test');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Logger::addRecord
|
||||
*/
|
||||
@@ -468,4 +520,29 @@ class LoggerTest extends \PHPUnit_Framework_TestCase
|
||||
\DateTimeZone::listIdentifiers()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider useMicrosecondTimestampsProvider
|
||||
* @covers Monolog\Logger::useMicrosecondTimestamps
|
||||
* @covers Monolog\Logger::addRecord
|
||||
*/
|
||||
public function testUseMicrosecondTimestamps($micro, $assert)
|
||||
{
|
||||
$logger = new Logger('foo');
|
||||
$logger->useMicrosecondTimestamps($micro);
|
||||
$handler = new TestHandler;
|
||||
$logger->pushHandler($handler);
|
||||
$logger->info('test');
|
||||
list($record) = $handler->getRecords();
|
||||
$this->{$assert}('000000', $record['datetime']->format('u'));
|
||||
}
|
||||
|
||||
public function useMicrosecondTimestampsProvider()
|
||||
{
|
||||
return array(
|
||||
// this has a very small chance of a false negative (1/10^6)
|
||||
'with microseconds' => array(true, 'assertNotSame'),
|
||||
'without microseconds' => array(false, 'assertSame'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class PsrLogMessageProcessorTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$message = $proc(array(
|
||||
'message' => '{foo}',
|
||||
'context' => array('foo' => $val)
|
||||
'context' => array('foo' => $val),
|
||||
));
|
||||
$this->assertEquals($expected, $message['message']);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ class UidProcessorTest extends TestCase
|
||||
$record = $processor($this->getRecord());
|
||||
$this->assertArrayHasKey('uid', $record['extra']);
|
||||
}
|
||||
|
||||
public function testGetUid()
|
||||
{
|
||||
$processor = new UidProcessor(10);
|
||||
|
||||
@@ -88,6 +88,21 @@ class WebProcessorTest extends TestCase
|
||||
$this->assertSame(array('url' => 'A', 'http_method' => 'C'), $record['extra']);
|
||||
}
|
||||
|
||||
public function testProcessorConfiguringOfExtraFields()
|
||||
{
|
||||
$server = array(
|
||||
'REQUEST_URI' => 'A',
|
||||
'REMOTE_ADDR' => 'B',
|
||||
'REQUEST_METHOD' => 'C',
|
||||
'SERVER_NAME' => 'F',
|
||||
);
|
||||
|
||||
$processor = new WebProcessor($server, array('url' => 'REMOTE_ADDR'));
|
||||
$record = $processor($this->getRecord());
|
||||
|
||||
$this->assertSame(array('url' => 'B'), $record['extra']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException UnexpectedValueException
|
||||
*/
|
||||
|
||||
@@ -39,7 +39,7 @@ class TestCase extends \PHPUnit_Framework_TestCase
|
||||
$this->getRecord(Logger::DEBUG, 'debug message 2'),
|
||||
$this->getRecord(Logger::INFO, 'information'),
|
||||
$this->getRecord(Logger::WARNING, 'warning'),
|
||||
$this->getRecord(Logger::ERROR, 'error')
|
||||
$this->getRecord(Logger::ERROR, 'error'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user