updated-packages
This commit is contained in:
59
vendor/monolog/monolog/.php_cs
vendored
59
vendor/monolog/monolog/.php_cs
vendored
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
$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::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)
|
||||
;
|
||||
62
vendor/monolog/monolog/CHANGELOG.md
vendored
62
vendor/monolog/monolog/CHANGELOG.md
vendored
@@ -1,5 +1,67 @@
|
||||
### 1.27.1 (2022-06-09)
|
||||
|
||||
* Fixed MandrillHandler support for SwiftMailer 6 (#1676)
|
||||
* Fixed StreamHandler chunk size (backport from #1552)
|
||||
|
||||
### 1.27.0 (2022-03-13)
|
||||
|
||||
* Added $maxDepth / setMaxDepth to NormalizerFormatter / JsonFormatter to configure the maximum depth if the default of 9 does not work for you (#1633)
|
||||
|
||||
### 1.26.1 (2021-05-28)
|
||||
|
||||
* Fixed PHP 8.1 deprecation warning
|
||||
|
||||
### 1.26.0 (2020-12-14)
|
||||
|
||||
* Added $dateFormat and $removeUsedContextFields arguments to PsrLogMessageProcessor (backport from 2.x)
|
||||
|
||||
### 1.25.5 (2020-07-23)
|
||||
|
||||
* Fixed array access on null in RavenHandler
|
||||
* Fixed unique_id in WebProcessor not being disableable
|
||||
|
||||
### 1.25.4 (2020-05-22)
|
||||
|
||||
* Fixed GitProcessor type error when there is no git repo present
|
||||
* Fixed normalization of SoapFault objects containing deeply nested objects as "detail"
|
||||
* Fixed support for relative paths in RotatingFileHandler
|
||||
|
||||
### 1.25.3 (2019-12-20)
|
||||
|
||||
* Fixed formatting of resources in JsonFormatter
|
||||
* Fixed RedisHandler failing to use MULTI properly when passed a proxied Redis instance (e.g. in Symfony with lazy services)
|
||||
* Fixed FilterHandler triggering a notice when handleBatch was filtering all records passed to it
|
||||
* Fixed Turkish locale messing up the conversion of level names to their constant values
|
||||
|
||||
### 1.25.2 (2019-11-13)
|
||||
|
||||
* Fixed normalization of Traversables to avoid traversing them as not all of them are rewindable
|
||||
* Fixed setFormatter/getFormatter to forward to the nested handler in FilterHandler, FingersCrossedHandler, BufferHandler and SamplingHandler
|
||||
* Fixed BrowserConsoleHandler formatting when using multiple styles
|
||||
* Fixed normalization of exception codes to be always integers even for PDOException which have them as numeric strings
|
||||
* Fixed normalization of SoapFault objects containing non-strings as "detail"
|
||||
* Fixed json encoding across all handlers to always attempt recovery of non-UTF-8 strings instead of failing the whole encoding
|
||||
|
||||
### 1.25.1 (2019-09-06)
|
||||
|
||||
* Fixed forward-compatible interfaces to be compatible with Monolog 1.x too.
|
||||
|
||||
### 1.25.0 (2019-09-06)
|
||||
|
||||
* Deprecated SlackbotHandler, use SlackWebhookHandler or SlackHandler instead
|
||||
* Deprecated RavenHandler, use sentry/sentry 2.x and their Sentry\Monolog\Handler instead
|
||||
* Deprecated HipChatHandler, migrate to Slack and use SlackWebhookHandler or SlackHandler instead
|
||||
* Added forward-compatible interfaces and traits FormattableHandlerInterface, FormattableHandlerTrait, ProcessableHandlerInterface, ProcessableHandlerTrait. If you use modern PHP and want to make code compatible with Monolog 1 and 2 this can help. You will have to require at least Monolog 1.25 though.
|
||||
* Added support for RFC3164 (outdated BSD syslog protocol) to SyslogUdpHandler
|
||||
* Fixed issue in GroupHandler and WhatFailureGroupHandler where setting multiple processors would duplicate records
|
||||
* Fixed issue in SignalHandler restarting syscalls functionality
|
||||
* Fixed normalizers handling of exception backtraces to avoid serializing arguments in some cases
|
||||
* Fixed ZendMonitorHandler to work with the latest Zend Server versions
|
||||
* Fixed ChromePHPHandler to avoid sending more data than latest Chrome versions allow in headers (4KB down from 256KB).
|
||||
|
||||
### 1.24.0 (2018-11-05)
|
||||
|
||||
* BC Notice: If you are extending any of the Monolog's Formatters' `normalize` method, make sure you add the new `$depth = 0` argument to your function signature to avoid strict PHP warnings.
|
||||
* Added a `ResettableInterface` in order to reset/reset/clear/flush handlers and processors
|
||||
* Added a `ProcessorInterface` as an optional way to label a class as being a processor (mostly useful for autowiring dependency containers)
|
||||
* Added a way to log signals being received using Monolog\SignalHandler
|
||||
|
||||
2
vendor/monolog/monolog/README.md
vendored
2
vendor/monolog/monolog/README.md
vendored
@@ -90,5 +90,5 @@ Monolog is licensed under the MIT License - see the `LICENSE` file for details
|
||||
|
||||
### Acknowledgements
|
||||
|
||||
This library is heavily inspired by Python's [Logbook](http://packages.python.org/Logbook/)
|
||||
This library is heavily inspired by Python's [Logbook](https://logbook.readthedocs.io/en/stable/)
|
||||
library, although most concepts have been adjusted to fit to the PHP world.
|
||||
|
||||
18
vendor/monolog/monolog/composer.json
vendored
18
vendor/monolog/monolog/composer.json
vendored
@@ -26,10 +26,8 @@
|
||||
"php-amqplib/php-amqplib": "~2.4",
|
||||
"swiftmailer/swiftmailer": "^5.3|^6.0",
|
||||
"php-console/php-console": "^3.1.3",
|
||||
"phpunit/phpunit-mock-objects": "2.3.0",
|
||||
"jakub-onderka/php-parallel-lint": "0.9"
|
||||
"phpstan/phpstan": "^0.12.59"
|
||||
},
|
||||
"_": "phpunit/phpunit-mock-objects required in 2.3.0 due to https://github.com/sebastianbergmann/phpunit-mock-objects/issues/223 - needs hhvm 3.8+ on travis",
|
||||
"suggest": {
|
||||
"graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
|
||||
"sentry/sentry": "Allow sending log messages to a Sentry server",
|
||||
@@ -52,15 +50,11 @@
|
||||
"provide": {
|
||||
"psr/log-implementation": "1.0.0"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": [
|
||||
"parallel-lint . --exclude vendor",
|
||||
"phpunit"
|
||||
]
|
||||
"test": "vendor/bin/phpunit",
|
||||
"phpstan": "vendor/bin/phpstan analyse"
|
||||
},
|
||||
"config": {
|
||||
"lock": false
|
||||
}
|
||||
}
|
||||
|
||||
231
vendor/monolog/monolog/doc/01-usage.md
vendored
231
vendor/monolog/monolog/doc/01-usage.md
vendored
@@ -1,231 +0,0 @@
|
||||
# Using Monolog
|
||||
|
||||
- [Installation](#installation)
|
||||
- [Core Concepts](#core-concepts)
|
||||
- [Log Levels](#log-levels)
|
||||
- [Configuring a logger](#configuring-a-logger)
|
||||
- [Adding extra data in the records](#adding-extra-data-in-the-records)
|
||||
- [Leveraging channels](#leveraging-channels)
|
||||
- [Customizing the log format](#customizing-the-log-format)
|
||||
|
||||
## Installation
|
||||
|
||||
Monolog is available on Packagist ([monolog/monolog](http://packagist.org/packages/monolog/monolog))
|
||||
and as such installable via [Composer](http://getcomposer.org/).
|
||||
|
||||
```bash
|
||||
composer require monolog/monolog
|
||||
```
|
||||
|
||||
If you do not use Composer, you can grab the code from GitHub, and use any
|
||||
PSR-0 compatible autoloader (e.g. the [Symfony2 ClassLoader component](https://github.com/symfony/ClassLoader))
|
||||
to load Monolog classes.
|
||||
|
||||
## Core Concepts
|
||||
|
||||
Every `Logger` instance has a channel (name) and a stack of handlers. Whenever
|
||||
you add a record to the logger, it traverses the handler stack. Each handler
|
||||
decides whether it fully handled the record, and if so, the propagation of the
|
||||
record ends there.
|
||||
|
||||
This allows for flexible logging setups, for example having a `StreamHandler` at
|
||||
the bottom of the stack that will log anything to disk, and on top of that add
|
||||
a `MailHandler` that will send emails only when an error message is logged.
|
||||
Handlers also have a `$bubble` property which defines whether they block the
|
||||
record or not if they handled it. In this example, setting the `MailHandler`'s
|
||||
`$bubble` argument to false means that records handled by the `MailHandler` will
|
||||
not propagate to the `StreamHandler` anymore.
|
||||
|
||||
You can create many `Logger`s, each defining a channel (e.g.: db, request,
|
||||
router, ..) and each of them combining various handlers, which can be shared
|
||||
or not. The channel is reflected in the logs and allows you to easily see or
|
||||
filter records.
|
||||
|
||||
Each Handler also has a Formatter, a default one with settings that make sense
|
||||
will be created if you don't set one. The formatters normalize and format
|
||||
incoming records so that they can be used by the handlers to output useful
|
||||
information.
|
||||
|
||||
Custom severity levels are not available. Only the eight
|
||||
[RFC 5424](http://tools.ietf.org/html/rfc5424) levels (debug, info, notice,
|
||||
warning, error, critical, alert, emergency) are present for basic filtering
|
||||
purposes, but for sorting and other use cases that would require
|
||||
flexibility, you should add Processors to the Logger that can add extra
|
||||
information (tags, user ip, ..) to the records before they are handled.
|
||||
|
||||
## Log Levels
|
||||
|
||||
Monolog supports the logging levels described by [RFC 5424](http://tools.ietf.org/html/rfc5424).
|
||||
|
||||
- **DEBUG** (100): Detailed debug information.
|
||||
|
||||
- **INFO** (200): Interesting events. Examples: User logs in, SQL logs.
|
||||
|
||||
- **NOTICE** (250): Normal but significant events.
|
||||
|
||||
- **WARNING** (300): Exceptional occurrences that are not errors. Examples:
|
||||
Use of deprecated APIs, poor use of an API, undesirable things that are not
|
||||
necessarily wrong.
|
||||
|
||||
- **ERROR** (400): Runtime errors that do not require immediate action but
|
||||
should typically be logged and monitored.
|
||||
|
||||
- **CRITICAL** (500): Critical conditions. Example: Application component
|
||||
unavailable, unexpected exception.
|
||||
|
||||
- **ALERT** (550): Action must be taken immediately. Example: Entire website
|
||||
down, database unavailable, etc. This should trigger the SMS alerts and wake
|
||||
you up.
|
||||
|
||||
- **EMERGENCY** (600): Emergency: system is unusable.
|
||||
|
||||
## Configuring a logger
|
||||
|
||||
Here is a basic setup to log to a file and to firephp on the DEBUG level:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Handler\FirePHPHandler;
|
||||
|
||||
// Create the logger
|
||||
$logger = new Logger('my_logger');
|
||||
// Now add some handlers
|
||||
$logger->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG));
|
||||
$logger->pushHandler(new FirePHPHandler());
|
||||
|
||||
// You can now use your logger
|
||||
$logger->addInfo('My logger is now ready');
|
||||
```
|
||||
|
||||
Let's explain it. The first step is to create the logger instance which will
|
||||
be used in your code. The argument is a channel name, which is useful when
|
||||
you use several loggers (see below for more details about it).
|
||||
|
||||
The logger itself does not know how to handle a record. It delegates it to
|
||||
some handlers. The code above registers two handlers in the stack to allow
|
||||
handling records in two different ways.
|
||||
|
||||
Note that the FirePHPHandler is called first as it is added on top of the
|
||||
stack. This allows you to temporarily add a logger with bubbling disabled if
|
||||
you want to override other configured loggers.
|
||||
|
||||
> If you use Monolog standalone and are looking for an easy way to
|
||||
> configure many handlers, the [theorchard/monolog-cascade](https://github.com/theorchard/monolog-cascade)
|
||||
> can help you build complex logging configs via PHP arrays, yaml or json configs.
|
||||
|
||||
## Adding extra data in the records
|
||||
|
||||
Monolog provides two different ways to add extra informations along the simple
|
||||
textual message.
|
||||
|
||||
### Using the logging context
|
||||
|
||||
The first way is the context, allowing to pass an array of data along the
|
||||
record:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
$logger->addInfo('Adding a new user', array('username' => 'Seldaek'));
|
||||
```
|
||||
|
||||
Simple handlers (like the StreamHandler for instance) will simply format
|
||||
the array to a string but richer handlers can take advantage of the context
|
||||
(FirePHP is able to display arrays in pretty way for instance).
|
||||
|
||||
### Using processors
|
||||
|
||||
The second way is to add extra data for all records by using a processor.
|
||||
Processors can be any callable. They will get the record as parameter and
|
||||
must return it after having eventually changed the `extra` part of it. Let's
|
||||
write a processor adding some dummy data in the record:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
$logger->pushProcessor(function ($record) {
|
||||
$record['extra']['dummy'] = 'Hello world!';
|
||||
|
||||
return $record;
|
||||
});
|
||||
```
|
||||
|
||||
Monolog provides some built-in processors that can be used in your project.
|
||||
Look at the [dedicated chapter](https://github.com/Seldaek/monolog/blob/master/doc/02-handlers-formatters-processors.md#processors) for the list.
|
||||
|
||||
> Tip: processors can also be registered on a specific handler instead of
|
||||
the logger to apply only for this handler.
|
||||
|
||||
## Leveraging channels
|
||||
|
||||
Channels are a great way to identify to which part of the application a record
|
||||
is related. This is useful in big applications (and is leveraged by
|
||||
MonologBundle in Symfony2).
|
||||
|
||||
Picture two loggers sharing a handler that writes to a single log file.
|
||||
Channels would allow you to identify the logger that issued every record.
|
||||
You can easily grep through the log files filtering this or that channel.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Handler\FirePHPHandler;
|
||||
|
||||
// Create some handlers
|
||||
$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
|
||||
$firephp = new FirePHPHandler();
|
||||
|
||||
// Create the main logger of the app
|
||||
$logger = new Logger('my_logger');
|
||||
$logger->pushHandler($stream);
|
||||
$logger->pushHandler($firephp);
|
||||
|
||||
// Create a logger for the security-related stuff with a different channel
|
||||
$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
|
||||
|
||||
In Monolog it's easy to customize the format of the logs written into files,
|
||||
sockets, mails, databases and other handlers. Most of the handlers use the
|
||||
|
||||
```php
|
||||
$record['formatted']
|
||||
```
|
||||
|
||||
value to be automatically put into the log device. This value depends on the
|
||||
formatter settings. You can choose between predefined formatter classes or
|
||||
write your own (e.g. a multiline text file for human-readable output).
|
||||
|
||||
To configure a predefined formatter class, just set it as the handler's field:
|
||||
|
||||
```php
|
||||
// the default date format is "Y-m-d H:i:s"
|
||||
$dateFormat = "Y n j, g:i a";
|
||||
// the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"
|
||||
$output = "%datetime% > %level_name% > %message% %context% %extra%\n";
|
||||
// finally, create a formatter
|
||||
$formatter = new LineFormatter($output, $dateFormat);
|
||||
|
||||
// Create a handler
|
||||
$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
|
||||
$stream->setFormatter($formatter);
|
||||
// bind it to a logger object
|
||||
$securityLogger = new Logger('security');
|
||||
$securityLogger->pushHandler($stream);
|
||||
```
|
||||
|
||||
You may also reuse the same formatter between multiple handlers and share those
|
||||
handlers between multiple loggers.
|
||||
|
||||
[Handlers, Formatters and Processors](02-handlers-formatters-processors.md) →
|
||||
@@ -1,158 +0,0 @@
|
||||
# Handlers, Formatters and Processors
|
||||
|
||||
- [Handlers](#handlers)
|
||||
- [Log to files and syslog](#log-to-files-and-syslog)
|
||||
- [Send alerts and emails](#send-alerts-and-emails)
|
||||
- [Log specific servers and networked logging](#log-specific-servers-and-networked-logging)
|
||||
- [Logging in development](#logging-in-development)
|
||||
- [Log to databases](#log-to-databases)
|
||||
- [Wrappers / Special Handlers](#wrappers--special-handlers)
|
||||
- [Formatters](#formatters)
|
||||
- [Processors](#processors)
|
||||
- [Third Party Packages](#third-party-packages)
|
||||
|
||||
## Handlers
|
||||
|
||||
### Log to files and syslog
|
||||
|
||||
- _StreamHandler_: Logs records into any PHP stream, use this for log files.
|
||||
- _RotatingFileHandler_: Logs records to a file and creates one logfile per day.
|
||||
It will also delete files older than `$maxFiles`. You should use
|
||||
[logrotate](http://linuxcommand.org/man_pages/logrotate8.html) for high profile
|
||||
setups though, this is just meant as a quick and dirty solution.
|
||||
- _SyslogHandler_: Logs records to the syslog.
|
||||
- _ErrorLogHandler_: Logs records to PHP's
|
||||
[`error_log()`](http://docs.php.net/manual/en/function.error-log.php) function.
|
||||
|
||||
### Send alerts and emails
|
||||
|
||||
- _NativeMailerHandler_: Sends emails using PHP's
|
||||
[`mail()`](http://php.net/manual/en/function.mail.php) function.
|
||||
- _SwiftMailerHandler_: Sends emails using a [`Swift_Mailer`](http://swiftmailer.org/) instance.
|
||||
- _PushoverHandler_: Sends mobile notifications via the [Pushover](https://www.pushover.net/) API.
|
||||
- _HipChatHandler_: Logs records to a [HipChat](http://hipchat.com) chat room using its API.
|
||||
- _FlowdockHandler_: Logs records to a [Flowdock](https://www.flowdock.com/) account.
|
||||
- _SlackHandler_: Logs records to a [Slack](https://www.slack.com/) account using the Slack API.
|
||||
- _SlackbotHandler_: Logs records to a [Slack](https://www.slack.com/) account using the Slackbot incoming hook.
|
||||
- _SlackWebhookHandler_: Logs records to a [Slack](https://www.slack.com/) account using Slack Webhooks.
|
||||
- _MandrillHandler_: Sends emails via the Mandrill API using a [`Swift_Message`](http://swiftmailer.org/) instance.
|
||||
- _FleepHookHandler_: Logs records to a [Fleep](https://fleep.io/) conversation using Webhooks.
|
||||
- _IFTTTHandler_: Notifies an [IFTTT](https://ifttt.com/maker) trigger with the log channel, level name and message.
|
||||
|
||||
### Log specific servers and networked logging
|
||||
|
||||
- _SocketHandler_: Logs records to [sockets](http://php.net/fsockopen), use this
|
||||
for UNIX and TCP sockets. See an [example](sockets.md).
|
||||
- _AmqpHandler_: Logs records to an [amqp](http://www.amqp.org/) compatible
|
||||
server. Requires the [php-amqp](http://pecl.php.net/package/amqp) extension (1.0+).
|
||||
- _GelfHandler_: Logs records to a [Graylog2](http://www.graylog2.org) server.
|
||||
- _CubeHandler_: Logs records to a [Cube](http://square.github.com/cube/) server.
|
||||
- _RavenHandler_: Logs records to a [Sentry](http://getsentry.com/) server using
|
||||
[raven](https://packagist.org/packages/raven/raven).
|
||||
- _ZendMonitorHandler_: Logs records to the Zend Monitor present in Zend Server.
|
||||
- _NewRelicHandler_: Logs records to a [NewRelic](http://newrelic.com/) application.
|
||||
- _LogglyHandler_: Logs records to a [Loggly](http://www.loggly.com/) account.
|
||||
- _RollbarHandler_: Logs records to a [Rollbar](https://rollbar.com/) account.
|
||||
- _SyslogUdpHandler_: Logs records to a remote [Syslogd](http://www.rsyslog.com/) server.
|
||||
- _LogEntriesHandler_: Logs records to a [LogEntries](http://logentries.com/) account.
|
||||
- _InsightOpsHandler_: Logs records to a [InsightOps](https://www.rapid7.com/products/insightops/) account.
|
||||
|
||||
### Logging in development
|
||||
|
||||
- _FirePHPHandler_: Handler for [FirePHP](http://www.firephp.org/), providing
|
||||
inline `console` messages within [FireBug](http://getfirebug.com/).
|
||||
- _ChromePHPHandler_: Handler for [ChromePHP](http://www.chromephp.com/), providing
|
||||
inline `console` messages within Chrome.
|
||||
- _BrowserConsoleHandler_: Handler to send logs to browser's Javascript `console` with
|
||||
no browser extension required. Most browsers supporting `console` API are supported.
|
||||
- _PHPConsoleHandler_: Handler for [PHP Console](https://chrome.google.com/webstore/detail/php-console/nfhmhhlpfleoednkpnnnkolmclajemef), providing
|
||||
inline `console` and notification popup messages within Chrome.
|
||||
|
||||
### Log to databases
|
||||
|
||||
- _RedisHandler_: Logs records to a [redis](http://redis.io) server.
|
||||
- _MongoDBHandler_: Handler to write records in MongoDB via a
|
||||
[Mongo](http://pecl.php.net/package/mongo) extension connection.
|
||||
- _CouchDBHandler_: Logs records to a CouchDB server.
|
||||
- _DoctrineCouchDBHandler_: Logs records to a CouchDB server via the Doctrine CouchDB ODM.
|
||||
- _ElasticSearchHandler_: Logs records to an Elastic Search server.
|
||||
- _DynamoDbHandler_: Logs records to a DynamoDB table with the [AWS SDK](https://github.com/aws/aws-sdk-php).
|
||||
|
||||
### Wrappers / Special Handlers
|
||||
|
||||
- _FingersCrossedHandler_: A very interesting wrapper. It takes a logger as
|
||||
parameter and will accumulate log records of all levels until a record
|
||||
exceeds the defined severity level. At which point it delivers all records,
|
||||
including those of lower severity, to the handler it wraps. This means that
|
||||
until an error actually happens you will not see anything in your logs, but
|
||||
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
|
||||
application to crash and may wish to continue to log to other handlers.
|
||||
- _BufferHandler_: This handler will buffer all the log records it receives
|
||||
until `close()` is called at which point it will call `handleBatch()` on the
|
||||
handler it wraps with all the log messages at once. This is very useful to
|
||||
send an email with all records at once for example instead of having one mail
|
||||
for every log record.
|
||||
- _GroupHandler_: This handler groups other handlers. Every record received is
|
||||
sent to all the handlers it is configured with.
|
||||
- _FilterHandler_: This handler only lets records of the given levels through
|
||||
to the wrapped handler.
|
||||
- _SamplingHandler_: Wraps around another handler and lets you sample records
|
||||
if you only want to store some of them.
|
||||
- _NullHandler_: Any record it can handle will be thrown away. This can be used
|
||||
to put on top of an existing handler stack to disable it temporarily.
|
||||
- _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
|
||||
|
||||
- _LineFormatter_: Formats a log record into a one-line string.
|
||||
- _HtmlFormatter_: Used to format log records into a human readable html table, mainly suitable for emails.
|
||||
- _NormalizerFormatter_: Normalizes objects/resources down to strings so a record can easily be serialized/encoded.
|
||||
- _ScalarFormatter_: Used to format log records into an associative array of scalar values.
|
||||
- _JsonFormatter_: Encodes a log record into json.
|
||||
- _WildfireFormatter_: Used to format log records into the Wildfire/FirePHP protocol, only useful for the FirePHPHandler.
|
||||
- _ChromePHPFormatter_: Used to format log records into the ChromePHP format, only useful for the ChromePHPHandler.
|
||||
- _GelfMessageFormatter_: Used to format log records into Gelf message instances, only useful for the GelfHandler.
|
||||
- _LogstashFormatter_: Used to format log records into [logstash](http://logstash.net/) event json, useful for any handler listed under inputs [here](http://logstash.net/docs/latest).
|
||||
- _ElasticaFormatter_: Used to format log records into an Elastica\Document object, only useful for the ElasticSearchHandler.
|
||||
- _LogglyFormatter_: Used to format log records into Loggly messages, only useful for the LogglyHandler.
|
||||
- _FlowdockFormatter_: Used to format log records into Flowdock messages, only useful for the FlowdockHandler.
|
||||
- _MongoDBFormatter_: Converts \DateTime instances to \MongoDate and objects recursively to arrays, only useful with the MongoDBHandler.
|
||||
|
||||
## 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.
|
||||
- _MemoryPeakUsageProcessor_: Adds the peak memory usage to a log record.
|
||||
- _ProcessIdProcessor_: Adds the process id to a log record.
|
||||
- _UidProcessor_: Adds a unique identifier to a log record.
|
||||
- _GitProcessor_: Adds the current git branch and commit to a log record.
|
||||
- _TagProcessor_: Adds an array of predefined tags to a log record.
|
||||
|
||||
## Third Party Packages
|
||||
|
||||
Third party handlers, formatters and processors are
|
||||
[listed in the wiki](https://github.com/Seldaek/monolog/wiki/Third-Party-Packages). You
|
||||
can also add your own there if you publish one.
|
||||
|
||||
← [Usage](01-usage.md) | [Utility classes](03-utilities.md) →
|
||||
15
vendor/monolog/monolog/doc/03-utilities.md
vendored
15
vendor/monolog/monolog/doc/03-utilities.md
vendored
@@ -1,15 +0,0 @@
|
||||
# Utilities
|
||||
|
||||
- _Registry_: The `Monolog\Registry` class lets you configure global loggers that you
|
||||
can then statically access from anywhere. It is not really a best practice but can
|
||||
help in some older codebases or for ease of use.
|
||||
- _ErrorHandler_: The `Monolog\ErrorHandler` class allows you to easily register
|
||||
a Logger instance as an exception handler, error handler or fatal error handler.
|
||||
- _SignalHandler_: The `Monolog\SignalHandler` class allows you to easily register
|
||||
a Logger instance as a POSIX signal handler.
|
||||
- _ErrorLevelActivationStrategy_: Activates a FingersCrossedHandler when a certain log
|
||||
level is reached.
|
||||
- _ChannelLevelActivationStrategy_: Activates a FingersCrossedHandler when a certain
|
||||
log level is reached, depending on which channel received the log record.
|
||||
|
||||
← [Handlers, Formatters and Processors](02-handlers-formatters-processors.md) | [Extending Monolog](04-extending.md) →
|
||||
76
vendor/monolog/monolog/doc/04-extending.md
vendored
76
vendor/monolog/monolog/doc/04-extending.md
vendored
@@ -1,76 +0,0 @@
|
||||
# Extending Monolog
|
||||
|
||||
Monolog is fully extensible, allowing you to adapt your logger to your needs.
|
||||
|
||||
## Writing your own handler
|
||||
|
||||
Monolog provides many built-in handlers. But if the one you need does not
|
||||
exist, you can write it and use it in your logger. The only requirement is
|
||||
to implement `Monolog\Handler\HandlerInterface`.
|
||||
|
||||
Let's write a PDOHandler to log records to a database. We will extend the
|
||||
abstract class provided by Monolog to keep things DRY.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\AbstractProcessingHandler;
|
||||
|
||||
class PDOHandler extends AbstractProcessingHandler
|
||||
{
|
||||
private $initialized = false;
|
||||
private $pdo;
|
||||
private $statement;
|
||||
|
||||
public function __construct(PDO $pdo, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
$this->pdo = $pdo;
|
||||
parent::__construct($level, $bubble);
|
||||
}
|
||||
|
||||
protected function write(array $record)
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
$this->statement->execute(array(
|
||||
'channel' => $record['channel'],
|
||||
'level' => $record['level'],
|
||||
'message' => $record['formatted'],
|
||||
'time' => $record['datetime']->format('U'),
|
||||
));
|
||||
}
|
||||
|
||||
private function initialize()
|
||||
{
|
||||
$this->pdo->exec(
|
||||
'CREATE TABLE IF NOT EXISTS monolog '
|
||||
.'(channel VARCHAR(255), level INTEGER, message LONGTEXT, time INTEGER UNSIGNED)'
|
||||
);
|
||||
$this->statement = $this->pdo->prepare(
|
||||
'INSERT INTO monolog (channel, level, message, time) VALUES (:channel, :level, :message, :time)'
|
||||
);
|
||||
|
||||
$this->initialized = true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can now use this handler in your logger:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
$logger->pushHandler(new PDOHandler(new PDO('sqlite:logs.sqlite')));
|
||||
|
||||
// You can now use your logger
|
||||
$logger->addInfo('My logger is now ready');
|
||||
```
|
||||
|
||||
The `Monolog\Handler\AbstractProcessingHandler` class provides most of the
|
||||
logic needed for the handler, including the use of processors and the formatting
|
||||
of the record (which is why we use ``$record['formatted']`` instead of ``$record['message']``).
|
||||
|
||||
← [Utility classes](03-utilities.md)
|
||||
39
vendor/monolog/monolog/doc/sockets.md
vendored
39
vendor/monolog/monolog/doc/sockets.md
vendored
@@ -1,39 +0,0 @@
|
||||
Sockets Handler
|
||||
===============
|
||||
|
||||
This handler allows you to write your logs to sockets using [fsockopen](http://php.net/fsockopen)
|
||||
or [pfsockopen](http://php.net/pfsockopen).
|
||||
|
||||
Persistent sockets are mainly useful in web environments where you gain some performance not closing/opening
|
||||
the connections between requests.
|
||||
|
||||
You can use a `unix://` prefix to access unix sockets and `udp://` to open UDP sockets instead of the default TCP.
|
||||
|
||||
Basic Example
|
||||
-------------
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\SocketHandler;
|
||||
|
||||
// Create the logger
|
||||
$logger = new Logger('my_logger');
|
||||
|
||||
// Create the handler
|
||||
$handler = new SocketHandler('unix:///var/log/httpd_app_log.socket');
|
||||
$handler->setPersistent(true);
|
||||
|
||||
// Now add the handler
|
||||
$logger->pushHandler($handler, Logger::DEBUG);
|
||||
|
||||
// You can now use your logger
|
||||
$logger->addInfo('My logger is now ready');
|
||||
|
||||
```
|
||||
|
||||
In this example, using syslog-ng, you should see the log on the log server:
|
||||
|
||||
cweb1 [2012-02-26 00:12:03] my_logger.INFO: My logger is now ready [] []
|
||||
|
||||
16
vendor/monolog/monolog/phpstan.neon.dist
vendored
Normal file
16
vendor/monolog/monolog/phpstan.neon.dist
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
parameters:
|
||||
level: 3
|
||||
|
||||
paths:
|
||||
- src/
|
||||
# - tests/
|
||||
|
||||
|
||||
ignoreErrors:
|
||||
- '#zend_monitor_|ZEND_MONITOR_#'
|
||||
- '#RollbarNotifier#'
|
||||
- '#Predis\\Client#'
|
||||
- '#^Cannot call method ltrim\(\) on int\|false.$#'
|
||||
- '#^Access to an undefined property Raven_Client::\$context.$#'
|
||||
- '#MongoDB\\(Client|Collection)#'
|
||||
- '#Gelf\\IMessagePublisher#'
|
||||
19
vendor/monolog/monolog/phpunit.xml.dist
vendored
19
vendor/monolog/monolog/phpunit.xml.dist
vendored
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit bootstrap="vendor/autoload.php" colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="Monolog Test Suite">
|
||||
<directory>tests/Monolog/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">src/Monolog/</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
<php>
|
||||
<ini name="date.timezone" value="UTC"/>
|
||||
</php>
|
||||
</phpunit>
|
||||
@@ -14,7 +14,6 @@ namespace Monolog;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use Monolog\Handler\AbstractHandler;
|
||||
use Monolog\Registry;
|
||||
|
||||
/**
|
||||
* Monolog error handler
|
||||
@@ -63,6 +62,7 @@ class ErrorHandler
|
||||
//Forces the autoloader to run for LogLevel. Fixes an autoload issue at compile-time on PHP5.3. See https://github.com/Seldaek/monolog/pull/929
|
||||
class_exists('\\Psr\\Log\\LogLevel', true);
|
||||
|
||||
/** @phpstan-ignore-next-line */
|
||||
$handler = new static($logger);
|
||||
if ($errorLevelMap !== false) {
|
||||
$handler->registerErrorHandler($errorLevelMap);
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace Monolog\Formatter;
|
||||
|
||||
use Monolog\Utils;
|
||||
|
||||
/**
|
||||
* Class FluentdFormatter
|
||||
*
|
||||
@@ -71,7 +73,7 @@ class FluentdFormatter implements FormatterInterface
|
||||
$message['level_name'] = $record['level_name'];
|
||||
}
|
||||
|
||||
return json_encode(array($tag, $record['datetime']->getTimestamp(), $message));
|
||||
return Utils::jsonEncode(array($tag, $record['datetime']->getTimestamp(), $message));
|
||||
}
|
||||
|
||||
public function formatBatch(array $records)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
namespace Monolog\Formatter;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Utils;
|
||||
|
||||
/**
|
||||
* Formats incoming records into an HTML table
|
||||
@@ -133,9 +134,9 @@ class HtmlFormatter extends NormalizerFormatter
|
||||
|
||||
$data = $this->normalize($data);
|
||||
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
return Utils::jsonEncode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE, true);
|
||||
}
|
||||
|
||||
return str_replace('\\/', '/', json_encode($data));
|
||||
return str_replace('\\/', '/', Utils::jsonEncode($data, null, true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,9 +38,11 @@ class JsonFormatter extends NormalizerFormatter
|
||||
/**
|
||||
* @param int $batchMode
|
||||
* @param bool $appendNewline
|
||||
* @param int $maxDepth
|
||||
*/
|
||||
public function __construct($batchMode = self::BATCH_MODE_JSON, $appendNewline = true)
|
||||
public function __construct($batchMode = self::BATCH_MODE_JSON, $appendNewline = true, $maxDepth = 9)
|
||||
{
|
||||
parent::__construct(null, $maxDepth);
|
||||
$this->batchMode = $batchMode;
|
||||
$this->appendNewline = $appendNewline;
|
||||
}
|
||||
@@ -141,11 +143,11 @@ class JsonFormatter extends NormalizerFormatter
|
||||
*/
|
||||
protected function normalize($data, $depth = 0)
|
||||
{
|
||||
if ($depth > 9) {
|
||||
return 'Over 9 levels deep, aborting normalization';
|
||||
if ($depth > $this->maxDepth) {
|
||||
return 'Over '.$this->maxDepth.' levels deep, aborting normalization';
|
||||
}
|
||||
|
||||
if (is_array($data) || $data instanceof \Traversable) {
|
||||
if (is_array($data)) {
|
||||
$normalized = array();
|
||||
|
||||
$count = 1;
|
||||
@@ -165,6 +167,10 @@ class JsonFormatter extends NormalizerFormatter
|
||||
return $this->normalizeException($data);
|
||||
}
|
||||
|
||||
if (is_resource($data)) {
|
||||
return parent::normalize($data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -186,7 +192,7 @@ class JsonFormatter extends NormalizerFormatter
|
||||
$data = array(
|
||||
'class' => Utils::getClass($e),
|
||||
'message' => $e->getMessage(),
|
||||
'code' => $e->getCode(),
|
||||
'code' => (int) $e->getCode(),
|
||||
'file' => $e->getFile().':'.$e->getLine(),
|
||||
);
|
||||
|
||||
@@ -195,12 +201,6 @@ class JsonFormatter extends NormalizerFormatter
|
||||
foreach ($trace as $frame) {
|
||||
if (isset($frame['file'])) {
|
||||
$data['trace'][] = $frame['file'].':'.$frame['line'];
|
||||
} elseif (isset($frame['function']) && $frame['function'] === '{closure}') {
|
||||
// We should again normalize the frames, because it might contain invalid items
|
||||
$data['trace'][] = $frame['function'];
|
||||
} else {
|
||||
// We should again normalize the frames, because it might contain invalid items
|
||||
$data['trace'][] = $this->normalize($frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ class LineFormatter extends NormalizerFormatter
|
||||
return $this->toJson($data, true);
|
||||
}
|
||||
|
||||
return str_replace('\\/', '/', @json_encode($data));
|
||||
return str_replace('\\/', '/', $this->toJson($data, true));
|
||||
}
|
||||
|
||||
protected function replaceNewlines($str)
|
||||
|
||||
@@ -87,7 +87,7 @@ class MongoDBFormatter implements FormatterInterface
|
||||
$formattedException = array(
|
||||
'class' => Utils::getClass($exception),
|
||||
'message' => $exception->getMessage(),
|
||||
'code' => $exception->getCode(),
|
||||
'code' => (int) $exception->getCode(),
|
||||
'file' => $exception->getFile() . ':' . $exception->getLine(),
|
||||
);
|
||||
|
||||
|
||||
@@ -24,13 +24,16 @@ class NormalizerFormatter implements FormatterInterface
|
||||
const SIMPLE_DATE = "Y-m-d H:i:s";
|
||||
|
||||
protected $dateFormat;
|
||||
protected $maxDepth;
|
||||
|
||||
/**
|
||||
* @param string $dateFormat The format of the timestamp: one supported by DateTime::format
|
||||
* @param int $maxDepth
|
||||
*/
|
||||
public function __construct($dateFormat = null)
|
||||
public function __construct($dateFormat = null, $maxDepth = 9)
|
||||
{
|
||||
$this->dateFormat = $dateFormat ?: static::SIMPLE_DATE;
|
||||
$this->maxDepth = $maxDepth;
|
||||
if (!function_exists('json_encode')) {
|
||||
throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s NormalizerFormatter');
|
||||
}
|
||||
@@ -56,10 +59,26 @@ class NormalizerFormatter implements FormatterInterface
|
||||
return $records;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getMaxDepth()
|
||||
{
|
||||
return $this->maxDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $maxDepth
|
||||
*/
|
||||
public function setMaxDepth($maxDepth)
|
||||
{
|
||||
$this->maxDepth = $maxDepth;
|
||||
}
|
||||
|
||||
protected function normalize($data, $depth = 0)
|
||||
{
|
||||
if ($depth > 9) {
|
||||
return 'Over 9 levels deep, aborting normalization';
|
||||
if ($depth > $this->maxDepth) {
|
||||
return 'Over '.$this->maxDepth.' levels deep, aborting normalization';
|
||||
}
|
||||
|
||||
if (null === $data || is_scalar($data)) {
|
||||
@@ -129,7 +148,7 @@ class NormalizerFormatter implements FormatterInterface
|
||||
$data = array(
|
||||
'class' => Utils::getClass($e),
|
||||
'message' => $e->getMessage(),
|
||||
'code' => $e->getCode(),
|
||||
'code' => (int) $e->getCode(),
|
||||
'file' => $e->getFile().':'.$e->getLine(),
|
||||
);
|
||||
|
||||
@@ -143,7 +162,11 @@ class NormalizerFormatter implements FormatterInterface
|
||||
}
|
||||
|
||||
if (isset($e->detail)) {
|
||||
$data['detail'] = $e->detail;
|
||||
if (is_string($e->detail)) {
|
||||
$data['detail'] = $e->detail;
|
||||
} elseif (is_object($e->detail) || is_array($e->detail)) {
|
||||
$data['detail'] = $this->toJson($e->detail, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,23 +174,6 @@ class NormalizerFormatter implements FormatterInterface
|
||||
foreach ($trace as $frame) {
|
||||
if (isset($frame['file'])) {
|
||||
$data['trace'][] = $frame['file'].':'.$frame['line'];
|
||||
} elseif (isset($frame['function']) && $frame['function'] === '{closure}') {
|
||||
// Simplify closures handling
|
||||
$data['trace'][] = $frame['function'];
|
||||
} else {
|
||||
if (isset($frame['args'])) {
|
||||
// Make sure that objects present as arguments are not serialized nicely but rather only
|
||||
// as a class name to avoid any unexpected leak of sensitive information
|
||||
$frame['args'] = array_map(function ($arg) {
|
||||
if (is_object($arg) && !($arg instanceof \DateTime || $arg instanceof \DateTimeInterface)) {
|
||||
return sprintf("[object] (%s)", Utils::getClass($arg));
|
||||
}
|
||||
|
||||
return $arg;
|
||||
}, $frame['args']);
|
||||
}
|
||||
// We should again normalize the frames, because it might contain invalid items
|
||||
$data['trace'][] = $this->toJson($this->normalize($frame), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,127 +194,6 @@ class NormalizerFormatter implements FormatterInterface
|
||||
*/
|
||||
protected function toJson($data, $ignoreErrors = false)
|
||||
{
|
||||
// suppress json_encode errors since it's twitchy with some inputs
|
||||
if ($ignoreErrors) {
|
||||
return @$this->jsonEncode($data);
|
||||
}
|
||||
|
||||
$json = $this->jsonEncode($data);
|
||||
|
||||
if ($json === false) {
|
||||
$json = $this->handleJsonError(json_last_error(), $data);
|
||||
}
|
||||
|
||||
return $json;
|
||||
return Utils::jsonEncode($data, null, $ignoreErrors);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $data
|
||||
* @return string JSON encoded data or null on failure
|
||||
*/
|
||||
private function jsonEncode($data)
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
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 attempt 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);
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function throwEncodeError($code, $data)
|
||||
{
|
||||
switch ($code) {
|
||||
case JSON_ERROR_DEPTH:
|
||||
$msg = 'Maximum stack depth exceeded';
|
||||
break;
|
||||
case JSON_ERROR_STATE_MISMATCH:
|
||||
$msg = 'Underflow or the modes mismatch';
|
||||
break;
|
||||
case JSON_ERROR_CTRL_CHAR:
|
||||
$msg = 'Unexpected control character found';
|
||||
break;
|
||||
case JSON_ERROR_UTF8:
|
||||
$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
|
||||
break;
|
||||
default:
|
||||
$msg = 'Unknown error';
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,8 +33,8 @@ abstract class AbstractHandler implements HandlerInterface, ResettableInterface
|
||||
protected $processors = array();
|
||||
|
||||
/**
|
||||
* @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|string $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($level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
|
||||
@@ -164,21 +164,22 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
|
||||
|
||||
private static function handleStyles($formatted)
|
||||
{
|
||||
$args = array(static::quote('font-weight: normal'));
|
||||
$args = array();
|
||||
$format = '%c' . $formatted;
|
||||
preg_match_all('/\[\[(.*?)\]\]\{([^}]*)\}/s', $format, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
|
||||
|
||||
foreach (array_reverse($matches) as $match) {
|
||||
$args[] = static::quote(static::handleCustomStyles($match[2][0], $match[1][0]));
|
||||
$args[] = '"font-weight: normal"';
|
||||
$args[] = static::quote(static::handleCustomStyles($match[2][0], $match[1][0]));
|
||||
|
||||
$pos = $match[0][1];
|
||||
$format = substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . substr($format, $pos + strlen($match[0][0]));
|
||||
}
|
||||
|
||||
array_unshift($args, static::quote($format));
|
||||
$args[] = static::quote('font-weight: normal');
|
||||
$args[] = static::quote($format);
|
||||
|
||||
return $args;
|
||||
return array_reverse($args);
|
||||
}
|
||||
|
||||
private static function handleCustomStyles($style, $string)
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Monolog\Handler;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\ResettableInterface;
|
||||
use Monolog\Formatter\FormatterInterface;
|
||||
|
||||
/**
|
||||
* Buffers all records until closing the handler and then pass them as batch.
|
||||
@@ -126,4 +127,22 @@ class BufferHandler extends AbstractHandler
|
||||
$this->handler->reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setFormatter(FormatterInterface $formatter)
|
||||
{
|
||||
$this->handler->setFormatter($formatter);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormatter()
|
||||
{
|
||||
return $this->handler->getFormatter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Monolog\Handler;
|
||||
|
||||
use Monolog\Formatter\ChromePHPFormatter;
|
||||
use Monolog\Logger;
|
||||
use Monolog\Utils;
|
||||
|
||||
/**
|
||||
* Handler sending logs to the ChromePHP extension (http://www.chromephp.com/)
|
||||
@@ -43,7 +44,7 @@ class ChromePHPHandler extends AbstractProcessingHandler
|
||||
/**
|
||||
* Tracks whether we sent too much data
|
||||
*
|
||||
* Chrome limits the headers to 256KB, so when we sent 240KB we stop sending
|
||||
* Chrome limits the headers to 4KB, so when we sent 3KB we stop sending
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
@@ -134,9 +135,9 @@ class ChromePHPHandler extends AbstractProcessingHandler
|
||||
self::$json['request_uri'] = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
|
||||
}
|
||||
|
||||
$json = @json_encode(self::$json);
|
||||
$json = Utils::jsonEncode(self::$json, null, true);
|
||||
$data = base64_encode(utf8_encode($json));
|
||||
if (strlen($data) > 240 * 1024) {
|
||||
if (strlen($data) > 3 * 1024) {
|
||||
self::$overflowed = true;
|
||||
|
||||
$record = array(
|
||||
@@ -149,7 +150,7 @@ class ChromePHPHandler extends AbstractProcessingHandler
|
||||
'extra' => array(),
|
||||
);
|
||||
self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record);
|
||||
$json = @json_encode(self::$json);
|
||||
$json = Utils::jsonEncode(self::$json, null, true);
|
||||
$data = base64_encode(utf8_encode($json));
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace Monolog\Handler;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Utils;
|
||||
|
||||
/**
|
||||
* Logs to Cube.
|
||||
@@ -119,9 +120,9 @@ class CubeHandler extends AbstractProcessingHandler
|
||||
$data['data']['level'] = $record['level'];
|
||||
|
||||
if ($this->scheme === 'http') {
|
||||
$this->writeHttp(json_encode($data));
|
||||
$this->writeHttp(Utils::jsonEncode($data));
|
||||
} else {
|
||||
$this->writeUdp(json_encode($data));
|
||||
$this->writeUdp(Utils::jsonEncode($data));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ class DynamoDbHandler extends AbstractProcessingHandler
|
||||
if ($this->version === 3) {
|
||||
$formatted = $this->marshaler->marshalItem($filtered);
|
||||
} else {
|
||||
/** @phpstan-ignore-next-line */
|
||||
$formatted = $this->client->formatAttributes($filtered);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace Monolog\Handler;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Formatter\FormatterInterface;
|
||||
|
||||
/**
|
||||
* Simple handler wrapper that filters records based on a list of levels
|
||||
@@ -45,7 +46,7 @@ class FilterHandler extends AbstractHandler
|
||||
protected $bubble;
|
||||
|
||||
/**
|
||||
* @param callable|HandlerInterface $handler Handler or factory callable($record, $this).
|
||||
* @param callable|HandlerInterface $handler Handler or factory callable($record|null, $filterHandler).
|
||||
* @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 bool $bubble Whether the messages that are handled can bubble up the stack or not
|
||||
@@ -104,21 +105,13 @@ class FilterHandler extends AbstractHandler
|
||||
return false;
|
||||
}
|
||||
|
||||
// The same logic as in FingersCrossedHandler
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
$this->handler = call_user_func($this->handler, $record, $this);
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
throw new \RuntimeException("The factory callable should return a HandlerInterface");
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->processors) {
|
||||
foreach ($this->processors as $processor) {
|
||||
$record = call_user_func($processor, $record);
|
||||
}
|
||||
}
|
||||
|
||||
$this->handler->handle($record);
|
||||
$this->getHandler($record)->handle($record);
|
||||
|
||||
return false === $this->bubble;
|
||||
}
|
||||
@@ -135,6 +128,45 @@ class FilterHandler extends AbstractHandler
|
||||
}
|
||||
}
|
||||
|
||||
$this->handler->handleBatch($filtered);
|
||||
if (count($filtered) > 0) {
|
||||
$this->getHandler($filtered[count($filtered) - 1])->handleBatch($filtered);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the nested handler
|
||||
*
|
||||
* If the handler was provided as a factory callable, this will trigger the handler's instantiation.
|
||||
*
|
||||
* @return HandlerInterface
|
||||
*/
|
||||
public function getHandler(array $record = null)
|
||||
{
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
$this->handler = call_user_func($this->handler, $record, $this);
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
throw new \RuntimeException("The factory callable should return a HandlerInterface");
|
||||
}
|
||||
}
|
||||
|
||||
return $this->handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setFormatter(FormatterInterface $formatter)
|
||||
{
|
||||
$this->getHandler()->setFormatter($formatter);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormatter()
|
||||
{
|
||||
return $this->getHandler()->getFormatter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
|
||||
use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
|
||||
use Monolog\Logger;
|
||||
use Monolog\ResettableInterface;
|
||||
use Monolog\Formatter\FormatterInterface;
|
||||
|
||||
/**
|
||||
* Buffers all records until a certain level is reached
|
||||
@@ -39,7 +40,7 @@ class FingersCrossedHandler extends AbstractHandler
|
||||
protected $passthruLevel;
|
||||
|
||||
/**
|
||||
* @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler).
|
||||
* @param callable|HandlerInterface $handler Handler or factory callable($record|null, $fingersCrossedHandler).
|
||||
* @param int|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action
|
||||
* @param int $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
|
||||
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
|
||||
@@ -88,15 +89,7 @@ class FingersCrossedHandler extends AbstractHandler
|
||||
if ($this->stopBuffering) {
|
||||
$this->buffering = false;
|
||||
}
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
$record = end($this->buffer) ?: null;
|
||||
|
||||
$this->handler = call_user_func($this->handler, $record, $this);
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
throw new \RuntimeException("The factory callable should return a HandlerInterface");
|
||||
}
|
||||
}
|
||||
$this->handler->handleBatch($this->buffer);
|
||||
$this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer);
|
||||
$this->buffer = array();
|
||||
}
|
||||
|
||||
@@ -120,7 +113,7 @@ class FingersCrossedHandler extends AbstractHandler
|
||||
$this->activate();
|
||||
}
|
||||
} else {
|
||||
$this->handler->handle($record);
|
||||
$this->getHandler($record)->handle($record);
|
||||
}
|
||||
|
||||
return false === $this->bubble;
|
||||
@@ -140,8 +133,8 @@ class FingersCrossedHandler extends AbstractHandler
|
||||
|
||||
parent::reset();
|
||||
|
||||
if ($this->handler instanceof ResettableInterface) {
|
||||
$this->handler->reset();
|
||||
if ($this->getHandler() instanceof ResettableInterface) {
|
||||
$this->getHandler()->reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,11 +160,48 @@ class FingersCrossedHandler extends AbstractHandler
|
||||
return $record['level'] >= $level;
|
||||
});
|
||||
if (count($this->buffer) > 0) {
|
||||
$this->handler->handleBatch($this->buffer);
|
||||
$this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer);
|
||||
}
|
||||
}
|
||||
|
||||
$this->buffer = array();
|
||||
$this->buffering = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the nested handler
|
||||
*
|
||||
* If the handler was provided as a factory callable, this will trigger the handler's instantiation.
|
||||
*
|
||||
* @return HandlerInterface
|
||||
*/
|
||||
public function getHandler(array $record = null)
|
||||
{
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
$this->handler = call_user_func($this->handler, $record, $this);
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
throw new \RuntimeException("The factory callable should return a HandlerInterface");
|
||||
}
|
||||
}
|
||||
|
||||
return $this->handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setFormatter(FormatterInterface $formatter)
|
||||
{
|
||||
$this->getHandler()->setFormatter($formatter);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormatter()
|
||||
{
|
||||
return $this->getHandler()->getFormatter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ class FirePHPHandler extends AbstractProcessingHandler
|
||||
*
|
||||
* @see createHeader()
|
||||
* @param array $record
|
||||
* @return string
|
||||
* @return array
|
||||
*/
|
||||
protected function createRecordHeader(array $record)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace Monolog\Handler;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Utils;
|
||||
use Monolog\Formatter\FlowdockFormatter;
|
||||
use Monolog\Formatter\FormatterInterface;
|
||||
|
||||
@@ -105,7 +106,7 @@ class FlowdockHandler extends SocketHandler
|
||||
*/
|
||||
private function buildContent($record)
|
||||
{
|
||||
return json_encode($record['formatted']['flowdock']);
|
||||
return Utils::jsonEncode($record['formatted']['flowdock']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
39
vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php
vendored
Normal file
39
vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Interface to describe loggers that have a formatter
|
||||
*
|
||||
* This interface is present in monolog 1.x to ease forward compatibility.
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
interface FormattableHandlerInterface
|
||||
{
|
||||
/**
|
||||
* Sets the formatter.
|
||||
*
|
||||
* @param FormatterInterface $formatter
|
||||
* @return HandlerInterface self
|
||||
*/
|
||||
public function setFormatter(FormatterInterface $formatter): HandlerInterface;
|
||||
|
||||
/**
|
||||
* Gets the formatter.
|
||||
*
|
||||
* @return FormatterInterface
|
||||
*/
|
||||
public function getFormatter(): FormatterInterface;
|
||||
}
|
||||
63
vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php
vendored
Normal file
63
vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
|
||||
/**
|
||||
* Helper trait for implementing FormattableInterface
|
||||
*
|
||||
* This trait is present in monolog 1.x to ease forward compatibility.
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
trait FormattableHandlerTrait
|
||||
{
|
||||
/**
|
||||
* @var FormatterInterface
|
||||
*/
|
||||
protected $formatter;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @suppress PhanTypeMismatchReturn
|
||||
*/
|
||||
public function setFormatter(FormatterInterface $formatter): HandlerInterface
|
||||
{
|
||||
$this->formatter = $formatter;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormatter(): FormatterInterface
|
||||
{
|
||||
if (!$this->formatter) {
|
||||
$this->formatter = $this->getDefaultFormatter();
|
||||
}
|
||||
|
||||
return $this->formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default formatter.
|
||||
*
|
||||
* Overwrite this if the LineFormatter is not a good default for your handler.
|
||||
*/
|
||||
protected function getDefaultFormatter(): FormatterInterface
|
||||
{
|
||||
return new LineFormatter();
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ use Monolog\Formatter\GelfMessageFormatter;
|
||||
class GelfHandler extends AbstractProcessingHandler
|
||||
{
|
||||
/**
|
||||
* @var Publisher the publisher object that sends the message to the server
|
||||
* @var Publisher|PublisherInterface|IMessagePublisher the publisher object that sends the message to the server
|
||||
*/
|
||||
protected $publisher;
|
||||
|
||||
|
||||
@@ -80,8 +80,9 @@ class GroupHandler extends AbstractHandler
|
||||
$processed = array();
|
||||
foreach ($records as $record) {
|
||||
foreach ($this->processors as $processor) {
|
||||
$processed[] = call_user_func($processor, $record);
|
||||
$record = call_user_func($processor, $record);
|
||||
}
|
||||
$processed[] = $record;
|
||||
}
|
||||
$records = $processed;
|
||||
}
|
||||
|
||||
@@ -97,6 +97,8 @@ class HipChatHandler extends SocketHandler
|
||||
*/
|
||||
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)
|
||||
{
|
||||
@trigger_error('The Monolog\Handler\HipChatHandler class is deprecated. You should migrate to Slack and the SlackWebhookHandler / SlackbotHandler, see https://www.atlassian.com/partnerships/slack', E_USER_DEPRECATED);
|
||||
|
||||
if ($version == self::API_V1 && !$this->validateStringLength($name, static::MAXIMUM_NAME_LENGTH)) {
|
||||
throw new \InvalidArgumentException('The supplied name is too long. HipChat\'s v1 API supports names up to 15 UTF-8 characters.');
|
||||
}
|
||||
@@ -268,10 +270,10 @@ class HipChatHandler extends SocketHandler
|
||||
* will be the highest level from the given records. Datetime will be taken
|
||||
* from the first record.
|
||||
*
|
||||
* @param $records
|
||||
* @param array $records
|
||||
* @return array
|
||||
*/
|
||||
private function combineRecords($records)
|
||||
private function combineRecords(array $records)
|
||||
{
|
||||
$batchRecord = null;
|
||||
$batchRecords = array();
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace Monolog\Handler;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Utils;
|
||||
|
||||
/**
|
||||
* IFTTTHandler uses cURL to trigger IFTTT Maker actions
|
||||
@@ -53,7 +54,7 @@ class IFTTTHandler extends AbstractProcessingHandler
|
||||
"value2" => $record["level_name"],
|
||||
"value3" => $record["message"],
|
||||
);
|
||||
$postString = json_encode($postData);
|
||||
$postString = Utils::jsonEncode($postData);
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, "https://maker.ifttt.com/trigger/" . $this->eventName . "/with/key/" . $this->secretKey);
|
||||
|
||||
@@ -38,7 +38,7 @@ class InsightOpsHandler extends SocketHandler
|
||||
public function __construct($token, $region = 'us', $useSSL = true, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
if ($useSSL && !extension_loaded('openssl')) {
|
||||
throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler');
|
||||
throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for InsightOpsHandler');
|
||||
}
|
||||
|
||||
$endpoint = $useSSL
|
||||
|
||||
@@ -50,7 +50,11 @@ class MandrillHandler extends MailHandler
|
||||
{
|
||||
$message = clone $this->message;
|
||||
$message->setBody($content);
|
||||
$message->setDate(time());
|
||||
if (version_compare(\Swift::VERSION, '6.0.0', '>=')) {
|
||||
$message->setDate(new \DateTimeImmutable());
|
||||
} else {
|
||||
$message->setDate(time());
|
||||
}
|
||||
|
||||
$ch = curl_init();
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace Monolog\Handler;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Utils;
|
||||
use Monolog\Formatter\NormalizerFormatter;
|
||||
|
||||
/**
|
||||
@@ -190,7 +191,7 @@ class NewRelicHandler extends AbstractProcessingHandler
|
||||
if (null === $value || is_scalar($value)) {
|
||||
newrelic_add_custom_parameter($key, $value);
|
||||
} else {
|
||||
newrelic_add_custom_parameter($key, @json_encode($value));
|
||||
newrelic_add_custom_parameter($key, Utils::jsonEncode($value, null, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Monolog\Handler;
|
||||
use Exception;
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
use Monolog\Logger;
|
||||
use Monolog\Utils;
|
||||
use PhpConsole\Connector;
|
||||
use PhpConsole\Handler;
|
||||
use PhpConsole\Helper;
|
||||
@@ -188,7 +189,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler
|
||||
$tags = $this->getRecordTags($record);
|
||||
$message = $record['message'];
|
||||
if ($record['context']) {
|
||||
$message .= ' ' . json_encode($this->connector->getDumper()->dump(array_filter($record['context'])));
|
||||
$message .= ' ' . Utils::jsonEncode($this->connector->getDumper()->dump(array_filter($record['context'])), null, true);
|
||||
}
|
||||
$this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']);
|
||||
}
|
||||
|
||||
40
vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php
vendored
Normal file
40
vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\Processor\ProcessorInterface;
|
||||
|
||||
/**
|
||||
* Interface to describe loggers that have processors
|
||||
*
|
||||
* This interface is present in monolog 1.x to ease forward compatibility.
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
interface ProcessableHandlerInterface
|
||||
{
|
||||
/**
|
||||
* Adds a processor in the stack.
|
||||
*
|
||||
* @param ProcessorInterface|callable $callback
|
||||
* @return HandlerInterface self
|
||||
*/
|
||||
public function pushProcessor($callback): HandlerInterface;
|
||||
|
||||
/**
|
||||
* Removes the processor on top of the stack and returns it.
|
||||
*
|
||||
* @throws \LogicException In case the processor stack is empty
|
||||
* @return callable
|
||||
*/
|
||||
public function popProcessor(): callable;
|
||||
}
|
||||
73
vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php
vendored
Normal file
73
vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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\ResettableInterface;
|
||||
|
||||
/**
|
||||
* Helper trait for implementing ProcessableInterface
|
||||
*
|
||||
* This trait is present in monolog 1.x to ease forward compatibility.
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
trait ProcessableHandlerTrait
|
||||
{
|
||||
/**
|
||||
* @var callable[]
|
||||
*/
|
||||
protected $processors = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @suppress PhanTypeMismatchReturn
|
||||
*/
|
||||
public function pushProcessor($callback): HandlerInterface
|
||||
{
|
||||
array_unshift($this->processors, $callback);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function popProcessor(): callable
|
||||
{
|
||||
if (!$this->processors) {
|
||||
throw new \LogicException('You tried to pop from an empty processor stack.');
|
||||
}
|
||||
|
||||
return array_shift($this->processors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a record.
|
||||
*/
|
||||
protected function processRecord(array $record): array
|
||||
{
|
||||
foreach ($this->processors as $processor) {
|
||||
$record = $processor($record);
|
||||
}
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
protected function resetProcessors(): void
|
||||
{
|
||||
foreach ($this->processors as $processor) {
|
||||
if ($processor instanceof ResettableInterface) {
|
||||
$processor->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ class RavenHandler extends AbstractProcessingHandler
|
||||
protected $ravenClient;
|
||||
|
||||
/**
|
||||
* @var LineFormatter The formatter to use for the logs generated via handleBatch()
|
||||
* @var FormatterInterface The formatter to use for the logs generated via handleBatch()
|
||||
*/
|
||||
protected $batchFormatter;
|
||||
|
||||
@@ -61,6 +61,8 @@ class RavenHandler extends AbstractProcessingHandler
|
||||
*/
|
||||
public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
@trigger_error('The Monolog\Handler\RavenHandler class is deprecated. You should rather upgrade to the sentry/sentry 2.x and use Sentry\Monolog\Handler, see https://github.com/getsentry/sentry-php/blob/master/src/Monolog/Handler.php', E_USER_DEPRECATED);
|
||||
|
||||
parent::__construct($level, $bubble);
|
||||
|
||||
$this->ravenClient = $ravenClient;
|
||||
@@ -84,7 +86,7 @@ class RavenHandler extends AbstractProcessingHandler
|
||||
|
||||
// the record with the highest severity is the "main" one
|
||||
$record = array_reduce($records, function ($highest, $record) {
|
||||
if ($record['level'] > $highest['level']) {
|
||||
if (null === $highest || $record['level'] > $highest['level']) {
|
||||
return $record;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class RedisHandler extends AbstractProcessingHandler
|
||||
* @param string $key The key name to push records 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
|
||||
* @param int|false $capSize Number of entries to limit list size to
|
||||
*/
|
||||
public function __construct($redis, $key, $level = Logger::DEBUG, $bubble = true, $capSize = false)
|
||||
{
|
||||
@@ -73,7 +73,8 @@ class RedisHandler extends AbstractProcessingHandler
|
||||
protected function writeCapped(array $record)
|
||||
{
|
||||
if ($this->redisClient instanceof \Redis) {
|
||||
$this->redisClient->multi()
|
||||
$mode = defined('\Redis::MULTI') ? \Redis::MULTI : 1;
|
||||
$this->redisClient->multi($mode)
|
||||
->rpush($this->redisKey, $record["formatted"])
|
||||
->ltrim($this->redisKey, -$this->capSize, -1)
|
||||
->exec();
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace Monolog\Handler;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Utils;
|
||||
|
||||
/**
|
||||
* Stores logs to files that are rotated every day and a limited number of files are kept.
|
||||
@@ -45,7 +46,7 @@ class RotatingFileHandler extends StreamHandler
|
||||
*/
|
||||
public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false)
|
||||
{
|
||||
$this->filename = $filename;
|
||||
$this->filename = Utils::canonicalizePath($filename);
|
||||
$this->maxFiles = (int) $maxFiles;
|
||||
$this->nextRotation = new \DateTime('tomorrow');
|
||||
$this->filenameFormat = '{filename}-{date}';
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace Monolog\Handler;
|
||||
|
||||
use Monolog\Formatter\FormatterInterface;
|
||||
|
||||
/**
|
||||
* Sampling handler
|
||||
*
|
||||
@@ -38,7 +40,7 @@ class SamplingHandler extends AbstractHandler
|
||||
protected $factor;
|
||||
|
||||
/**
|
||||
* @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler).
|
||||
* @param callable|HandlerInterface $handler Handler or factory callable($record|null, $samplingHandler).
|
||||
* @param int $factor Sample factor
|
||||
*/
|
||||
public function __construct($handler, $factor)
|
||||
@@ -54,29 +56,58 @@ class SamplingHandler extends AbstractHandler
|
||||
|
||||
public function isHandling(array $record)
|
||||
{
|
||||
return $this->handler->isHandling($record);
|
||||
return $this->getHandler($record)->isHandling($record);
|
||||
}
|
||||
|
||||
public function handle(array $record)
|
||||
{
|
||||
if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) {
|
||||
// The same logic as in FingersCrossedHandler
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
$this->handler = call_user_func($this->handler, $record, $this);
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
throw new \RuntimeException("The factory callable should return a HandlerInterface");
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->processors) {
|
||||
foreach ($this->processors as $processor) {
|
||||
$record = call_user_func($processor, $record);
|
||||
}
|
||||
}
|
||||
|
||||
$this->handler->handle($record);
|
||||
$this->getHandler($record)->handle($record);
|
||||
}
|
||||
|
||||
return false === $this->bubble;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the nested handler
|
||||
*
|
||||
* If the handler was provided as a factory callable, this will trigger the handler's instantiation.
|
||||
*
|
||||
* @return HandlerInterface
|
||||
*/
|
||||
public function getHandler(array $record = null)
|
||||
{
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
$this->handler = call_user_func($this->handler, $record, $this);
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
throw new \RuntimeException("The factory callable should return a HandlerInterface");
|
||||
}
|
||||
}
|
||||
|
||||
return $this->handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setFormatter(FormatterInterface $formatter)
|
||||
{
|
||||
$this->getHandler()->setFormatter($formatter);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormatter()
|
||||
{
|
||||
return $this->getHandler()->getFormatter();
|
||||
}
|
||||
}
|
||||
|
||||
9
vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php
vendored
Executable file → Normal file
9
vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php
vendored
Executable file → Normal file
@@ -12,6 +12,7 @@
|
||||
namespace Monolog\Handler\Slack;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Utils;
|
||||
use Monolog\Formatter\NormalizerFormatter;
|
||||
use Monolog\Formatter\FormatterInterface;
|
||||
|
||||
@@ -207,13 +208,17 @@ class SlackRecord
|
||||
{
|
||||
$normalized = $this->normalizerFormatter->format($fields);
|
||||
$prettyPrintFlag = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 128;
|
||||
$flags = 0;
|
||||
if (PHP_VERSION_ID >= 50400) {
|
||||
$flags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
|
||||
}
|
||||
|
||||
$hasSecondDimension = count(array_filter($normalized, 'is_array'));
|
||||
$hasNonNumericKeys = !count(array_filter(array_keys($normalized), 'is_numeric'));
|
||||
|
||||
return $hasSecondDimension || $hasNonNumericKeys
|
||||
? json_encode($normalized, $prettyPrintFlag)
|
||||
: json_encode($normalized);
|
||||
? Utils::jsonEncode($normalized, $prettyPrintFlag | $flags)
|
||||
: Utils::jsonEncode($normalized, $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Monolog\Handler;
|
||||
|
||||
use Monolog\Formatter\FormatterInterface;
|
||||
use Monolog\Logger;
|
||||
use Monolog\Utils;
|
||||
use Monolog\Handler\Slack\SlackRecord;
|
||||
|
||||
/**
|
||||
@@ -118,7 +119,7 @@ class SlackHandler extends SocketHandler
|
||||
$dataArray['token'] = $this->token;
|
||||
|
||||
if (!empty($dataArray['attachments'])) {
|
||||
$dataArray['attachments'] = json_encode($dataArray['attachments']);
|
||||
$dataArray['attachments'] = Utils::jsonEncode($dataArray['attachments']);
|
||||
}
|
||||
|
||||
return $dataArray;
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Monolog\Handler;
|
||||
|
||||
use Monolog\Formatter\FormatterInterface;
|
||||
use Monolog\Logger;
|
||||
use Monolog\Utils;
|
||||
use Monolog\Handler\Slack\SlackRecord;
|
||||
|
||||
/**
|
||||
@@ -83,7 +84,7 @@ class SlackWebhookHandler extends AbstractProcessingHandler
|
||||
protected function write(array $record)
|
||||
{
|
||||
$postData = $this->slackRecord->getSlackData($record);
|
||||
$postString = json_encode($postData);
|
||||
$postString = Utils::jsonEncode($postData);
|
||||
|
||||
$ch = curl_init();
|
||||
$options = array(
|
||||
|
||||
@@ -16,8 +16,11 @@ use Monolog\Logger;
|
||||
/**
|
||||
* Sends notifications through Slack's Slackbot
|
||||
*
|
||||
* @author Haralan Dobrev <hkdobrev@gmail.com>
|
||||
* @see https://slack.com/apps/A0F81R8ET-slackbot
|
||||
* @author Haralan Dobrev <hkdobrev@gmail.com>
|
||||
* @see https://slack.com/apps/A0F81R8ET-slackbot
|
||||
* @deprecated According to Slack the API used on this handler it is deprecated.
|
||||
* Therefore this handler will be removed on 2.x
|
||||
* Slack suggests to use webhooks instead. Please contact slack for more information.
|
||||
*/
|
||||
class SlackbotHandler extends AbstractProcessingHandler
|
||||
{
|
||||
@@ -48,6 +51,7 @@ class SlackbotHandler extends AbstractProcessingHandler
|
||||
*/
|
||||
public function __construct($slackTeam, $token, $channel, $level = Logger::CRITICAL, $bubble = true)
|
||||
{
|
||||
@trigger_error('SlackbotHandler is deprecated and will be removed on 2.x', E_USER_DEPRECATED);
|
||||
parent::__construct($level, $bubble);
|
||||
|
||||
$this->slackTeam = $slackTeam;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace Monolog\Handler;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Utils;
|
||||
|
||||
/**
|
||||
* Stores to any stream resource
|
||||
@@ -22,6 +23,10 @@ use Monolog\Logger;
|
||||
*/
|
||||
class StreamHandler extends AbstractProcessingHandler
|
||||
{
|
||||
/** @private 512KB */
|
||||
const CHUNK_SIZE = 524288;
|
||||
|
||||
/** @var resource|null */
|
||||
protected $stream;
|
||||
protected $url;
|
||||
private $errorMessage;
|
||||
@@ -44,8 +49,9 @@ class StreamHandler extends AbstractProcessingHandler
|
||||
parent::__construct($level, $bubble);
|
||||
if (is_resource($stream)) {
|
||||
$this->stream = $stream;
|
||||
$this->streamSetChunkSize();
|
||||
} elseif (is_string($stream)) {
|
||||
$this->url = $stream;
|
||||
$this->url = Utils::canonicalizePath($stream);
|
||||
} else {
|
||||
throw new \InvalidArgumentException('A stream must either be a resource or a string.');
|
||||
}
|
||||
@@ -63,6 +69,7 @@ class StreamHandler extends AbstractProcessingHandler
|
||||
fclose($this->stream);
|
||||
}
|
||||
$this->stream = null;
|
||||
$this->dirCreated = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,8 +111,10 @@ class StreamHandler extends AbstractProcessingHandler
|
||||
restore_error_handler();
|
||||
if (!is_resource($this->stream)) {
|
||||
$this->stream = null;
|
||||
throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: '.$this->errorMessage, $this->url));
|
||||
|
||||
throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage, $this->url));
|
||||
}
|
||||
$this->streamSetChunkSize();
|
||||
}
|
||||
|
||||
if ($this->useLocking) {
|
||||
@@ -130,6 +139,15 @@ class StreamHandler extends AbstractProcessingHandler
|
||||
fwrite($stream, (string) $record['formatted']);
|
||||
}
|
||||
|
||||
protected function streamSetChunkSize()
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
return stream_set_chunk_size($this->stream, self::CHUNK_SIZE);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function customErrorHandler($code, $msg)
|
||||
{
|
||||
$this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg);
|
||||
@@ -151,7 +169,7 @@ class StreamHandler extends AbstractProcessingHandler
|
||||
return dirname(substr($stream, 7));
|
||||
}
|
||||
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
private function createDir()
|
||||
|
||||
@@ -18,11 +18,21 @@ use Monolog\Handler\SyslogUdp\UdpSocket;
|
||||
* A Handler for logging to a remote syslogd server.
|
||||
*
|
||||
* @author Jesper Skovgaard Nielsen <nulpunkt@gmail.com>
|
||||
* @author Dominik Kukacka <dominik.kukacka@gmail.com>
|
||||
*/
|
||||
class SyslogUdpHandler extends AbstractSyslogHandler
|
||||
{
|
||||
const RFC3164 = 0;
|
||||
const RFC5424 = 1;
|
||||
|
||||
private $dateFormats = array(
|
||||
self::RFC3164 => 'M d H:i:s',
|
||||
self::RFC5424 => \DateTime::RFC3339,
|
||||
);
|
||||
|
||||
protected $socket;
|
||||
protected $ident;
|
||||
protected $rfc;
|
||||
|
||||
/**
|
||||
* @param string $host
|
||||
@@ -31,12 +41,14 @@ class SyslogUdpHandler extends AbstractSyslogHandler
|
||||
* @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 string $ident Program name or tag for each log message.
|
||||
* @param int $rfc RFC to format the message for.
|
||||
*/
|
||||
public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $ident = 'php')
|
||||
public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $ident = 'php', $rfc = self::RFC5424)
|
||||
{
|
||||
parent::__construct($facility, $level, $bubble);
|
||||
|
||||
$this->ident = $ident;
|
||||
$this->rfc = $rfc;
|
||||
|
||||
$this->socket = new UdpSocket($host, $port ?: 514);
|
||||
}
|
||||
@@ -67,7 +79,7 @@ class SyslogUdpHandler extends AbstractSyslogHandler
|
||||
}
|
||||
|
||||
/**
|
||||
* Make common syslog header (see rfc5424)
|
||||
* Make common syslog header (see rfc5424 or rfc3164)
|
||||
*/
|
||||
protected function makeCommonSyslogHeader($severity)
|
||||
{
|
||||
@@ -81,16 +93,25 @@ class SyslogUdpHandler extends AbstractSyslogHandler
|
||||
$hostname = '-';
|
||||
}
|
||||
|
||||
return "<$priority>1 " .
|
||||
$this->getDateTime() . " " .
|
||||
$hostname . " " .
|
||||
$this->ident . " " .
|
||||
$pid . " - - ";
|
||||
$date = $this->getDateTime();
|
||||
|
||||
if ($this->rfc === self::RFC3164) {
|
||||
return "<$priority>" .
|
||||
$date . " " .
|
||||
$hostname . " " .
|
||||
$this->ident . "[" . $pid . "]: ";
|
||||
} else {
|
||||
return "<$priority>1 " .
|
||||
$date . " " .
|
||||
$hostname . " " .
|
||||
$this->ident . " " .
|
||||
$pid . " - - ";
|
||||
}
|
||||
}
|
||||
|
||||
protected function getDateTime()
|
||||
{
|
||||
return date(\DateTime::RFC3339);
|
||||
return date($this->dateFormats[$this->rfc]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -67,6 +67,7 @@ class TestHandler extends AbstractProcessingHandler
|
||||
{
|
||||
protected $records = array();
|
||||
protected $recordsByLevel = array();
|
||||
private $skipReset = false;
|
||||
|
||||
public function getRecords()
|
||||
{
|
||||
@@ -79,6 +80,18 @@ class TestHandler extends AbstractProcessingHandler
|
||||
$this->recordsByLevel = array();
|
||||
}
|
||||
|
||||
public function reset()
|
||||
{
|
||||
if (!$this->skipReset) {
|
||||
$this->clear();
|
||||
}
|
||||
}
|
||||
|
||||
public function setSkipReset($skipReset)
|
||||
{
|
||||
$this->skipReset = $skipReset;
|
||||
}
|
||||
|
||||
public function hasRecords($level)
|
||||
{
|
||||
return isset($this->recordsByLevel[$level]);
|
||||
|
||||
@@ -52,8 +52,9 @@ class WhatFailureGroupHandler extends GroupHandler
|
||||
$processed = array();
|
||||
foreach ($records as $record) {
|
||||
foreach ($this->processors as $processor) {
|
||||
$processed[] = call_user_func($processor, $record);
|
||||
$record = call_user_func($processor, $record);
|
||||
}
|
||||
$processed[] = $record;
|
||||
}
|
||||
$records = $processed;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ use Monolog\Logger;
|
||||
* Handler sending logs to Zend Monitor
|
||||
*
|
||||
* @author Christian Bergau <cbergau86@gmail.com>
|
||||
* @author Jason Davis <happydude@jasondavis.net>
|
||||
*/
|
||||
class ZendMonitorHandler extends AbstractProcessingHandler
|
||||
{
|
||||
@@ -25,16 +26,7 @@ class ZendMonitorHandler extends AbstractProcessingHandler
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $levelMap = array(
|
||||
Logger::DEBUG => 1,
|
||||
Logger::INFO => 2,
|
||||
Logger::NOTICE => 3,
|
||||
Logger::WARNING => 4,
|
||||
Logger::ERROR => 5,
|
||||
Logger::CRITICAL => 6,
|
||||
Logger::ALERT => 7,
|
||||
Logger::EMERGENCY => 0,
|
||||
);
|
||||
protected $levelMap = array();
|
||||
|
||||
/**
|
||||
* Construct
|
||||
@@ -46,8 +38,21 @@ class ZendMonitorHandler extends AbstractProcessingHandler
|
||||
public function __construct($level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
if (!function_exists('zend_monitor_custom_event')) {
|
||||
throw new MissingExtensionException('You must have Zend Server installed in order to use this handler');
|
||||
throw new MissingExtensionException(
|
||||
'You must have Zend Server installed with Zend Monitor enabled in order to use this handler'
|
||||
);
|
||||
}
|
||||
//zend monitor constants are not defined if zend monitor is not enabled.
|
||||
$this->levelMap = array(
|
||||
Logger::DEBUG => \ZEND_MONITOR_EVENT_SEVERITY_INFO,
|
||||
Logger::INFO => \ZEND_MONITOR_EVENT_SEVERITY_INFO,
|
||||
Logger::NOTICE => \ZEND_MONITOR_EVENT_SEVERITY_INFO,
|
||||
Logger::WARNING => \ZEND_MONITOR_EVENT_SEVERITY_WARNING,
|
||||
Logger::ERROR => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
|
||||
Logger::CRITICAL => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
|
||||
Logger::ALERT => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
|
||||
Logger::EMERGENCY => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
|
||||
);
|
||||
parent::__construct($level, $bubble);
|
||||
}
|
||||
|
||||
@@ -57,22 +62,23 @@ class ZendMonitorHandler extends AbstractProcessingHandler
|
||||
protected function write(array $record)
|
||||
{
|
||||
$this->writeZendMonitorCustomEvent(
|
||||
$this->levelMap[$record['level']],
|
||||
Logger::getLevelName($record['level']),
|
||||
$record['message'],
|
||||
$record['formatted']
|
||||
$record['formatted'],
|
||||
$this->levelMap[$record['level']]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a record to Zend Monitor
|
||||
*
|
||||
* @param int $level
|
||||
* @param string $message
|
||||
* @param array $formatted
|
||||
* Write to Zend Monitor Events
|
||||
* @param string $type Text displayed in "Class Name (custom)" field
|
||||
* @param string $message Text displayed in "Error String"
|
||||
* @param mixed $formatted Displayed in Custom Variables tab
|
||||
* @param int $severity Set the event severity level (-1,0,1)
|
||||
*/
|
||||
protected function writeZendMonitorCustomEvent($level, $message, $formatted)
|
||||
protected function writeZendMonitorCustomEvent($type, $message, $formatted, $severity)
|
||||
{
|
||||
zend_monitor_custom_event($level, $message, $formatted);
|
||||
zend_monitor_custom_event($type, $message, $formatted, $severity);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
13
vendor/monolog/monolog/src/Monolog/Logger.php
vendored
13
vendor/monolog/monolog/src/Monolog/Logger.php
vendored
@@ -321,7 +321,7 @@ class Logger implements LoggerInterface, ResettableInterface
|
||||
if ($this->microsecondTimestamps && PHP_VERSION_ID < 70100) {
|
||||
$ts = \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), static::$timezone);
|
||||
} else {
|
||||
$ts = new \DateTime(null, static::$timezone);
|
||||
$ts = new \DateTime('now', static::$timezone);
|
||||
}
|
||||
$ts->setTimezone(static::$timezone);
|
||||
|
||||
@@ -522,13 +522,18 @@ class Logger implements LoggerInterface, ResettableInterface
|
||||
/**
|
||||
* Converts PSR-3 levels to Monolog ones if necessary
|
||||
*
|
||||
* @param string|int Level number (monolog) or name (PSR-3)
|
||||
* @param string|int $level Level number (monolog) or name (PSR-3)
|
||||
* @return int
|
||||
*/
|
||||
public static function toMonologLevel($level)
|
||||
{
|
||||
if (is_string($level) && defined(__CLASS__.'::'.strtoupper($level))) {
|
||||
return constant(__CLASS__.'::'.strtoupper($level));
|
||||
if (is_string($level)) {
|
||||
// Contains chars of all log levels and avoids using strtoupper() which may have
|
||||
// strange results depending on locale (for example, "i" will become "İ")
|
||||
$upper = strtr($level, 'abcdefgilmnortuwy', 'ABCDEFGILMNORTUWY');
|
||||
if (defined(__CLASS__.'::'.$upper)) {
|
||||
return constant(__CLASS__ . '::' . $upper);
|
||||
}
|
||||
}
|
||||
|
||||
return $level;
|
||||
|
||||
@@ -52,7 +52,7 @@ class GitProcessor implements ProcessorInterface
|
||||
}
|
||||
|
||||
$branches = `git branch -v --no-abbrev`;
|
||||
if (preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) {
|
||||
if ($branches && preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) {
|
||||
return self::$cache = array(
|
||||
'branch' => $matches[1],
|
||||
'commit' => $matches[2],
|
||||
|
||||
@@ -22,6 +22,24 @@ use Monolog\Utils;
|
||||
*/
|
||||
class PsrLogMessageProcessor implements ProcessorInterface
|
||||
{
|
||||
const SIMPLE_DATE = "Y-m-d\TH:i:s.uP";
|
||||
|
||||
/** @var string|null */
|
||||
private $dateFormat;
|
||||
|
||||
/** @var bool */
|
||||
private $removeUsedContextFields;
|
||||
|
||||
/**
|
||||
* @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format
|
||||
* @param bool $removeUsedContextFields If set to true the fields interpolated into message gets unset
|
||||
*/
|
||||
public function __construct($dateFormat = null, $removeUsedContextFields = false)
|
||||
{
|
||||
$this->dateFormat = $dateFormat;
|
||||
$this->removeUsedContextFields = $removeUsedContextFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $record
|
||||
* @return array
|
||||
@@ -34,12 +52,25 @@ class PsrLogMessageProcessor implements ProcessorInterface
|
||||
|
||||
$replacements = array();
|
||||
foreach ($record['context'] as $key => $val) {
|
||||
$placeholder = '{' . $key . '}';
|
||||
if (strpos($record['message'], $placeholder) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_null($val) || is_scalar($val) || (is_object($val) && method_exists($val, "__toString"))) {
|
||||
$replacements['{'.$key.'}'] = $val;
|
||||
$replacements[$placeholder] = $val;
|
||||
} elseif ($val instanceof \DateTime) {
|
||||
$replacements[$placeholder] = $val->format($this->dateFormat ?: static::SIMPLE_DATE);
|
||||
} elseif (is_object($val)) {
|
||||
$replacements['{'.$key.'}'] = '[object '.Utils::getClass($val).']';
|
||||
$replacements[$placeholder] = '[object '.Utils::getClass($val).']';
|
||||
} elseif (is_array($val)) {
|
||||
$replacements[$placeholder] = 'array'.Utils::jsonEncode($val, null, true);
|
||||
} else {
|
||||
$replacements['{'.$key.'}'] = '['.gettype($val).']';
|
||||
$replacements[$placeholder] = '['.gettype($val).']';
|
||||
}
|
||||
|
||||
if ($this->removeUsedContextFields) {
|
||||
unset($record['context'][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,10 @@ class WebProcessor implements ProcessorInterface
|
||||
throw new \UnexpectedValueException('$serverData must be an array or object implementing ArrayAccess.');
|
||||
}
|
||||
|
||||
if (isset($this->serverData['UNIQUE_ID'])) {
|
||||
$this->extraFields['unique_id'] = 'UNIQUE_ID';
|
||||
}
|
||||
|
||||
if (null !== $extraFields) {
|
||||
if (isset($extraFields[0])) {
|
||||
foreach (array_keys($this->extraFields) as $fieldName) {
|
||||
@@ -104,10 +108,6 @@ class WebProcessor implements ProcessorInterface
|
||||
$extra[$extraName] = isset($this->serverData[$serverName]) ? $this->serverData[$serverName] : null;
|
||||
}
|
||||
|
||||
if (isset($this->serverData['UNIQUE_ID'])) {
|
||||
$extra['unique_id'] = $this->serverData['UNIQUE_ID'];
|
||||
}
|
||||
|
||||
return $extra;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ class SignalHandler
|
||||
if ($this->previousSignalHandler[$signo] === true || $this->previousSignalHandler[$signo] === SIG_DFL) {
|
||||
if (extension_loaded('pcntl') && function_exists('pcntl_signal') && function_exists('pcntl_sigprocmask') && function_exists('pcntl_signal_dispatch')
|
||||
&& extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill')) {
|
||||
$restartSyscalls = isset($this->restartSyscalls[$signo]) ? $this->restartSyscalls[$signo] : true;
|
||||
$restartSyscalls = isset($this->signalRestartSyscalls[$signo]) ? $this->signalRestartSyscalls[$signo] : true;
|
||||
pcntl_signal($signo, SIG_DFL, $restartSyscalls);
|
||||
pcntl_sigprocmask(SIG_UNBLOCK, array($signo), $oldset);
|
||||
posix_kill(posix_getpid(), $signo);
|
||||
|
||||
164
vendor/monolog/monolog/src/Monolog/Utils.php
vendored
164
vendor/monolog/monolog/src/Monolog/Utils.php
vendored
@@ -22,4 +22,168 @@ class Utils
|
||||
|
||||
return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure if a relative path is passed in it is turned into an absolute path
|
||||
*
|
||||
* @param string $streamUrl stream URL or path without protocol
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function canonicalizePath($streamUrl)
|
||||
{
|
||||
$prefix = '';
|
||||
if ('file://' === substr($streamUrl, 0, 7)) {
|
||||
$streamUrl = substr($streamUrl, 7);
|
||||
$prefix = 'file://';
|
||||
}
|
||||
|
||||
// other type of stream, not supported
|
||||
if (false !== strpos($streamUrl, '://')) {
|
||||
return $streamUrl;
|
||||
}
|
||||
|
||||
// already absolute
|
||||
if (substr($streamUrl, 0, 1) === '/' || substr($streamUrl, 1, 1) === ':' || substr($streamUrl, 0, 2) === '\\\\') {
|
||||
return $prefix.$streamUrl;
|
||||
}
|
||||
|
||||
$streamUrl = getcwd() . '/' . $streamUrl;
|
||||
|
||||
return $prefix.$streamUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JSON representation of a value
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
|
||||
* @param bool $ignoreErrors whether to ignore encoding errors or to throw on error, when ignored and the encoding fails, "null" is returned which is valid json for null
|
||||
* @throws \RuntimeException if encoding fails and errors are not ignored
|
||||
* @return string
|
||||
*/
|
||||
public static function jsonEncode($data, $encodeFlags = null, $ignoreErrors = false)
|
||||
{
|
||||
if (null === $encodeFlags && version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
$encodeFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
|
||||
}
|
||||
|
||||
if ($ignoreErrors) {
|
||||
$json = @json_encode($data, $encodeFlags);
|
||||
if (false === $json) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
$json = json_encode($data, $encodeFlags);
|
||||
if (false === $json) {
|
||||
$json = self::handleJsonError(json_last_error(), $data);
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 attempt 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
|
||||
* @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
|
||||
* @throws \RuntimeException if failure can't be corrected
|
||||
* @return string JSON encoded data after error correction
|
||||
*/
|
||||
public static function handleJsonError($code, $data, $encodeFlags = null)
|
||||
{
|
||||
if ($code !== JSON_ERROR_UTF8) {
|
||||
self::throwEncodeError($code, $data);
|
||||
}
|
||||
|
||||
if (is_string($data)) {
|
||||
self::detectAndCleanUtf8($data);
|
||||
} elseif (is_array($data)) {
|
||||
array_walk_recursive($data, array('Monolog\Utils', 'detectAndCleanUtf8'));
|
||||
} else {
|
||||
self::throwEncodeError($code, $data);
|
||||
}
|
||||
|
||||
if (null === $encodeFlags && version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
$encodeFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
|
||||
}
|
||||
|
||||
$json = json_encode($data, $encodeFlags);
|
||||
|
||||
if ($json === false) {
|
||||
self::throwEncodeError(json_last_error(), $data);
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private static function throwEncodeError($code, $data)
|
||||
{
|
||||
switch ($code) {
|
||||
case JSON_ERROR_DEPTH:
|
||||
$msg = 'Maximum stack depth exceeded';
|
||||
break;
|
||||
case JSON_ERROR_STATE_MISMATCH:
|
||||
$msg = 'Underflow or the modes mismatch';
|
||||
break;
|
||||
case JSON_ERROR_CTRL_CHAR:
|
||||
$msg = 'Unexpected control character found';
|
||||
break;
|
||||
case JSON_ERROR_UTF8:
|
||||
$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
|
||||
break;
|
||||
default:
|
||||
$msg = 'Unknown error';
|
||||
}
|
||||
|
||||
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, passed by ref
|
||||
* @private
|
||||
*/
|
||||
public static 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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Monolog package.
|
||||
*
|
||||
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Monolog;
|
||||
|
||||
use Monolog\Handler\TestHandler;
|
||||
|
||||
class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testHandleError()
|
||||
{
|
||||
$logger = new Logger('test', array($handler = new TestHandler));
|
||||
$errHandler = new ErrorHandler($logger);
|
||||
|
||||
$errHandler->registerErrorHandler(array(E_USER_NOTICE => Logger::EMERGENCY), false);
|
||||
trigger_error('Foo', E_USER_ERROR);
|
||||
$this->assertCount(1, $handler->getRecords());
|
||||
$this->assertTrue($handler->hasErrorRecords());
|
||||
trigger_error('Foo', E_USER_NOTICE);
|
||||
$this->assertCount(2, $handler->getRecords());
|
||||
$this->assertTrue($handler->hasEmergencyRecords());
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
<?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;
|
||||
|
||||
class ChromePHPFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Monolog\Formatter\ChromePHPFormatter::format
|
||||
*/
|
||||
public function testDefaultFormat()
|
||||
{
|
||||
$formatter = new ChromePHPFormatter();
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('ip' => '127.0.0.1'),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = $formatter->format($record);
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'meh',
|
||||
array(
|
||||
'message' => 'log',
|
||||
'context' => array('from' => 'logger'),
|
||||
'extra' => array('ip' => '127.0.0.1'),
|
||||
),
|
||||
'unknown',
|
||||
'error',
|
||||
),
|
||||
$message
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\ChromePHPFormatter::format
|
||||
*/
|
||||
public function testFormatWithFileAndLine()
|
||||
{
|
||||
$formatter = new ChromePHPFormatter();
|
||||
$record = array(
|
||||
'level' => Logger::CRITICAL,
|
||||
'level_name' => 'CRITICAL',
|
||||
'channel' => 'meh',
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('ip' => '127.0.0.1', 'file' => 'test', 'line' => 14),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = $formatter->format($record);
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'meh',
|
||||
array(
|
||||
'message' => 'log',
|
||||
'context' => array('from' => 'logger'),
|
||||
'extra' => array('ip' => '127.0.0.1'),
|
||||
),
|
||||
'test : 14',
|
||||
'error',
|
||||
),
|
||||
$message
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\ChromePHPFormatter::format
|
||||
*/
|
||||
public function testFormatWithoutContext()
|
||||
{
|
||||
$formatter = new ChromePHPFormatter();
|
||||
$record = array(
|
||||
'level' => Logger::DEBUG,
|
||||
'level_name' => 'DEBUG',
|
||||
'channel' => 'meh',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array(),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = $formatter->format($record);
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'meh',
|
||||
'log',
|
||||
'unknown',
|
||||
'log',
|
||||
),
|
||||
$message
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\ChromePHPFormatter::formatBatch
|
||||
*/
|
||||
public function testBatchFormatThrowException()
|
||||
{
|
||||
$formatter = new ChromePHPFormatter();
|
||||
$records = array(
|
||||
array(
|
||||
'level' => Logger::INFO,
|
||||
'level_name' => 'INFO',
|
||||
'channel' => 'meh',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array(),
|
||||
'message' => 'log',
|
||||
),
|
||||
array(
|
||||
'level' => Logger::WARNING,
|
||||
'level_name' => 'WARNING',
|
||||
'channel' => 'foo',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array(),
|
||||
'message' => 'log2',
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
array(
|
||||
'meh',
|
||||
'log',
|
||||
'unknown',
|
||||
'info',
|
||||
),
|
||||
array(
|
||||
'foo',
|
||||
'log2',
|
||||
'unknown',
|
||||
'warn',
|
||||
),
|
||||
),
|
||||
$formatter->formatBatch($records)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
<?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;
|
||||
|
||||
class ElasticaFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
if (!class_exists("Elastica\Document")) {
|
||||
$this->markTestSkipped("ruflin/elastica not installed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\ElasticaFormatter::__construct
|
||||
* @covers Monolog\Formatter\ElasticaFormatter::format
|
||||
* @covers Monolog\Formatter\ElasticaFormatter::getDocument
|
||||
*/
|
||||
public function testFormat()
|
||||
{
|
||||
// test log message
|
||||
$msg = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('foo' => 7, 'bar', 'class' => new \stdClass),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array(),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
// expected values
|
||||
$expected = $msg;
|
||||
$expected['datetime'] = '1970-01-01T00:00:00.000000+00:00';
|
||||
$expected['context'] = array(
|
||||
'class' => '[object] (stdClass: {})',
|
||||
'foo' => 7,
|
||||
0 => 'bar',
|
||||
);
|
||||
|
||||
// format log message
|
||||
$formatter = new ElasticaFormatter('my_index', 'doc_type');
|
||||
$doc = $formatter->format($msg);
|
||||
$this->assertInstanceOf('Elastica\Document', $doc);
|
||||
|
||||
// Document parameters
|
||||
$params = $doc->getParams();
|
||||
$this->assertEquals('my_index', $params['_index']);
|
||||
$this->assertEquals('doc_type', $params['_type']);
|
||||
|
||||
// Document data values
|
||||
$data = $doc->getData();
|
||||
foreach (array_keys($expected) as $key) {
|
||||
$this->assertEquals($expected[$key], $data[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\ElasticaFormatter::getIndex
|
||||
* @covers Monolog\Formatter\ElasticaFormatter::getType
|
||||
*/
|
||||
public function testGetters()
|
||||
{
|
||||
$formatter = new ElasticaFormatter('my_index', 'doc_type');
|
||||
$this->assertEquals('my_index', $formatter->getIndex());
|
||||
$this->assertEquals('doc_type', $formatter->getType());
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
<?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 FlowdockFormatterTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Monolog\Formatter\FlowdockFormatter::format
|
||||
*/
|
||||
public function testFormat()
|
||||
{
|
||||
$formatter = new FlowdockFormatter('test_source', 'source@test.com');
|
||||
$record = $this->getRecord();
|
||||
|
||||
$expected = array(
|
||||
'source' => 'test_source',
|
||||
'from_address' => 'source@test.com',
|
||||
'subject' => 'in test_source: WARNING - test',
|
||||
'content' => 'test',
|
||||
'tags' => array('#logs', '#warning', '#test'),
|
||||
'project' => 'test_source',
|
||||
);
|
||||
$formatted = $formatter->format($record);
|
||||
|
||||
$this->assertEquals($expected, $formatted['flowdock']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ covers Monolog\Formatter\FlowdockFormatter::formatBatch
|
||||
*/
|
||||
public function testFormatBatch()
|
||||
{
|
||||
$formatter = new FlowdockFormatter('test_source', 'source@test.com');
|
||||
$records = array(
|
||||
$this->getRecord(Logger::WARNING),
|
||||
$this->getRecord(Logger::DEBUG),
|
||||
);
|
||||
$formatted = $formatter->formatBatch($records);
|
||||
|
||||
$this->assertArrayHasKey('flowdock', $formatted[0]);
|
||||
$this->assertArrayHasKey('flowdock', $formatted[1]);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
<?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","context":[],"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","context":[],"extra":[]}]',
|
||||
$formatter->format($record)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,258 +0,0 @@
|
||||
<?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;
|
||||
|
||||
class GelfMessageFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
if (!class_exists('\Gelf\Message')) {
|
||||
$this->markTestSkipped("graylog2/gelf-php or mlehner/gelf-php is not installed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\GelfMessageFormatter::format
|
||||
*/
|
||||
public function testDefaultFormatter()
|
||||
{
|
||||
$formatter = new GelfMessageFormatter();
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array(),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = $formatter->format($record);
|
||||
|
||||
$this->assertInstanceOf('Gelf\Message', $message);
|
||||
$this->assertEquals(0, $message->getTimestamp());
|
||||
$this->assertEquals('log', $message->getShortMessage());
|
||||
$this->assertEquals('meh', $message->getFacility());
|
||||
$this->assertEquals(null, $message->getLine());
|
||||
$this->assertEquals(null, $message->getFile());
|
||||
$this->assertEquals($this->isLegacy() ? 3 : 'error', $message->getLevel());
|
||||
$this->assertNotEmpty($message->getHost());
|
||||
|
||||
$formatter = new GelfMessageFormatter('mysystem');
|
||||
|
||||
$message = $formatter->format($record);
|
||||
|
||||
$this->assertInstanceOf('Gelf\Message', $message);
|
||||
$this->assertEquals('mysystem', $message->getHost());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\GelfMessageFormatter::format
|
||||
*/
|
||||
public function testFormatWithFileAndLine()
|
||||
{
|
||||
$formatter = new GelfMessageFormatter();
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('file' => 'test', 'line' => 14),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = $formatter->format($record);
|
||||
|
||||
$this->assertInstanceOf('Gelf\Message', $message);
|
||||
$this->assertEquals('test', $message->getFile());
|
||||
$this->assertEquals(14, $message->getLine());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\GelfMessageFormatter::format
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testFormatInvalidFails()
|
||||
{
|
||||
$formatter = new GelfMessageFormatter();
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
);
|
||||
|
||||
$formatter->format($record);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\GelfMessageFormatter::format
|
||||
*/
|
||||
public function testFormatWithContext()
|
||||
{
|
||||
$formatter = new GelfMessageFormatter();
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => 'pair'),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = $formatter->format($record);
|
||||
|
||||
$this->assertInstanceOf('Gelf\Message', $message);
|
||||
|
||||
$message_array = $message->toArray();
|
||||
|
||||
$this->assertArrayHasKey('_ctxt_from', $message_array);
|
||||
$this->assertEquals('logger', $message_array['_ctxt_from']);
|
||||
|
||||
// Test with extraPrefix
|
||||
$formatter = new GelfMessageFormatter(null, null, 'CTX');
|
||||
$message = $formatter->format($record);
|
||||
|
||||
$this->assertInstanceOf('Gelf\Message', $message);
|
||||
|
||||
$message_array = $message->toArray();
|
||||
|
||||
$this->assertArrayHasKey('_CTXfrom', $message_array);
|
||||
$this->assertEquals('logger', $message_array['_CTXfrom']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\GelfMessageFormatter::format
|
||||
*/
|
||||
public function testFormatWithContextContainingException()
|
||||
{
|
||||
$formatter = new GelfMessageFormatter();
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'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'),
|
||||
)),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array(),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = $formatter->format($record);
|
||||
|
||||
$this->assertInstanceOf('Gelf\Message', $message);
|
||||
|
||||
$this->assertEquals("/some/file/in/dir.php", $message->getFile());
|
||||
$this->assertEquals("56", $message->getLine());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\GelfMessageFormatter::format
|
||||
*/
|
||||
public function testFormatWithExtra()
|
||||
{
|
||||
$formatter = new GelfMessageFormatter();
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => 'pair'),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = $formatter->format($record);
|
||||
|
||||
$this->assertInstanceOf('Gelf\Message', $message);
|
||||
|
||||
$message_array = $message->toArray();
|
||||
|
||||
$this->assertArrayHasKey('_key', $message_array);
|
||||
$this->assertEquals('pair', $message_array['_key']);
|
||||
|
||||
// Test with extraPrefix
|
||||
$formatter = new GelfMessageFormatter(null, 'EXT');
|
||||
$message = $formatter->format($record);
|
||||
|
||||
$this->assertInstanceOf('Gelf\Message', $message);
|
||||
|
||||
$message_array = $message->toArray();
|
||||
|
||||
$this->assertArrayHasKey('_EXTkey', $message_array);
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertLessThanOrEqual(65792, $length, 'The message length is no longer than the maximum allowed length');
|
||||
}
|
||||
|
||||
public function testFormatWithUnlimitedLength()
|
||||
{
|
||||
$formatter = new GelfMessageFormatter('LONG_SYSTEM_NAME', null, 'ctxt_', PHP_INT_MAX);
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('exception' => str_repeat(' ', 32767 * 2)),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => str_repeat(' ', 32767 * 2)),
|
||||
'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);
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertGreaterThanOrEqual(131289, $length, 'The message should not be truncated');
|
||||
}
|
||||
|
||||
private function isLegacy()
|
||||
{
|
||||
return interface_exists('\Gelf\IMessagePublisher');
|
||||
}
|
||||
}
|
||||
@@ -1,219 +0,0 @@
|
||||
<?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 JsonFormatterTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Monolog\Formatter\JsonFormatter::__construct
|
||||
* @covers Monolog\Formatter\JsonFormatter::getBatchMode
|
||||
* @covers Monolog\Formatter\JsonFormatter::isAppendingNewlines
|
||||
*/
|
||||
public function testConstruct()
|
||||
{
|
||||
$formatter = new JsonFormatter();
|
||||
$this->assertEquals(JsonFormatter::BATCH_MODE_JSON, $formatter->getBatchMode());
|
||||
$this->assertEquals(true, $formatter->isAppendingNewlines());
|
||||
$formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_NEWLINES, false);
|
||||
$this->assertEquals(JsonFormatter::BATCH_MODE_NEWLINES, $formatter->getBatchMode());
|
||||
$this->assertEquals(false, $formatter->isAppendingNewlines());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\JsonFormatter::format
|
||||
*/
|
||||
public function testFormat()
|
||||
{
|
||||
$formatter = new JsonFormatter();
|
||||
$record = $this->getRecord();
|
||||
$this->assertEquals(json_encode($record)."\n", $formatter->format($record));
|
||||
|
||||
$formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false);
|
||||
$record = $this->getRecord();
|
||||
$this->assertEquals(json_encode($record), $formatter->format($record));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\JsonFormatter::formatBatch
|
||||
* @covers Monolog\Formatter\JsonFormatter::formatBatchJson
|
||||
*/
|
||||
public function testFormatBatch()
|
||||
{
|
||||
$formatter = new JsonFormatter();
|
||||
$records = array(
|
||||
$this->getRecord(Logger::WARNING),
|
||||
$this->getRecord(Logger::DEBUG),
|
||||
);
|
||||
$this->assertEquals(json_encode($records), $formatter->formatBatch($records));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\JsonFormatter::formatBatch
|
||||
* @covers Monolog\Formatter\JsonFormatter::formatBatchNewlines
|
||||
*/
|
||||
public function testFormatBatchNewlines()
|
||||
{
|
||||
$formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_NEWLINES);
|
||||
$records = $expected = array(
|
||||
$this->getRecord(Logger::WARNING),
|
||||
$this->getRecord(Logger::DEBUG),
|
||||
);
|
||||
array_walk($expected, function (&$value, $key) {
|
||||
$value = json_encode($value);
|
||||
});
|
||||
$this->assertEquals(implode("\n", $expected), $formatter->formatBatch($records));
|
||||
}
|
||||
|
||||
public function testDefFormatWithException()
|
||||
{
|
||||
$formatter = new JsonFormatter();
|
||||
$exception = new \RuntimeException('Foo');
|
||||
$formattedException = $this->formatException($exception);
|
||||
|
||||
$message = $this->formatRecordWithExceptionInContext($formatter, $exception);
|
||||
|
||||
$this->assertContextContainsFormattedException($formattedException, $message);
|
||||
}
|
||||
|
||||
public function testDefFormatWithPreviousException()
|
||||
{
|
||||
$formatter = new JsonFormatter();
|
||||
$exception = new \RuntimeException('Foo', 0, new \LogicException('Wut?'));
|
||||
$formattedPrevException = $this->formatException($exception->getPrevious());
|
||||
$formattedException = $this->formatException($exception, $formattedPrevException);
|
||||
|
||||
$message = $this->formatRecordWithExceptionInContext($formatter, $exception);
|
||||
|
||||
$this->assertContextContainsFormattedException($formattedException, $message);
|
||||
}
|
||||
|
||||
public function testDefFormatWithThrowable()
|
||||
{
|
||||
if (!class_exists('Error') || !is_subclass_of('Error', 'Throwable')) {
|
||||
$this->markTestSkipped('Requires PHP >=7');
|
||||
}
|
||||
|
||||
$formatter = new JsonFormatter();
|
||||
$throwable = new \Error('Foo');
|
||||
$formattedThrowable = $this->formatException($throwable);
|
||||
|
||||
$message = $this->formatRecordWithExceptionInContext($formatter, $throwable);
|
||||
|
||||
$this->assertContextContainsFormattedException($formattedThrowable, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $expected
|
||||
* @param string $actual
|
||||
*
|
||||
* @internal param string $exception
|
||||
*/
|
||||
private function assertContextContainsFormattedException($expected, $actual)
|
||||
{
|
||||
$this->assertEquals(
|
||||
'{"level_name":"CRITICAL","channel":"core","context":{"exception":'.$expected.'},"datetime":null,"extra":[],"message":"foobar"}'."\n",
|
||||
$actual
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param JsonFormatter $formatter
|
||||
* @param \Exception|\Throwable $exception
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function formatRecordWithExceptionInContext(JsonFormatter $formatter, $exception)
|
||||
{
|
||||
$message = $formatter->format(array(
|
||||
'level_name' => 'CRITICAL',
|
||||
'channel' => 'core',
|
||||
'context' => array('exception' => $exception),
|
||||
'datetime' => null,
|
||||
'extra' => array(),
|
||||
'message' => 'foobar',
|
||||
));
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Exception|\Throwable $exception
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function formatExceptionFilePathWithLine($exception)
|
||||
{
|
||||
$options = 0;
|
||||
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
$options = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
|
||||
}
|
||||
$path = substr(json_encode($exception->getFile(), $options), 1, -1);
|
||||
return $path . ':' . $exception->getLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Exception|\Throwable $exception
|
||||
*
|
||||
* @param null|string $previous
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function formatException($exception, $previous = null)
|
||||
{
|
||||
$formattedException =
|
||||
'{"class":"' . get_class($exception) .
|
||||
'","message":"' . $exception->getMessage() .
|
||||
'","code":' . $exception->getCode() .
|
||||
',"file":"' . $this->formatExceptionFilePathWithLine($exception) .
|
||||
($previous ? '","previous":' . $previous : '"') .
|
||||
'}';
|
||||
return $formattedException;
|
||||
}
|
||||
|
||||
public function testNormalizeHandleLargeArraysWithExactly1000Items()
|
||||
{
|
||||
$formatter = new NormalizerFormatter();
|
||||
$largeArray = range(1, 1000);
|
||||
|
||||
$res = $formatter->format(array(
|
||||
'level_name' => 'CRITICAL',
|
||||
'channel' => 'test',
|
||||
'message' => 'bar',
|
||||
'context' => array($largeArray),
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array(),
|
||||
));
|
||||
|
||||
$this->assertCount(1000, $res['context'][0]);
|
||||
$this->assertArrayNotHasKey('...', $res['context'][0]);
|
||||
}
|
||||
|
||||
public function testNormalizeHandleLargeArrays()
|
||||
{
|
||||
$formatter = new NormalizerFormatter();
|
||||
$largeArray = range(1, 2000);
|
||||
|
||||
$res = $formatter->format(array(
|
||||
'level_name' => 'CRITICAL',
|
||||
'channel' => 'test',
|
||||
'message' => 'bar',
|
||||
'context' => array($largeArray),
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array(),
|
||||
));
|
||||
|
||||
$this->assertCount(1001, $res['context'][0]);
|
||||
$this->assertEquals('Over 1000 items (2000 total), aborting normalization', $res['context'][0]['...']);
|
||||
}
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\LineFormatter
|
||||
*/
|
||||
class LineFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testDefFormatWithString()
|
||||
{
|
||||
$formatter = new LineFormatter(null, 'Y-m-d');
|
||||
$message = $formatter->format(array(
|
||||
'level_name' => 'WARNING',
|
||||
'channel' => 'log',
|
||||
'context' => array(),
|
||||
'message' => 'foo',
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array(),
|
||||
));
|
||||
$this->assertEquals('['.date('Y-m-d').'] log.WARNING: foo [] []'."\n", $message);
|
||||
}
|
||||
|
||||
public function testDefFormatWithArrayContext()
|
||||
{
|
||||
$formatter = new LineFormatter(null, 'Y-m-d');
|
||||
$message = $formatter->format(array(
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'message' => 'foo',
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array(),
|
||||
'context' => array(
|
||||
'foo' => 'bar',
|
||||
'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);
|
||||
}
|
||||
|
||||
public function testDefFormatExtras()
|
||||
{
|
||||
$formatter = new LineFormatter(null, 'Y-m-d');
|
||||
$message = $formatter->format(array(
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array('ip' => '127.0.0.1'),
|
||||
'message' => 'log',
|
||||
));
|
||||
$this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log [] {"ip":"127.0.0.1"}'."\n", $message);
|
||||
}
|
||||
|
||||
public function testFormatExtras()
|
||||
{
|
||||
$formatter = new LineFormatter("[%datetime%] %channel%.%level_name%: %message% %context% %extra.file% %extra%\n", 'Y-m-d');
|
||||
$message = $formatter->format(array(
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array('ip' => '127.0.0.1', 'file' => 'test'),
|
||||
'message' => 'log',
|
||||
));
|
||||
$this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log [] test {"ip":"127.0.0.1"}'."\n", $message);
|
||||
}
|
||||
|
||||
public function testContextAndExtraOptionallyNotShownIfEmpty()
|
||||
{
|
||||
$formatter = new LineFormatter(null, 'Y-m-d', false, true);
|
||||
$message = $formatter->format(array(
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array(),
|
||||
'message' => 'log',
|
||||
));
|
||||
$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');
|
||||
$message = $formatter->format(array(
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array('foo' => new TestFoo, 'bar' => new TestBar, 'baz' => array(), 'res' => fopen('php://memory', 'rb')),
|
||||
'message' => 'foobar',
|
||||
));
|
||||
|
||||
$this->assertEquals('['.date('Y-m-d').'] meh.ERROR: foobar [] {"foo":"[object] (Monolog\\\\Formatter\\\\TestFoo: {\\"foo\\":\\"foo\\"})","bar":"[object] (Monolog\\\\Formatter\\\\TestBar: bar)","baz":[],"res":"[resource] (stream)"}'."\n", $message);
|
||||
}
|
||||
|
||||
public function testDefFormatWithException()
|
||||
{
|
||||
$formatter = new LineFormatter(null, 'Y-m-d');
|
||||
$message = $formatter->format(array(
|
||||
'level_name' => 'CRITICAL',
|
||||
'channel' => 'core',
|
||||
'context' => array('exception' => new \RuntimeException('Foo')),
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array(),
|
||||
'message' => 'foobar',
|
||||
));
|
||||
|
||||
$path = str_replace('\\/', '/', json_encode(__FILE__));
|
||||
|
||||
$this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (RuntimeException(code: 0): Foo at '.substr($path, 1, -1).':'.(__LINE__ - 8).')"} []'."\n", $message);
|
||||
}
|
||||
|
||||
public function testDefFormatWithPreviousException()
|
||||
{
|
||||
$formatter = new LineFormatter(null, 'Y-m-d');
|
||||
$previous = new \LogicException('Wut?');
|
||||
$message = $formatter->format(array(
|
||||
'level_name' => 'CRITICAL',
|
||||
'channel' => 'core',
|
||||
'context' => array('exception' => new \RuntimeException('Foo', 0, $previous)),
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array(),
|
||||
'message' => 'foobar',
|
||||
));
|
||||
|
||||
$path = str_replace('\\/', '/', json_encode(__FILE__));
|
||||
|
||||
$this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (RuntimeException(code: 0): Foo at '.substr($path, 1, -1).':'.(__LINE__ - 8).', LogicException(code: 0): Wut? at '.substr($path, 1, -1).':'.(__LINE__ - 12).')"} []'."\n", $message);
|
||||
}
|
||||
|
||||
public function testBatchFormat()
|
||||
{
|
||||
$formatter = new LineFormatter(null, 'Y-m-d');
|
||||
$message = $formatter->formatBatch(array(
|
||||
array(
|
||||
'level_name' => 'CRITICAL',
|
||||
'channel' => 'test',
|
||||
'message' => 'bar',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array(),
|
||||
),
|
||||
array(
|
||||
'level_name' => 'WARNING',
|
||||
'channel' => 'log',
|
||||
'message' => 'foo',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array(),
|
||||
),
|
||||
));
|
||||
$this->assertEquals('['.date('Y-m-d').'] test.CRITICAL: bar [] []'."\n".'['.date('Y-m-d').'] log.WARNING: foo [] []'."\n", $message);
|
||||
}
|
||||
|
||||
public function testFormatShouldStripInlineLineBreaks()
|
||||
{
|
||||
$formatter = new LineFormatter(null, 'Y-m-d');
|
||||
$message = $formatter->format(
|
||||
array(
|
||||
'message' => "foo\nbar",
|
||||
'context' => array(),
|
||||
'extra' => array(),
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertRegExp('/foo bar/', $message);
|
||||
}
|
||||
|
||||
public function testFormatShouldNotStripInlineLineBreaksWhenFlagIsSet()
|
||||
{
|
||||
$formatter = new LineFormatter(null, 'Y-m-d', true);
|
||||
$message = $formatter->format(
|
||||
array(
|
||||
'message' => "foo\nbar",
|
||||
'context' => array(),
|
||||
'extra' => array(),
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertRegExp('/foo\nbar/', $message);
|
||||
}
|
||||
}
|
||||
|
||||
class TestFoo
|
||||
{
|
||||
public $foo = 'foo';
|
||||
}
|
||||
|
||||
class TestBar
|
||||
{
|
||||
public function __toString()
|
||||
{
|
||||
return 'bar';
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
<?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\TestCase;
|
||||
|
||||
class LogglyFormatterTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Monolog\Formatter\LogglyFormatter::__construct
|
||||
*/
|
||||
public function testConstruct()
|
||||
{
|
||||
$formatter = new LogglyFormatter();
|
||||
$this->assertEquals(LogglyFormatter::BATCH_MODE_NEWLINES, $formatter->getBatchMode());
|
||||
$formatter = new LogglyFormatter(LogglyFormatter::BATCH_MODE_JSON);
|
||||
$this->assertEquals(LogglyFormatter::BATCH_MODE_JSON, $formatter->getBatchMode());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\LogglyFormatter::format
|
||||
*/
|
||||
public function testFormat()
|
||||
{
|
||||
$formatter = new LogglyFormatter();
|
||||
$record = $this->getRecord();
|
||||
$formatted_decoded = json_decode($formatter->format($record), true);
|
||||
$this->assertArrayHasKey("timestamp", $formatted_decoded);
|
||||
$this->assertEquals(new \DateTime($formatted_decoded["timestamp"]), $record["datetime"]);
|
||||
}
|
||||
}
|
||||
@@ -1,333 +0,0 @@
|
||||
<?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;
|
||||
|
||||
class LogstashFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function tearDown()
|
||||
{
|
||||
\PHPUnit_Framework_Error_Warning::$enabled = true;
|
||||
|
||||
return parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\LogstashFormatter::format
|
||||
*/
|
||||
public function testDefaultFormatter()
|
||||
{
|
||||
$formatter = new LogstashFormatter('test', 'hostname');
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array(),
|
||||
'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('meh', $message['@fields']['channel']);
|
||||
$this->assertContains('meh', $message['@tags']);
|
||||
$this->assertEquals(Logger::ERROR, $message['@fields']['level']);
|
||||
$this->assertEquals('test', $message['@type']);
|
||||
$this->assertEquals('hostname', $message['@source']);
|
||||
|
||||
$formatter = new LogstashFormatter('mysystem');
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
|
||||
$this->assertEquals('mysystem', $message['@type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\LogstashFormatter::format
|
||||
*/
|
||||
public function testFormatWithFileAndLine()
|
||||
{
|
||||
$formatter = new LogstashFormatter('test');
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('file' => 'test', 'line' => 14),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
|
||||
$this->assertEquals('test', $message['@fields']['file']);
|
||||
$this->assertEquals(14, $message['@fields']['line']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\LogstashFormatter::format
|
||||
*/
|
||||
public function testFormatWithContext()
|
||||
{
|
||||
$formatter = new LogstashFormatter('test');
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => 'pair'),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
|
||||
$message_array = $message['@fields'];
|
||||
|
||||
$this->assertArrayHasKey('ctxt_from', $message_array);
|
||||
$this->assertEquals('logger', $message_array['ctxt_from']);
|
||||
|
||||
// Test with extraPrefix
|
||||
$formatter = new LogstashFormatter('test', null, null, 'CTX');
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
|
||||
$message_array = $message['@fields'];
|
||||
|
||||
$this->assertArrayHasKey('CTXfrom', $message_array);
|
||||
$this->assertEquals('logger', $message_array['CTXfrom']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\LogstashFormatter::format
|
||||
*/
|
||||
public function testFormatWithExtra()
|
||||
{
|
||||
$formatter = new LogstashFormatter('test');
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => 'pair'),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
|
||||
$message_array = $message['@fields'];
|
||||
|
||||
$this->assertArrayHasKey('key', $message_array);
|
||||
$this->assertEquals('pair', $message_array['key']);
|
||||
|
||||
// Test with extraPrefix
|
||||
$formatter = new LogstashFormatter('test', null, 'EXT');
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
|
||||
$message_array = $message['@fields'];
|
||||
|
||||
$this->assertArrayHasKey('EXTkey', $message_array);
|
||||
$this->assertEquals('pair', $message_array['EXTkey']);
|
||||
}
|
||||
|
||||
public function testFormatWithApplicationName()
|
||||
{
|
||||
$formatter = new LogstashFormatter('app', 'test');
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => 'pair'),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
|
||||
$this->assertArrayHasKey('@type', $message);
|
||||
$this->assertEquals('app', $message['@type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\LogstashFormatter::format
|
||||
*/
|
||||
public function testDefaultFormatterV1()
|
||||
{
|
||||
$formatter = new LogstashFormatter('test', 'hostname', null, 'ctxt_', LogstashFormatter::V1);
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array(),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
|
||||
$this->assertEquals("1970-01-01T00:00:00.000000+00:00", $message['@timestamp']);
|
||||
$this->assertEquals("1", $message['@version']);
|
||||
$this->assertEquals('log', $message['message']);
|
||||
$this->assertEquals('meh', $message['channel']);
|
||||
$this->assertEquals('ERROR', $message['level']);
|
||||
$this->assertEquals('test', $message['type']);
|
||||
$this->assertEquals('hostname', $message['host']);
|
||||
|
||||
$formatter = new LogstashFormatter('mysystem', null, null, 'ctxt_', LogstashFormatter::V1);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
|
||||
$this->assertEquals('mysystem', $message['type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\LogstashFormatter::format
|
||||
*/
|
||||
public function testFormatWithFileAndLineV1()
|
||||
{
|
||||
$formatter = new LogstashFormatter('test', null, null, 'ctxt_', LogstashFormatter::V1);
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('file' => 'test', 'line' => 14),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
|
||||
$this->assertEquals('test', $message['file']);
|
||||
$this->assertEquals(14, $message['line']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\LogstashFormatter::format
|
||||
*/
|
||||
public function testFormatWithContextV1()
|
||||
{
|
||||
$formatter = new LogstashFormatter('test', null, null, 'ctxt_', LogstashFormatter::V1);
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => 'pair'),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
|
||||
$this->assertArrayHasKey('ctxt_from', $message);
|
||||
$this->assertEquals('logger', $message['ctxt_from']);
|
||||
|
||||
// Test with extraPrefix
|
||||
$formatter = new LogstashFormatter('test', null, null, 'CTX', LogstashFormatter::V1);
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
|
||||
$this->assertArrayHasKey('CTXfrom', $message);
|
||||
$this->assertEquals('logger', $message['CTXfrom']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\LogstashFormatter::format
|
||||
*/
|
||||
public function testFormatWithExtraV1()
|
||||
{
|
||||
$formatter = new LogstashFormatter('test', null, null, 'ctxt_', LogstashFormatter::V1);
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => 'pair'),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
|
||||
$this->assertArrayHasKey('key', $message);
|
||||
$this->assertEquals('pair', $message['key']);
|
||||
|
||||
// Test with extraPrefix
|
||||
$formatter = new LogstashFormatter('test', null, 'EXT', 'ctxt_', LogstashFormatter::V1);
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
|
||||
$this->assertArrayHasKey('EXTkey', $message);
|
||||
$this->assertEquals('pair', $message['EXTkey']);
|
||||
}
|
||||
|
||||
public function testFormatWithApplicationNameV1()
|
||||
{
|
||||
$formatter = new LogstashFormatter('app', 'test', null, 'ctxt_', LogstashFormatter::V1);
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('key' => 'pair'),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = json_decode($formatter->format($record), true);
|
||||
|
||||
$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,262 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @author Florian Plattner <me@florianplattner.de>
|
||||
*/
|
||||
class MongoDBFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
if (!class_exists('MongoDate')) {
|
||||
$this->markTestSkipped('mongo extension not installed');
|
||||
}
|
||||
}
|
||||
|
||||
public function constructArgumentProvider()
|
||||
{
|
||||
return array(
|
||||
array(1, true, 1, true),
|
||||
array(0, false, 0, false),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $traceDepth
|
||||
* @param $traceAsString
|
||||
* @param $expectedTraceDepth
|
||||
* @param $expectedTraceAsString
|
||||
*
|
||||
* @dataProvider constructArgumentProvider
|
||||
*/
|
||||
public function testConstruct($traceDepth, $traceAsString, $expectedTraceDepth, $expectedTraceAsString)
|
||||
{
|
||||
$formatter = new MongoDBFormatter($traceDepth, $traceAsString);
|
||||
|
||||
$reflTrace = new \ReflectionProperty($formatter, 'exceptionTraceAsString');
|
||||
$reflTrace->setAccessible(true);
|
||||
$this->assertEquals($expectedTraceAsString, $reflTrace->getValue($formatter));
|
||||
|
||||
$reflDepth = new\ReflectionProperty($formatter, 'maxNestingLevel');
|
||||
$reflDepth->setAccessible(true);
|
||||
$this->assertEquals($expectedTraceDepth, $reflDepth->getValue($formatter));
|
||||
}
|
||||
|
||||
public function testSimpleFormat()
|
||||
{
|
||||
$record = array(
|
||||
'message' => 'some log message',
|
||||
'context' => array(),
|
||||
'level' => Logger::WARNING,
|
||||
'level_name' => Logger::getLevelName(Logger::WARNING),
|
||||
'channel' => 'test',
|
||||
'datetime' => new \DateTime('2014-02-01 00:00:00'),
|
||||
'extra' => array(),
|
||||
);
|
||||
|
||||
$formatter = new MongoDBFormatter();
|
||||
$formattedRecord = $formatter->format($record);
|
||||
|
||||
$this->assertCount(7, $formattedRecord);
|
||||
$this->assertEquals('some log message', $formattedRecord['message']);
|
||||
$this->assertEquals(array(), $formattedRecord['context']);
|
||||
$this->assertEquals(Logger::WARNING, $formattedRecord['level']);
|
||||
$this->assertEquals(Logger::getLevelName(Logger::WARNING), $formattedRecord['level_name']);
|
||||
$this->assertEquals('test', $formattedRecord['channel']);
|
||||
$this->assertInstanceOf('\MongoDate', $formattedRecord['datetime']);
|
||||
$this->assertEquals('0.00000000 1391212800', $formattedRecord['datetime']->__toString());
|
||||
$this->assertEquals(array(), $formattedRecord['extra']);
|
||||
}
|
||||
|
||||
public function testRecursiveFormat()
|
||||
{
|
||||
$someObject = new \stdClass();
|
||||
$someObject->foo = 'something';
|
||||
$someObject->bar = 'stuff';
|
||||
|
||||
$record = array(
|
||||
'message' => 'some log message',
|
||||
'context' => array(
|
||||
'stuff' => new \DateTime('2014-02-01 02:31:33'),
|
||||
'some_object' => $someObject,
|
||||
'context_string' => 'some string',
|
||||
'context_int' => 123456,
|
||||
'except' => new \Exception('exception message', 987),
|
||||
),
|
||||
'level' => Logger::WARNING,
|
||||
'level_name' => Logger::getLevelName(Logger::WARNING),
|
||||
'channel' => 'test',
|
||||
'datetime' => new \DateTime('2014-02-01 00:00:00'),
|
||||
'extra' => array(),
|
||||
);
|
||||
|
||||
$formatter = new MongoDBFormatter();
|
||||
$formattedRecord = $formatter->format($record);
|
||||
|
||||
$this->assertCount(5, $formattedRecord['context']);
|
||||
$this->assertInstanceOf('\MongoDate', $formattedRecord['context']['stuff']);
|
||||
$this->assertEquals('0.00000000 1391221893', $formattedRecord['context']['stuff']->__toString());
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'foo' => 'something',
|
||||
'bar' => 'stuff',
|
||||
'class' => 'stdClass',
|
||||
),
|
||||
$formattedRecord['context']['some_object']
|
||||
);
|
||||
$this->assertEquals('some string', $formattedRecord['context']['context_string']);
|
||||
$this->assertEquals(123456, $formattedRecord['context']['context_int']);
|
||||
|
||||
$this->assertCount(5, $formattedRecord['context']['except']);
|
||||
$this->assertEquals('exception message', $formattedRecord['context']['except']['message']);
|
||||
$this->assertEquals(987, $formattedRecord['context']['except']['code']);
|
||||
$this->assertInternalType('string', $formattedRecord['context']['except']['file']);
|
||||
$this->assertInternalType('integer', $formattedRecord['context']['except']['code']);
|
||||
$this->assertInternalType('string', $formattedRecord['context']['except']['trace']);
|
||||
$this->assertEquals('Exception', $formattedRecord['context']['except']['class']);
|
||||
}
|
||||
|
||||
public function testFormatDepthArray()
|
||||
{
|
||||
$record = array(
|
||||
'message' => 'some log message',
|
||||
'context' => array(
|
||||
'nest2' => array(
|
||||
'property' => 'anything',
|
||||
'nest3' => array(
|
||||
'nest4' => 'value',
|
||||
'property' => 'nothing',
|
||||
),
|
||||
),
|
||||
),
|
||||
'level' => Logger::WARNING,
|
||||
'level_name' => Logger::getLevelName(Logger::WARNING),
|
||||
'channel' => 'test',
|
||||
'datetime' => new \DateTime('2014-02-01 00:00:00'),
|
||||
'extra' => array(),
|
||||
);
|
||||
|
||||
$formatter = new MongoDBFormatter(2);
|
||||
$formattedResult = $formatter->format($record);
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'nest2' => array(
|
||||
'property' => 'anything',
|
||||
'nest3' => '[...]',
|
||||
),
|
||||
),
|
||||
$formattedResult['context']
|
||||
);
|
||||
}
|
||||
|
||||
public function testFormatDepthArrayInfiniteNesting()
|
||||
{
|
||||
$record = array(
|
||||
'message' => 'some log message',
|
||||
'context' => array(
|
||||
'nest2' => array(
|
||||
'property' => 'something',
|
||||
'nest3' => array(
|
||||
'property' => 'anything',
|
||||
'nest4' => array(
|
||||
'property' => 'nothing',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
'level' => Logger::WARNING,
|
||||
'level_name' => Logger::getLevelName(Logger::WARNING),
|
||||
'channel' => 'test',
|
||||
'datetime' => new \DateTime('2014-02-01 00:00:00'),
|
||||
'extra' => array(),
|
||||
);
|
||||
|
||||
$formatter = new MongoDBFormatter(0);
|
||||
$formattedResult = $formatter->format($record);
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'nest2' => array(
|
||||
'property' => 'something',
|
||||
'nest3' => array(
|
||||
'property' => 'anything',
|
||||
'nest4' => array(
|
||||
'property' => 'nothing',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
$formattedResult['context']
|
||||
);
|
||||
}
|
||||
|
||||
public function testFormatDepthObjects()
|
||||
{
|
||||
$someObject = new \stdClass();
|
||||
$someObject->property = 'anything';
|
||||
$someObject->nest3 = new \stdClass();
|
||||
$someObject->nest3->property = 'nothing';
|
||||
$someObject->nest3->nest4 = 'invisible';
|
||||
|
||||
$record = array(
|
||||
'message' => 'some log message',
|
||||
'context' => array(
|
||||
'nest2' => $someObject,
|
||||
),
|
||||
'level' => Logger::WARNING,
|
||||
'level_name' => Logger::getLevelName(Logger::WARNING),
|
||||
'channel' => 'test',
|
||||
'datetime' => new \DateTime('2014-02-01 00:00:00'),
|
||||
'extra' => array(),
|
||||
);
|
||||
|
||||
$formatter = new MongoDBFormatter(2, true);
|
||||
$formattedResult = $formatter->format($record);
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'nest2' => array(
|
||||
'property' => 'anything',
|
||||
'nest3' => '[...]',
|
||||
'class' => 'stdClass',
|
||||
),
|
||||
),
|
||||
$formattedResult['context']
|
||||
);
|
||||
}
|
||||
|
||||
public function testFormatDepthException()
|
||||
{
|
||||
$record = array(
|
||||
'message' => 'some log message',
|
||||
'context' => array(
|
||||
'nest2' => new \Exception('exception message', 987),
|
||||
),
|
||||
'level' => Logger::WARNING,
|
||||
'level_name' => Logger::getLevelName(Logger::WARNING),
|
||||
'channel' => 'test',
|
||||
'datetime' => new \DateTime('2014-02-01 00:00:00'),
|
||||
'extra' => array(),
|
||||
);
|
||||
|
||||
$formatter = new MongoDBFormatter(2, false);
|
||||
$formattedRecord = $formatter->format($record);
|
||||
|
||||
$this->assertEquals('exception message', $formattedRecord['context']['nest2']['message']);
|
||||
$this->assertEquals(987, $formattedRecord['context']['nest2']['code']);
|
||||
$this->assertEquals('[...]', $formattedRecord['context']['nest2']['trace']);
|
||||
}
|
||||
}
|
||||
@@ -1,481 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\NormalizerFormatter
|
||||
*/
|
||||
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');
|
||||
$formatted = $formatter->format(array(
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'message' => 'foo',
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array('foo' => new TestFooNorm, 'bar' => new TestBarNorm, 'baz' => array(), 'res' => fopen('php://memory', 'rb')),
|
||||
'context' => array(
|
||||
'foo' => 'bar',
|
||||
'baz' => 'qux',
|
||||
'inf' => INF,
|
||||
'-inf' => -INF,
|
||||
'nan' => acos(4),
|
||||
),
|
||||
));
|
||||
|
||||
$this->assertEquals(array(
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'message' => 'foo',
|
||||
'datetime' => date('Y-m-d'),
|
||||
'extra' => array(
|
||||
'foo' => '[object] (Monolog\\Formatter\\TestFooNorm: {"foo":"foo"})',
|
||||
'bar' => '[object] (Monolog\\Formatter\\TestBarNorm: bar)',
|
||||
'baz' => array(),
|
||||
'res' => '[resource] (stream)',
|
||||
),
|
||||
'context' => array(
|
||||
'foo' => 'bar',
|
||||
'baz' => 'qux',
|
||||
'inf' => 'INF',
|
||||
'-inf' => '-INF',
|
||||
'nan' => 'NaN',
|
||||
),
|
||||
), $formatted);
|
||||
}
|
||||
|
||||
public function testFormatExceptions()
|
||||
{
|
||||
$formatter = new NormalizerFormatter('Y-m-d');
|
||||
$e = new \LogicException('bar');
|
||||
$e2 = new \RuntimeException('foo', 0, $e);
|
||||
$formatted = $formatter->format(array(
|
||||
'exception' => $e2,
|
||||
));
|
||||
|
||||
$this->assertGreaterThan(5, count($formatted['exception']['trace']));
|
||||
$this->assertTrue(isset($formatted['exception']['previous']));
|
||||
unset($formatted['exception']['trace'], $formatted['exception']['previous']);
|
||||
|
||||
$this->assertEquals(array(
|
||||
'exception' => array(
|
||||
'class' => get_class($e2),
|
||||
'message' => $e2->getMessage(),
|
||||
'code' => $e2->getCode(),
|
||||
'file' => $e2->getFile().':'.$e2->getLine(),
|
||||
),
|
||||
), $formatted);
|
||||
}
|
||||
|
||||
public function testFormatSoapFaultException()
|
||||
{
|
||||
if (!class_exists('SoapFault')) {
|
||||
$this->markTestSkipped('Requires the soap extension');
|
||||
}
|
||||
|
||||
$formatter = new NormalizerFormatter('Y-m-d');
|
||||
$e = new \SoapFault('foo', 'bar', 'hello', 'world');
|
||||
$formatted = $formatter->format(array(
|
||||
'exception' => $e,
|
||||
));
|
||||
|
||||
unset($formatted['exception']['trace']);
|
||||
|
||||
$this->assertEquals(array(
|
||||
'exception' => array(
|
||||
'class' => 'SoapFault',
|
||||
'message' => 'bar',
|
||||
'code' => 0,
|
||||
'file' => $e->getFile().':'.$e->getLine(),
|
||||
'faultcode' => 'foo',
|
||||
'faultactor' => 'hello',
|
||||
'detail' => 'world',
|
||||
),
|
||||
), $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');
|
||||
$formatted = $formatter->formatBatch(array(
|
||||
array(
|
||||
'level_name' => 'CRITICAL',
|
||||
'channel' => 'test',
|
||||
'message' => 'bar',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array(),
|
||||
),
|
||||
array(
|
||||
'level_name' => 'WARNING',
|
||||
'channel' => 'log',
|
||||
'message' => 'foo',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array(),
|
||||
),
|
||||
));
|
||||
$this->assertEquals(array(
|
||||
array(
|
||||
'level_name' => 'CRITICAL',
|
||||
'channel' => 'test',
|
||||
'message' => 'bar',
|
||||
'context' => array(),
|
||||
'datetime' => date('Y-m-d'),
|
||||
'extra' => array(),
|
||||
),
|
||||
array(
|
||||
'level_name' => 'WARNING',
|
||||
'channel' => 'log',
|
||||
'message' => 'foo',
|
||||
'context' => array(),
|
||||
'datetime' => date('Y-m-d'),
|
||||
'extra' => array(),
|
||||
),
|
||||
), $formatted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test issue #137
|
||||
*/
|
||||
public function testIgnoresRecursiveObjectReferences()
|
||||
{
|
||||
// set up the recursion
|
||||
$foo = new \stdClass();
|
||||
$bar = new \stdClass();
|
||||
|
||||
$foo->bar = $bar;
|
||||
$bar->foo = $foo;
|
||||
|
||||
// set an error handler to assert that the error is not raised anymore
|
||||
$that = $this;
|
||||
set_error_handler(function ($level, $message, $file, $line, $context) use ($that) {
|
||||
if (error_reporting() & $level) {
|
||||
restore_error_handler();
|
||||
$that->fail("$message should not be raised");
|
||||
}
|
||||
});
|
||||
|
||||
$formatter = new NormalizerFormatter();
|
||||
$reflMethod = new \ReflectionMethod($formatter, 'toJson');
|
||||
$reflMethod->setAccessible(true);
|
||||
$res = $reflMethod->invoke($formatter, array($foo, $bar), true);
|
||||
|
||||
restore_error_handler();
|
||||
|
||||
$this->assertEquals(@json_encode(array($foo, $bar)), $res);
|
||||
}
|
||||
|
||||
public function testCanNormalizeReferences()
|
||||
{
|
||||
$formatter = new NormalizerFormatter();
|
||||
$x = array('foo' => 'bar');
|
||||
$y = array('x' => &$x);
|
||||
$x['y'] = &$y;
|
||||
$formatter->format($y);
|
||||
}
|
||||
|
||||
public function testIgnoresInvalidTypes()
|
||||
{
|
||||
// set up the recursion
|
||||
$resource = fopen(__FILE__, 'r');
|
||||
|
||||
// set an error handler to assert that the error is not raised anymore
|
||||
$that = $this;
|
||||
set_error_handler(function ($level, $message, $file, $line, $context) use ($that) {
|
||||
if (error_reporting() & $level) {
|
||||
restore_error_handler();
|
||||
$that->fail("$message should not be raised");
|
||||
}
|
||||
});
|
||||
|
||||
$formatter = new NormalizerFormatter();
|
||||
$reflMethod = new \ReflectionMethod($formatter, 'toJson');
|
||||
$reflMethod->setAccessible(true);
|
||||
$res = $reflMethod->invoke($formatter, array($resource), true);
|
||||
|
||||
restore_error_handler();
|
||||
|
||||
$this->assertEquals(@json_encode(array($resource)), $res);
|
||||
}
|
||||
|
||||
public function testNormalizeHandleLargeArraysWithExactly1000Items()
|
||||
{
|
||||
$formatter = new NormalizerFormatter();
|
||||
$largeArray = range(1, 1000);
|
||||
|
||||
$res = $formatter->format(array(
|
||||
'level_name' => 'CRITICAL',
|
||||
'channel' => 'test',
|
||||
'message' => 'bar',
|
||||
'context' => array($largeArray),
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array(),
|
||||
));
|
||||
|
||||
$this->assertCount(1000, $res['context'][0]);
|
||||
$this->assertArrayNotHasKey('...', $res['context'][0]);
|
||||
}
|
||||
|
||||
public function testNormalizeHandleLargeArrays()
|
||||
{
|
||||
$formatter = new NormalizerFormatter();
|
||||
$largeArray = range(1, 2000);
|
||||
|
||||
$res = $formatter->format(array(
|
||||
'level_name' => 'CRITICAL',
|
||||
'channel' => 'test',
|
||||
'message' => 'bar',
|
||||
'context' => array($largeArray),
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array(),
|
||||
));
|
||||
|
||||
$this->assertCount(1001, $res['context'][0]);
|
||||
$this->assertEquals('Over 1000 items (2000 total), aborting normalization', $res['context'][0]['...']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException RuntimeException
|
||||
*/
|
||||
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 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')) {
|
||||
$this->markTestSkipped('Not supported in HHVM since it detects errors differently');
|
||||
}
|
||||
|
||||
// This happens i.e. in React promises or Guzzle streams where stream wrappers are registered
|
||||
// and no file or line are included in the trace because it's treated as internal function
|
||||
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
|
||||
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
|
||||
});
|
||||
|
||||
try {
|
||||
// This will contain $resource and $wrappedResource as arguments in the trace item
|
||||
$resource = fopen('php://memory', 'rw+');
|
||||
fwrite($resource, 'test_resource');
|
||||
$wrappedResource = new TestFooNorm;
|
||||
$wrappedResource->foo = $resource;
|
||||
// Just do something stupid with a resource/wrapped resource as argument
|
||||
array_keys($wrappedResource);
|
||||
} catch (\Exception $e) {
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
$formatter = new NormalizerFormatter();
|
||||
$record = array('context' => array('exception' => $e));
|
||||
$result = $formatter->format($record);
|
||||
|
||||
$this->assertRegExp(
|
||||
'%"resource":"\[resource\] \(stream\)"%',
|
||||
$result['context']['exception']['trace'][0]
|
||||
);
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
|
||||
$pattern = '%"wrappedResource":"\[object\] \(Monolog\\\\\\\\Formatter\\\\\\\\TestFooNorm: \)"%';
|
||||
} else {
|
||||
$pattern = '%\\\\"foo\\\\":null%';
|
||||
}
|
||||
|
||||
// Tests that the wrapped resource is ignored while encoding, only works for PHP <= 5.4
|
||||
$this->assertRegExp(
|
||||
$pattern,
|
||||
$result['context']['exception']['trace'][0]
|
||||
);
|
||||
}
|
||||
|
||||
public function testExceptionTraceDoesNotLeakCallUserFuncArgs()
|
||||
{
|
||||
try {
|
||||
$arg = new TestInfoLeak;
|
||||
call_user_func(array($this, 'throwHelper'), $arg, $dt = new \DateTime());
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
$formatter = new NormalizerFormatter();
|
||||
$record = array('context' => array('exception' => $e));
|
||||
$result = $formatter->format($record);
|
||||
|
||||
$this->assertSame(
|
||||
'{"function":"throwHelper","class":"Monolog\\\\Formatter\\\\NormalizerFormatterTest","type":"->","args":["[object] (Monolog\\\\Formatter\\\\TestInfoLeak)","'.$dt->format('Y-m-d H:i:s').'"]}',
|
||||
$result['context']['exception']['trace'][0]
|
||||
);
|
||||
}
|
||||
|
||||
private function throwHelper($arg)
|
||||
{
|
||||
throw new \RuntimeException('Thrown');
|
||||
}
|
||||
}
|
||||
|
||||
class TestFooNorm
|
||||
{
|
||||
public $foo = 'foo';
|
||||
}
|
||||
|
||||
class TestBarNorm
|
||||
{
|
||||
public function __toString()
|
||||
{
|
||||
return 'bar';
|
||||
}
|
||||
}
|
||||
|
||||
class TestStreamFoo
|
||||
{
|
||||
public $foo;
|
||||
public $resource;
|
||||
|
||||
public function __construct($resource)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
$this->foo = 'BAR';
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
fseek($this->resource, 0);
|
||||
|
||||
return $this->foo . ' - ' . (string) stream_get_contents($this->resource);
|
||||
}
|
||||
}
|
||||
|
||||
class TestToStringError
|
||||
{
|
||||
public function __toString()
|
||||
{
|
||||
throw new \RuntimeException('Could not convert to string');
|
||||
}
|
||||
}
|
||||
|
||||
class TestInfoLeak
|
||||
{
|
||||
public function __toString()
|
||||
{
|
||||
return 'Sensitive information';
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
<?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
|
||||
{
|
||||
private $formatter;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->formatter = new ScalarFormatter();
|
||||
}
|
||||
|
||||
public function buildTrace(\Exception $e)
|
||||
{
|
||||
$data = array();
|
||||
$trace = $e->getTrace();
|
||||
foreach ($trace as $frame) {
|
||||
if (isset($frame['file'])) {
|
||||
$data[] = $frame['file'].':'.$frame['line'];
|
||||
} else {
|
||||
$data[] = json_encode($frame);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function encodeJson($data)
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
return json_encode($data);
|
||||
}
|
||||
|
||||
public function testFormat()
|
||||
{
|
||||
$exception = new \Exception('foo');
|
||||
$formatted = $this->formatter->format(array(
|
||||
'foo' => 'string',
|
||||
'bar' => 1,
|
||||
'baz' => false,
|
||||
'bam' => array(1, 2, 3),
|
||||
'bat' => array('foo' => 'bar'),
|
||||
'bap' => \DateTime::createFromFormat(\DateTime::ISO8601, '1970-01-01T00:00:00+0000'),
|
||||
'ban' => $exception,
|
||||
));
|
||||
|
||||
$this->assertSame(array(
|
||||
'foo' => 'string',
|
||||
'bar' => 1,
|
||||
'baz' => false,
|
||||
'bam' => $this->encodeJson(array(1, 2, 3)),
|
||||
'bat' => $this->encodeJson(array('foo' => 'bar')),
|
||||
'bap' => '1970-01-01 00:00:00',
|
||||
'ban' => $this->encodeJson(array(
|
||||
'class' => get_class($exception),
|
||||
'message' => $exception->getMessage(),
|
||||
'code' => $exception->getCode(),
|
||||
'file' => $exception->getFile() . ':' . $exception->getLine(),
|
||||
'trace' => $this->buildTrace($exception),
|
||||
)),
|
||||
), $formatted);
|
||||
}
|
||||
|
||||
public function testFormatWithErrorContext()
|
||||
{
|
||||
$context = array('file' => 'foo', 'line' => 1);
|
||||
$formatted = $this->formatter->format(array(
|
||||
'context' => $context,
|
||||
));
|
||||
|
||||
$this->assertSame(array(
|
||||
'context' => $this->encodeJson($context),
|
||||
), $formatted);
|
||||
}
|
||||
|
||||
public function testFormatWithExceptionContext()
|
||||
{
|
||||
$exception = new \Exception('foo');
|
||||
$formatted = $this->formatter->format(array(
|
||||
'context' => array(
|
||||
'exception' => $exception,
|
||||
),
|
||||
));
|
||||
|
||||
$this->assertSame(array(
|
||||
'context' => $this->encodeJson(array(
|
||||
'exception' => array(
|
||||
'class' => get_class($exception),
|
||||
'message' => $exception->getMessage(),
|
||||
'code' => $exception->getCode(),
|
||||
'file' => $exception->getFile() . ':' . $exception->getLine(),
|
||||
'trace' => $this->buildTrace($exception),
|
||||
),
|
||||
)),
|
||||
), $formatted);
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
<?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;
|
||||
|
||||
class WildfireFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Monolog\Formatter\WildfireFormatter::format
|
||||
*/
|
||||
public function testDefaultFormat()
|
||||
{
|
||||
$wildfire = new WildfireFormatter();
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('ip' => '127.0.0.1'),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = $wildfire->format($record);
|
||||
|
||||
$this->assertEquals(
|
||||
'125|[{"Type":"ERROR","File":"","Line":"","Label":"meh"},'
|
||||
.'{"message":"log","context":{"from":"logger"},"extra":{"ip":"127.0.0.1"}}]|',
|
||||
$message
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\WildfireFormatter::format
|
||||
*/
|
||||
public function testFormatWithFileAndLine()
|
||||
{
|
||||
$wildfire = new WildfireFormatter();
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('from' => 'logger'),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array('ip' => '127.0.0.1', 'file' => 'test', 'line' => 14),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = $wildfire->format($record);
|
||||
|
||||
$this->assertEquals(
|
||||
'129|[{"Type":"ERROR","File":"test","Line":14,"Label":"meh"},'
|
||||
.'{"message":"log","context":{"from":"logger"},"extra":{"ip":"127.0.0.1"}}]|',
|
||||
$message
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\WildfireFormatter::format
|
||||
*/
|
||||
public function testFormatWithoutContext()
|
||||
{
|
||||
$wildfire = new WildfireFormatter();
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array(),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$message = $wildfire->format($record);
|
||||
|
||||
$this->assertEquals(
|
||||
'58|[{"Type":"ERROR","File":"","Line":"","Label":"meh"},"log"]|',
|
||||
$message
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\WildfireFormatter::formatBatch
|
||||
* @expectedException BadMethodCallException
|
||||
*/
|
||||
public function testBatchFormatThrowException()
|
||||
{
|
||||
$wildfire = new WildfireFormatter();
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array(),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array(),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$wildfire->formatBatch(array($record));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Formatter\WildfireFormatter::format
|
||||
*/
|
||||
public function testTableFormat()
|
||||
{
|
||||
$wildfire = new WildfireFormatter();
|
||||
$record = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'table-channel',
|
||||
'context' => array(
|
||||
WildfireFormatter::TABLE => array(
|
||||
array('col1', 'col2', 'col3'),
|
||||
array('val1', 'val2', 'val3'),
|
||||
array('foo1', 'foo2', 'foo3'),
|
||||
array('bar1', 'bar2', 'bar3'),
|
||||
),
|
||||
),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array(),
|
||||
'message' => 'table-message',
|
||||
);
|
||||
|
||||
$message = $wildfire->format($record);
|
||||
|
||||
$this->assertEquals(
|
||||
'171|[{"Type":"TABLE","File":"","Line":"","Label":"table-channel: table-message"},[["col1","col2","col3"],["val1","val2","val3"],["foo1","foo2","foo3"],["bar1","bar2","bar3"]]]|',
|
||||
$message
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
<?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;
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
use Monolog\Processor\WebProcessor;
|
||||
|
||||
class AbstractHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Monolog\Handler\AbstractHandler::__construct
|
||||
* @covers Monolog\Handler\AbstractHandler::getLevel
|
||||
* @covers Monolog\Handler\AbstractHandler::setLevel
|
||||
* @covers Monolog\Handler\AbstractHandler::getBubble
|
||||
* @covers Monolog\Handler\AbstractHandler::setBubble
|
||||
* @covers Monolog\Handler\AbstractHandler::getFormatter
|
||||
* @covers Monolog\Handler\AbstractHandler::setFormatter
|
||||
*/
|
||||
public function testConstructAndGetSet()
|
||||
{
|
||||
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', array(Logger::WARNING, false));
|
||||
$this->assertEquals(Logger::WARNING, $handler->getLevel());
|
||||
$this->assertEquals(false, $handler->getBubble());
|
||||
|
||||
$handler->setLevel(Logger::ERROR);
|
||||
$handler->setBubble(true);
|
||||
$handler->setFormatter($formatter = new LineFormatter);
|
||||
$this->assertEquals(Logger::ERROR, $handler->getLevel());
|
||||
$this->assertEquals(true, $handler->getBubble());
|
||||
$this->assertSame($formatter, $handler->getFormatter());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\AbstractHandler::handleBatch
|
||||
*/
|
||||
public function testHandleBatch()
|
||||
{
|
||||
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler');
|
||||
$handler->expects($this->exactly(2))
|
||||
->method('handle');
|
||||
$handler->handleBatch(array($this->getRecord(), $this->getRecord()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\AbstractHandler::isHandling
|
||||
*/
|
||||
public function testIsHandling()
|
||||
{
|
||||
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', array(Logger::WARNING, false));
|
||||
$this->assertTrue($handler->isHandling($this->getRecord()));
|
||||
$this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\AbstractHandler::__construct
|
||||
*/
|
||||
public function testHandlesPsrStyleLevels()
|
||||
{
|
||||
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', array('warning', false));
|
||||
$this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG)));
|
||||
$handler->setLevel('debug');
|
||||
$this->assertTrue($handler->isHandling($this->getRecord(Logger::DEBUG)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\AbstractHandler::getFormatter
|
||||
* @covers Monolog\Handler\AbstractHandler::getDefaultFormatter
|
||||
*/
|
||||
public function testGetFormatterInitializesDefault()
|
||||
{
|
||||
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler');
|
||||
$this->assertInstanceOf('Monolog\Formatter\LineFormatter', $handler->getFormatter());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\AbstractHandler::pushProcessor
|
||||
* @covers Monolog\Handler\AbstractHandler::popProcessor
|
||||
* @expectedException LogicException
|
||||
*/
|
||||
public function testPushPopProcessor()
|
||||
{
|
||||
$logger = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler');
|
||||
$processor1 = new WebProcessor;
|
||||
$processor2 = new WebProcessor;
|
||||
|
||||
$logger->pushProcessor($processor1);
|
||||
$logger->pushProcessor($processor2);
|
||||
|
||||
$this->assertEquals($processor2, $logger->popProcessor());
|
||||
$this->assertEquals($processor1, $logger->popProcessor());
|
||||
$logger->popProcessor();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\AbstractHandler::pushProcessor
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testPushProcessorWithNonCallable()
|
||||
{
|
||||
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler');
|
||||
|
||||
$handler->pushProcessor(new \stdClass());
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<?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;
|
||||
use Monolog\Processor\WebProcessor;
|
||||
|
||||
class AbstractProcessingHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Monolog\Handler\AbstractProcessingHandler::handle
|
||||
*/
|
||||
public function testHandleLowerLevelMessage()
|
||||
{
|
||||
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::WARNING, true));
|
||||
$this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\AbstractProcessingHandler::handle
|
||||
*/
|
||||
public function testHandleBubbling()
|
||||
{
|
||||
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::DEBUG, true));
|
||||
$this->assertFalse($handler->handle($this->getRecord()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\AbstractProcessingHandler::handle
|
||||
*/
|
||||
public function testHandleNotBubbling()
|
||||
{
|
||||
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::DEBUG, false));
|
||||
$this->assertTrue($handler->handle($this->getRecord()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\AbstractProcessingHandler::handle
|
||||
*/
|
||||
public function testHandleIsFalseWhenNotHandled()
|
||||
{
|
||||
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::WARNING, false));
|
||||
$this->assertTrue($handler->handle($this->getRecord()));
|
||||
$this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\AbstractProcessingHandler::processRecord
|
||||
*/
|
||||
public function testProcessRecord()
|
||||
{
|
||||
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler');
|
||||
$handler->pushProcessor(new WebProcessor(array(
|
||||
'REQUEST_URI' => '',
|
||||
'REQUEST_METHOD' => '',
|
||||
'REMOTE_ADDR' => '',
|
||||
'SERVER_NAME' => '',
|
||||
'UNIQUE_ID' => '',
|
||||
)));
|
||||
$handledRecord = null;
|
||||
$handler->expects($this->once())
|
||||
->method('write')
|
||||
->will($this->returnCallback(function ($record) use (&$handledRecord) {
|
||||
$handledRecord = $record;
|
||||
}))
|
||||
;
|
||||
$handler->handle($this->getRecord());
|
||||
$this->assertEquals(6, count($handledRecord['extra']));
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
<?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;
|
||||
use PhpAmqpLib\Message\AMQPMessage;
|
||||
use PhpAmqpLib\Connection\AMQPConnection;
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\RotatingFileHandler
|
||||
*/
|
||||
class AmqpHandlerTest extends TestCase
|
||||
{
|
||||
public function testHandleAmqpExt()
|
||||
{
|
||||
if (!class_exists('AMQPConnection') || !class_exists('AMQPExchange')) {
|
||||
$this->markTestSkipped("amqp-php not installed");
|
||||
}
|
||||
|
||||
if (!class_exists('AMQPChannel')) {
|
||||
$this->markTestSkipped("Please update AMQP to version >= 1.0");
|
||||
}
|
||||
|
||||
$messages = array();
|
||||
|
||||
$exchange = $this->getMock('AMQPExchange', array('publish', 'setName'), array(), '', false);
|
||||
$exchange->expects($this->once())
|
||||
->method('setName')
|
||||
->with('log')
|
||||
;
|
||||
$exchange->expects($this->any())
|
||||
->method('publish')
|
||||
->will($this->returnCallback(function ($message, $routing_key, $flags = 0, $attributes = array()) use (&$messages) {
|
||||
$messages[] = array($message, $routing_key, $flags, $attributes);
|
||||
}))
|
||||
;
|
||||
|
||||
$handler = new AmqpHandler($exchange, 'log');
|
||||
|
||||
$record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
|
||||
|
||||
$expected = array(
|
||||
array(
|
||||
'message' => 'test',
|
||||
'context' => array(
|
||||
'data' => array(),
|
||||
'foo' => 34,
|
||||
),
|
||||
'level' => 300,
|
||||
'level_name' => 'WARNING',
|
||||
'channel' => 'test',
|
||||
'extra' => array(),
|
||||
),
|
||||
'warn.test',
|
||||
0,
|
||||
array(
|
||||
'delivery_mode' => 2,
|
||||
'content_type' => 'application/json',
|
||||
),
|
||||
);
|
||||
|
||||
$handler->handle($record);
|
||||
|
||||
$this->assertCount(1, $messages);
|
||||
$messages[0][0] = json_decode($messages[0][0], true);
|
||||
unset($messages[0][0]['datetime']);
|
||||
$this->assertEquals($expected, $messages[0]);
|
||||
}
|
||||
|
||||
public function testHandlePhpAmqpLib()
|
||||
{
|
||||
if (!class_exists('PhpAmqpLib\Connection\AMQPConnection')) {
|
||||
$this->markTestSkipped("php-amqplib not installed");
|
||||
}
|
||||
|
||||
$messages = array();
|
||||
|
||||
$exchange = $this->getMock('PhpAmqpLib\Channel\AMQPChannel', array('basic_publish', '__destruct'), array(), '', false);
|
||||
|
||||
$exchange->expects($this->any())
|
||||
->method('basic_publish')
|
||||
->will($this->returnCallback(function (AMQPMessage $msg, $exchange = "", $routing_key = "", $mandatory = false, $immediate = false, $ticket = null) use (&$messages) {
|
||||
$messages[] = array($msg, $exchange, $routing_key, $mandatory, $immediate, $ticket);
|
||||
}))
|
||||
;
|
||||
|
||||
$handler = new AmqpHandler($exchange, 'log');
|
||||
|
||||
$record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
|
||||
|
||||
$expected = array(
|
||||
array(
|
||||
'message' => 'test',
|
||||
'context' => array(
|
||||
'data' => array(),
|
||||
'foo' => 34,
|
||||
),
|
||||
'level' => 300,
|
||||
'level_name' => 'WARNING',
|
||||
'channel' => 'test',
|
||||
'extra' => array(),
|
||||
),
|
||||
'log',
|
||||
'warn.test',
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
array(
|
||||
'delivery_mode' => 2,
|
||||
'content_type' => 'application/json',
|
||||
),
|
||||
);
|
||||
|
||||
$handler->handle($record);
|
||||
|
||||
$this->assertCount(1, $messages);
|
||||
|
||||
/* @var $msg AMQPMessage */
|
||||
$msg = $messages[0][0];
|
||||
$messages[0][0] = json_decode($msg->body, true);
|
||||
$messages[0][] = $msg->get_properties();
|
||||
unset($messages[0][0]['datetime']);
|
||||
|
||||
$this->assertEquals($expected, $messages[0]);
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\BrowserConsoleHandlerTest
|
||||
*/
|
||||
class BrowserConsoleHandlerTest extends TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
BrowserConsoleHandler::resetStatic();
|
||||
}
|
||||
|
||||
protected function generateScript()
|
||||
{
|
||||
$reflMethod = new \ReflectionMethod('Monolog\Handler\BrowserConsoleHandler', 'generateScript');
|
||||
$reflMethod->setAccessible(true);
|
||||
|
||||
return $reflMethod->invoke(null);
|
||||
}
|
||||
|
||||
public function testStyling()
|
||||
{
|
||||
$handler = new BrowserConsoleHandler();
|
||||
$handler->setFormatter($this->getIdentityFormatter());
|
||||
|
||||
$handler->handle($this->getRecord(Logger::DEBUG, 'foo[[bar]]{color: red}'));
|
||||
|
||||
$expected = <<<EOF
|
||||
(function (c) {if (c && c.groupCollapsed) {
|
||||
c.log("%cfoo%cbar%c", "font-weight: normal", "color: red", "font-weight: normal");
|
||||
}})(console);
|
||||
EOF;
|
||||
|
||||
$this->assertEquals($expected, $this->generateScript());
|
||||
}
|
||||
|
||||
public function testEscaping()
|
||||
{
|
||||
$handler = new BrowserConsoleHandler();
|
||||
$handler->setFormatter($this->getIdentityFormatter());
|
||||
|
||||
$handler->handle($this->getRecord(Logger::DEBUG, "[foo] [[\"bar\n[baz]\"]]{color: red}"));
|
||||
|
||||
$expected = <<<EOF
|
||||
(function (c) {if (c && c.groupCollapsed) {
|
||||
c.log("%c[foo] %c\"bar\\n[baz]\"%c", "font-weight: normal", "color: red", "font-weight: normal");
|
||||
}})(console);
|
||||
EOF;
|
||||
|
||||
$this->assertEquals($expected, $this->generateScript());
|
||||
}
|
||||
|
||||
public function testAutolabel()
|
||||
{
|
||||
$handler = new BrowserConsoleHandler();
|
||||
$handler->setFormatter($this->getIdentityFormatter());
|
||||
|
||||
$handler->handle($this->getRecord(Logger::DEBUG, '[[foo]]{macro: autolabel}'));
|
||||
$handler->handle($this->getRecord(Logger::DEBUG, '[[bar]]{macro: autolabel}'));
|
||||
$handler->handle($this->getRecord(Logger::DEBUG, '[[foo]]{macro: autolabel}'));
|
||||
|
||||
$expected = <<<EOF
|
||||
(function (c) {if (c && c.groupCollapsed) {
|
||||
c.log("%c%cfoo%c", "font-weight: normal", "background-color: blue; color: white; border-radius: 3px; padding: 0 2px 0 2px", "font-weight: normal");
|
||||
c.log("%c%cbar%c", "font-weight: normal", "background-color: green; color: white; border-radius: 3px; padding: 0 2px 0 2px", "font-weight: normal");
|
||||
c.log("%c%cfoo%c", "font-weight: normal", "background-color: blue; color: white; border-radius: 3px; padding: 0 2px 0 2px", "font-weight: normal");
|
||||
}})(console);
|
||||
EOF;
|
||||
|
||||
$this->assertEquals($expected, $this->generateScript());
|
||||
}
|
||||
|
||||
public function testContext()
|
||||
{
|
||||
$handler = new BrowserConsoleHandler();
|
||||
$handler->setFormatter($this->getIdentityFormatter());
|
||||
|
||||
$handler->handle($this->getRecord(Logger::DEBUG, 'test', array('foo' => 'bar')));
|
||||
|
||||
$expected = <<<EOF
|
||||
(function (c) {if (c && c.groupCollapsed) {
|
||||
c.groupCollapsed("%ctest", "font-weight: normal");
|
||||
c.log("%c%s", "font-weight: bold", "Context");
|
||||
c.log("%s: %o", "foo", "bar");
|
||||
c.groupEnd();
|
||||
}})(console);
|
||||
EOF;
|
||||
|
||||
$this->assertEquals($expected, $this->generateScript());
|
||||
}
|
||||
|
||||
public function testConcurrentHandlers()
|
||||
{
|
||||
$handler1 = new BrowserConsoleHandler();
|
||||
$handler1->setFormatter($this->getIdentityFormatter());
|
||||
|
||||
$handler2 = new BrowserConsoleHandler();
|
||||
$handler2->setFormatter($this->getIdentityFormatter());
|
||||
|
||||
$handler1->handle($this->getRecord(Logger::DEBUG, 'test1'));
|
||||
$handler2->handle($this->getRecord(Logger::DEBUG, 'test2'));
|
||||
$handler1->handle($this->getRecord(Logger::DEBUG, 'test3'));
|
||||
$handler2->handle($this->getRecord(Logger::DEBUG, 'test4'));
|
||||
|
||||
$expected = <<<EOF
|
||||
(function (c) {if (c && c.groupCollapsed) {
|
||||
c.log("%ctest1", "font-weight: normal");
|
||||
c.log("%ctest2", "font-weight: normal");
|
||||
c.log("%ctest3", "font-weight: normal");
|
||||
c.log("%ctest4", "font-weight: normal");
|
||||
}})(console);
|
||||
EOF;
|
||||
|
||||
$this->assertEquals($expected, $this->generateScript());
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
<?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 BufferHandlerTest extends TestCase
|
||||
{
|
||||
private $shutdownCheckHandler;
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\BufferHandler::__construct
|
||||
* @covers Monolog\Handler\BufferHandler::handle
|
||||
* @covers Monolog\Handler\BufferHandler::close
|
||||
*/
|
||||
public function testHandleBuffers()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new BufferHandler($test);
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
$this->assertFalse($test->hasDebugRecords());
|
||||
$this->assertFalse($test->hasInfoRecords());
|
||||
$handler->close();
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
$this->assertTrue(count($test->getRecords()) === 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\BufferHandler::close
|
||||
* @covers Monolog\Handler\BufferHandler::flush
|
||||
*/
|
||||
public function testPropagatesRecordsAtEndOfRequest()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new BufferHandler($test);
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$this->shutdownCheckHandler = $test;
|
||||
register_shutdown_function(array($this, 'checkPropagation'));
|
||||
}
|
||||
|
||||
public function checkPropagation()
|
||||
{
|
||||
if (!$this->shutdownCheckHandler->hasWarningRecords() || !$this->shutdownCheckHandler->hasDebugRecords()) {
|
||||
echo '!!! BufferHandlerTest::testPropagatesRecordsAtEndOfRequest failed to verify that the messages have been propagated' . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\BufferHandler::handle
|
||||
*/
|
||||
public function testHandleBufferLimit()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new BufferHandler($test, 2);
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$handler->close();
|
||||
$this->assertTrue($test->hasWarningRecords());
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
$this->assertFalse($test->hasDebugRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\BufferHandler::handle
|
||||
*/
|
||||
public function testHandleBufferLimitWithFlushOnOverflow()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new BufferHandler($test, 3, Logger::DEBUG, true, true);
|
||||
|
||||
// send two records
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$this->assertFalse($test->hasDebugRecords());
|
||||
$this->assertCount(0, $test->getRecords());
|
||||
|
||||
// overflow
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
$this->assertTrue($test->hasDebugRecords());
|
||||
$this->assertCount(3, $test->getRecords());
|
||||
|
||||
// should buffer again
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$this->assertCount(3, $test->getRecords());
|
||||
|
||||
$handler->close();
|
||||
$this->assertCount(5, $test->getRecords());
|
||||
$this->assertTrue($test->hasWarningRecords());
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\BufferHandler::handle
|
||||
*/
|
||||
public function testHandleLevel()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new BufferHandler($test, 0, Logger::INFO);
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->close();
|
||||
$this->assertTrue($test->hasWarningRecords());
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
$this->assertFalse($test->hasDebugRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\BufferHandler::flush
|
||||
*/
|
||||
public function testFlush()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new BufferHandler($test, 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\BufferHandler::handle
|
||||
*/
|
||||
public function testHandleUsesProcessors()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new BufferHandler($test);
|
||||
$handler->pushProcessor(function ($record) {
|
||||
$record['extra']['foo'] = true;
|
||||
|
||||
return $record;
|
||||
});
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$handler->flush();
|
||||
$this->assertTrue($test->hasWarningRecords());
|
||||
$records = $test->getRecords();
|
||||
$this->assertTrue($records[0]['extra']['foo']);
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\ChromePHPHandler
|
||||
*/
|
||||
class ChromePHPHandlerTest extends TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
TestChromePHPHandler::resetStatic();
|
||||
$_SERVER['HTTP_USER_AGENT'] = 'Monolog Test; Chrome/1.0';
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider agentsProvider
|
||||
*/
|
||||
public function testHeaders($agent)
|
||||
{
|
||||
$_SERVER['HTTP_USER_AGENT'] = $agent;
|
||||
|
||||
$handler = new TestChromePHPHandler();
|
||||
$handler->setFormatter($this->getIdentityFormatter());
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
|
||||
$expected = array(
|
||||
'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode(array(
|
||||
'version' => ChromePHPHandler::VERSION,
|
||||
'columns' => array('label', 'log', 'backtrace', 'type'),
|
||||
'rows' => array(
|
||||
'test',
|
||||
'test',
|
||||
),
|
||||
'request_uri' => '',
|
||||
)))),
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $handler->getHeaders());
|
||||
}
|
||||
|
||||
public static function agentsProvider()
|
||||
{
|
||||
return array(
|
||||
array('Monolog Test; Chrome/1.0'),
|
||||
array('Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0'),
|
||||
array('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/56.0.2924.76 Chrome/56.0.2924.76 Safari/537.36'),
|
||||
array('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome Safari/537.36'),
|
||||
);
|
||||
}
|
||||
|
||||
public function testHeadersOverflow()
|
||||
{
|
||||
$handler = new TestChromePHPHandler();
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::WARNING, str_repeat('a', 150 * 1024)));
|
||||
|
||||
// overflow chrome headers limit
|
||||
$handler->handle($this->getRecord(Logger::WARNING, str_repeat('a', 100 * 1024)));
|
||||
|
||||
$expected = array(
|
||||
'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode(array(
|
||||
'version' => ChromePHPHandler::VERSION,
|
||||
'columns' => array('label', 'log', 'backtrace', 'type'),
|
||||
'rows' => array(
|
||||
array(
|
||||
'test',
|
||||
'test',
|
||||
'unknown',
|
||||
'log',
|
||||
),
|
||||
array(
|
||||
'test',
|
||||
str_repeat('a', 150 * 1024),
|
||||
'unknown',
|
||||
'warn',
|
||||
),
|
||||
array(
|
||||
'monolog',
|
||||
'Incomplete logs, chrome header size limit reached',
|
||||
'unknown',
|
||||
'warn',
|
||||
),
|
||||
),
|
||||
'request_uri' => '',
|
||||
)))),
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $handler->getHeaders());
|
||||
}
|
||||
|
||||
public function testConcurrentHandlers()
|
||||
{
|
||||
$handler = new TestChromePHPHandler();
|
||||
$handler->setFormatter($this->getIdentityFormatter());
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
|
||||
$handler2 = new TestChromePHPHandler();
|
||||
$handler2->setFormatter($this->getIdentityFormatter());
|
||||
$handler2->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler2->handle($this->getRecord(Logger::WARNING));
|
||||
|
||||
$expected = array(
|
||||
'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode(array(
|
||||
'version' => ChromePHPHandler::VERSION,
|
||||
'columns' => array('label', 'log', 'backtrace', 'type'),
|
||||
'rows' => array(
|
||||
'test',
|
||||
'test',
|
||||
'test',
|
||||
'test',
|
||||
),
|
||||
'request_uri' => '',
|
||||
)))),
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $handler2->getHeaders());
|
||||
}
|
||||
}
|
||||
|
||||
class TestChromePHPHandler extends ChromePHPHandler
|
||||
{
|
||||
protected $headers = array();
|
||||
|
||||
public static function resetStatic()
|
||||
{
|
||||
self::$initialized = false;
|
||||
self::$overflowed = false;
|
||||
self::$sendHeaders = true;
|
||||
self::$json['rows'] = array();
|
||||
}
|
||||
|
||||
protected function sendHeader($header, $content)
|
||||
{
|
||||
$this->headers[$header] = $content;
|
||||
}
|
||||
|
||||
public function getHeaders()
|
||||
{
|
||||
return $this->headers;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?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 CouchDBHandlerTest extends TestCase
|
||||
{
|
||||
public function testHandle()
|
||||
{
|
||||
$record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
|
||||
|
||||
$handler = new CouchDBHandler();
|
||||
|
||||
try {
|
||||
$handler->handle($record);
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->markTestSkipped('Could not connect to couchdb server on http://localhost:5984');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
<?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 DoctrineCouchDBHandlerTest extends TestCase
|
||||
{
|
||||
protected function setup()
|
||||
{
|
||||
if (!class_exists('Doctrine\CouchDB\CouchDBClient')) {
|
||||
$this->markTestSkipped('The "doctrine/couchdb" package is not installed');
|
||||
}
|
||||
}
|
||||
|
||||
public function testHandle()
|
||||
{
|
||||
$client = $this->getMockBuilder('Doctrine\\CouchDB\\CouchDBClient')
|
||||
->setMethods(array('postDocument'))
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
|
||||
|
||||
$expected = array(
|
||||
'message' => 'test',
|
||||
'context' => array('data' => '[object] (stdClass: {})', 'foo' => 34),
|
||||
'level' => Logger::WARNING,
|
||||
'level_name' => 'WARNING',
|
||||
'channel' => 'test',
|
||||
'datetime' => $record['datetime']->format('Y-m-d H:i:s'),
|
||||
'extra' => array(),
|
||||
);
|
||||
|
||||
$client->expects($this->once())
|
||||
->method('postDocument')
|
||||
->with($expected);
|
||||
|
||||
$handler = new DoctrineCouchDBHandler($client);
|
||||
$handler->handle($record);
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
<?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;
|
||||
|
||||
class DynamoDbHandlerTest extends TestCase
|
||||
{
|
||||
private $client;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
if (!class_exists('Aws\DynamoDb\DynamoDbClient')) {
|
||||
$this->markTestSkipped('aws/aws-sdk-php not installed');
|
||||
}
|
||||
|
||||
$this->client = $this->getMockBuilder('Aws\DynamoDb\DynamoDbClient')
|
||||
->setMethods(array('formatAttributes', '__call'))
|
||||
->disableOriginalConstructor()->getMock();
|
||||
}
|
||||
|
||||
public function testConstruct()
|
||||
{
|
||||
$this->assertInstanceOf('Monolog\Handler\DynamoDbHandler', new DynamoDbHandler($this->client, 'foo'));
|
||||
}
|
||||
|
||||
public function testInterface()
|
||||
{
|
||||
$this->assertInstanceOf('Monolog\Handler\HandlerInterface', new DynamoDbHandler($this->client, 'foo'));
|
||||
}
|
||||
|
||||
public function testGetFormatter()
|
||||
{
|
||||
$handler = new DynamoDbHandler($this->client, 'foo');
|
||||
$this->assertInstanceOf('Monolog\Formatter\ScalarFormatter', $handler->getFormatter());
|
||||
}
|
||||
|
||||
public function testHandle()
|
||||
{
|
||||
$record = $this->getRecord();
|
||||
$formatter = $this->getMock('Monolog\Formatter\FormatterInterface');
|
||||
$formatted = array('foo' => 1, 'bar' => 2);
|
||||
$handler = new DynamoDbHandler($this->client, 'foo');
|
||||
$handler->setFormatter($formatter);
|
||||
|
||||
$isV3 = defined('Aws\Sdk::VERSION') && version_compare(\Aws\Sdk::VERSION, '3.0', '>=');
|
||||
if ($isV3) {
|
||||
$expFormatted = array('foo' => array('N' => 1), 'bar' => array('N' => 2));
|
||||
} else {
|
||||
$expFormatted = $formatted;
|
||||
}
|
||||
|
||||
$formatter
|
||||
->expects($this->once())
|
||||
->method('format')
|
||||
->with($record)
|
||||
->will($this->returnValue($formatted));
|
||||
$this->client
|
||||
->expects($isV3 ? $this->never() : $this->once())
|
||||
->method('formatAttributes')
|
||||
->with($this->isType('array'))
|
||||
->will($this->returnValue($formatted));
|
||||
$this->client
|
||||
->expects($this->once())
|
||||
->method('__call')
|
||||
->with('putItem', array(array(
|
||||
'TableName' => 'foo',
|
||||
'Item' => $expFormatted,
|
||||
)));
|
||||
|
||||
$handler->handle($record);
|
||||
}
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
<?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\ElasticaFormatter;
|
||||
use Monolog\Formatter\NormalizerFormatter;
|
||||
use Monolog\TestCase;
|
||||
use Monolog\Logger;
|
||||
use Elastica\Client;
|
||||
use Elastica\Request;
|
||||
use Elastica\Response;
|
||||
|
||||
class ElasticSearchHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var Client mock
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* @var array Default handler options
|
||||
*/
|
||||
protected $options = array(
|
||||
'index' => 'my_index',
|
||||
'type' => 'doc_type',
|
||||
);
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
// Elastica lib required
|
||||
if (!class_exists("Elastica\Client")) {
|
||||
$this->markTestSkipped("ruflin/elastica not installed");
|
||||
}
|
||||
|
||||
// base mock Elastica Client object
|
||||
$this->client = $this->getMockBuilder('Elastica\Client')
|
||||
->setMethods(array('addDocuments'))
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\ElasticSearchHandler::write
|
||||
* @covers Monolog\Handler\ElasticSearchHandler::handleBatch
|
||||
* @covers Monolog\Handler\ElasticSearchHandler::bulkSend
|
||||
* @covers Monolog\Handler\ElasticSearchHandler::getDefaultFormatter
|
||||
*/
|
||||
public function testHandle()
|
||||
{
|
||||
// log message
|
||||
$msg = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('foo' => 7, 'bar', 'class' => new \stdClass),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array(),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
// format expected result
|
||||
$formatter = new ElasticaFormatter($this->options['index'], $this->options['type']);
|
||||
$expected = array($formatter->format($msg));
|
||||
|
||||
// setup ES client mock
|
||||
$this->client->expects($this->any())
|
||||
->method('addDocuments')
|
||||
->with($expected);
|
||||
|
||||
// perform tests
|
||||
$handler = new ElasticSearchHandler($this->client, $this->options);
|
||||
$handler->handle($msg);
|
||||
$handler->handleBatch(array($msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\ElasticSearchHandler::setFormatter
|
||||
*/
|
||||
public function testSetFormatter()
|
||||
{
|
||||
$handler = new ElasticSearchHandler($this->client);
|
||||
$formatter = new ElasticaFormatter('index_new', 'type_new');
|
||||
$handler->setFormatter($formatter);
|
||||
$this->assertInstanceOf('Monolog\Formatter\ElasticaFormatter', $handler->getFormatter());
|
||||
$this->assertEquals('index_new', $handler->getFormatter()->getIndex());
|
||||
$this->assertEquals('type_new', $handler->getFormatter()->getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\ElasticSearchHandler::setFormatter
|
||||
* @expectedException InvalidArgumentException
|
||||
* @expectedExceptionMessage ElasticSearchHandler is only compatible with ElasticaFormatter
|
||||
*/
|
||||
public function testSetFormatterInvalid()
|
||||
{
|
||||
$handler = new ElasticSearchHandler($this->client);
|
||||
$formatter = new NormalizerFormatter();
|
||||
$handler->setFormatter($formatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\ElasticSearchHandler::__construct
|
||||
* @covers Monolog\Handler\ElasticSearchHandler::getOptions
|
||||
*/
|
||||
public function testOptions()
|
||||
{
|
||||
$expected = array(
|
||||
'index' => $this->options['index'],
|
||||
'type' => $this->options['type'],
|
||||
'ignore_error' => false,
|
||||
);
|
||||
$handler = new ElasticSearchHandler($this->client, $this->options);
|
||||
$this->assertEquals($expected, $handler->getOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\ElasticSearchHandler::bulkSend
|
||||
* @dataProvider providerTestConnectionErrors
|
||||
*/
|
||||
public function testConnectionErrors($ignore, $expectedError)
|
||||
{
|
||||
$clientOpts = array('host' => '127.0.0.1', 'port' => 1);
|
||||
$client = new Client($clientOpts);
|
||||
$handlerOpts = array('ignore_error' => $ignore);
|
||||
$handler = new ElasticSearchHandler($client, $handlerOpts);
|
||||
|
||||
if ($expectedError) {
|
||||
$this->setExpectedException($expectedError[0], $expectedError[1]);
|
||||
$handler->handle($this->getRecord());
|
||||
} else {
|
||||
$this->assertFalse($handler->handle($this->getRecord()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function providerTestConnectionErrors()
|
||||
{
|
||||
return array(
|
||||
array(false, array('RuntimeException', 'Error sending messages to Elasticsearch')),
|
||||
array(true, false),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Integration test using localhost Elastic Search server
|
||||
*
|
||||
* @covers Monolog\Handler\ElasticSearchHandler::__construct
|
||||
* @covers Monolog\Handler\ElasticSearchHandler::handleBatch
|
||||
* @covers Monolog\Handler\ElasticSearchHandler::bulkSend
|
||||
* @covers Monolog\Handler\ElasticSearchHandler::getDefaultFormatter
|
||||
*/
|
||||
public function testHandleIntegration()
|
||||
{
|
||||
$msg = array(
|
||||
'level' => Logger::ERROR,
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('foo' => 7, 'bar', 'class' => new \stdClass),
|
||||
'datetime' => new \DateTime("@0"),
|
||||
'extra' => array(),
|
||||
'message' => 'log',
|
||||
);
|
||||
|
||||
$expected = $msg;
|
||||
$expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601);
|
||||
$expected['context'] = array(
|
||||
'class' => '[object] (stdClass: {})',
|
||||
'foo' => 7,
|
||||
0 => 'bar',
|
||||
);
|
||||
|
||||
$client = new Client();
|
||||
$handler = new ElasticSearchHandler($client, $this->options);
|
||||
try {
|
||||
$handler->handleBatch(array($msg));
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->markTestSkipped("Cannot connect to Elastic Search server on localhost");
|
||||
}
|
||||
|
||||
// check document id from ES server response
|
||||
$documentId = $this->getCreatedDocId($client->getLastResponse());
|
||||
$this->assertNotEmpty($documentId, 'No elastic document id received');
|
||||
|
||||
// retrieve document source from ES and validate
|
||||
$document = $this->getDocSourceFromElastic(
|
||||
$client,
|
||||
$this->options['index'],
|
||||
$this->options['type'],
|
||||
$documentId
|
||||
);
|
||||
$this->assertEquals($expected, $document);
|
||||
|
||||
// remove test index from ES
|
||||
$client->request("/{$this->options['index']}", Request::DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return last created document id from ES response
|
||||
* @param Response $response Elastica Response object
|
||||
* @return string|null
|
||||
*/
|
||||
protected function getCreatedDocId(Response $response)
|
||||
{
|
||||
$data = $response->getData();
|
||||
if (!empty($data['items'][0]['create']['_id'])) {
|
||||
return $data['items'][0]['create']['_id'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve document by id from Elasticsearch
|
||||
* @param Client $client Elastica client
|
||||
* @param string $index
|
||||
* @param string $type
|
||||
* @param string $documentId
|
||||
* @return array
|
||||
*/
|
||||
protected function getDocSourceFromElastic(Client $client, $index, $type, $documentId)
|
||||
{
|
||||
$resp = $client->request("/{$index}/{$type}/{$documentId}", Request::GET);
|
||||
$data = $resp->getData();
|
||||
if (!empty($data['_source'])) {
|
||||
return $data['_source'];
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
<?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;
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
|
||||
function error_log()
|
||||
{
|
||||
$GLOBALS['error_log'][] = func_get_args();
|
||||
}
|
||||
|
||||
class ErrorLogHandlerTest extends TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
$GLOBALS['error_log'] = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\ErrorLogHandler::__construct
|
||||
* @expectedException InvalidArgumentException
|
||||
* @expectedExceptionMessage The given message type "42" is not supported
|
||||
*/
|
||||
public function testShouldNotAcceptAnInvalidTypeOnContructor()
|
||||
{
|
||||
new ErrorLogHandler(42);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\ErrorLogHandler::write
|
||||
*/
|
||||
public function testShouldLogMessagesUsingErrorLogFuncion()
|
||||
{
|
||||
$type = ErrorLogHandler::OPERATING_SYSTEM;
|
||||
$handler = new ErrorLogHandler($type);
|
||||
$handler->setFormatter(new LineFormatter('%channel%.%level_name%: %message% %context% %extra%', null, true));
|
||||
$handler->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz"));
|
||||
|
||||
$this->assertSame("test.ERROR: Foo\nBar\r\n\r\nBaz [] []", $GLOBALS['error_log'][0][0]);
|
||||
$this->assertSame($GLOBALS['error_log'][0][1], $type);
|
||||
|
||||
$handler = new ErrorLogHandler($type, Logger::DEBUG, true, true);
|
||||
$handler->setFormatter(new LineFormatter(null, null, true));
|
||||
$handler->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz"));
|
||||
|
||||
$this->assertStringMatchesFormat('[%s] test.ERROR: Foo', $GLOBALS['error_log'][1][0]);
|
||||
$this->assertSame($GLOBALS['error_log'][1][1], $type);
|
||||
|
||||
$this->assertStringMatchesFormat('Bar', $GLOBALS['error_log'][2][0]);
|
||||
$this->assertSame($GLOBALS['error_log'][2][1], $type);
|
||||
|
||||
$this->assertStringMatchesFormat('Baz [] []', $GLOBALS['error_log'][3][0]);
|
||||
$this->assertSame($GLOBALS['error_log'][3][1], $type);
|
||||
}
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
<?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;
|
||||
use Monolog\TestCase;
|
||||
|
||||
class FilterHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Monolog\Handler\FilterHandler::isHandling
|
||||
*/
|
||||
public function testIsHandling()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE);
|
||||
$this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG)));
|
||||
$this->assertTrue($handler->isHandling($this->getRecord(Logger::INFO)));
|
||||
$this->assertTrue($handler->isHandling($this->getRecord(Logger::NOTICE)));
|
||||
$this->assertFalse($handler->isHandling($this->getRecord(Logger::WARNING)));
|
||||
$this->assertFalse($handler->isHandling($this->getRecord(Logger::ERROR)));
|
||||
$this->assertFalse($handler->isHandling($this->getRecord(Logger::CRITICAL)));
|
||||
$this->assertFalse($handler->isHandling($this->getRecord(Logger::ALERT)));
|
||||
$this->assertFalse($handler->isHandling($this->getRecord(Logger::EMERGENCY)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FilterHandler::handle
|
||||
* @covers Monolog\Handler\FilterHandler::setAcceptedLevels
|
||||
* @covers Monolog\Handler\FilterHandler::isHandling
|
||||
*/
|
||||
public function testHandleProcessOnlyNeededLevels()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE);
|
||||
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$this->assertFalse($test->hasDebugRecords());
|
||||
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
$handler->handle($this->getRecord(Logger::NOTICE));
|
||||
$this->assertTrue($test->hasNoticeRecords());
|
||||
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$this->assertFalse($test->hasWarningRecords());
|
||||
$handler->handle($this->getRecord(Logger::ERROR));
|
||||
$this->assertFalse($test->hasErrorRecords());
|
||||
$handler->handle($this->getRecord(Logger::CRITICAL));
|
||||
$this->assertFalse($test->hasCriticalRecords());
|
||||
$handler->handle($this->getRecord(Logger::ALERT));
|
||||
$this->assertFalse($test->hasAlertRecords());
|
||||
$handler->handle($this->getRecord(Logger::EMERGENCY));
|
||||
$this->assertFalse($test->hasEmergencyRecords());
|
||||
|
||||
$test = new TestHandler();
|
||||
$handler = new FilterHandler($test, array(Logger::INFO, Logger::ERROR));
|
||||
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$this->assertFalse($test->hasDebugRecords());
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
$handler->handle($this->getRecord(Logger::NOTICE));
|
||||
$this->assertFalse($test->hasNoticeRecords());
|
||||
$handler->handle($this->getRecord(Logger::ERROR));
|
||||
$this->assertTrue($test->hasErrorRecords());
|
||||
$handler->handle($this->getRecord(Logger::CRITICAL));
|
||||
$this->assertFalse($test->hasCriticalRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FilterHandler::setAcceptedLevels
|
||||
* @covers Monolog\Handler\FilterHandler::getAcceptedLevels
|
||||
*/
|
||||
public function testAcceptedLevelApi()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FilterHandler($test);
|
||||
|
||||
$levels = array(Logger::INFO, Logger::ERROR);
|
||||
$handler->setAcceptedLevels($levels);
|
||||
$this->assertSame($levels, $handler->getAcceptedLevels());
|
||||
|
||||
$handler->setAcceptedLevels(array('info', 'error'));
|
||||
$this->assertSame($levels, $handler->getAcceptedLevels());
|
||||
|
||||
$levels = array(Logger::CRITICAL, Logger::ALERT, Logger::EMERGENCY);
|
||||
$handler->setAcceptedLevels(Logger::CRITICAL, Logger::EMERGENCY);
|
||||
$this->assertSame($levels, $handler->getAcceptedLevels());
|
||||
|
||||
$handler->setAcceptedLevels('critical', 'emergency');
|
||||
$this->assertSame($levels, $handler->getAcceptedLevels());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FilterHandler::handle
|
||||
*/
|
||||
public function testHandleUsesProcessors()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FilterHandler($test, Logger::DEBUG, Logger::EMERGENCY);
|
||||
$handler->pushProcessor(
|
||||
function ($record) {
|
||||
$record['extra']['foo'] = true;
|
||||
|
||||
return $record;
|
||||
}
|
||||
);
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$this->assertTrue($test->hasWarningRecords());
|
||||
$records = $test->getRecords();
|
||||
$this->assertTrue($records[0]['extra']['foo']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FilterHandler::handle
|
||||
*/
|
||||
public function testHandleRespectsBubble()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
|
||||
$handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE, false);
|
||||
$this->assertTrue($handler->handle($this->getRecord(Logger::INFO)));
|
||||
$this->assertFalse($handler->handle($this->getRecord(Logger::WARNING)));
|
||||
|
||||
$handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE, true);
|
||||
$this->assertFalse($handler->handle($this->getRecord(Logger::INFO)));
|
||||
$this->assertFalse($handler->handle($this->getRecord(Logger::WARNING)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FilterHandler::handle
|
||||
*/
|
||||
public function testHandleWithCallback()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FilterHandler(
|
||||
function ($record, $handler) use ($test) {
|
||||
return $test;
|
||||
}, Logger::INFO, Logger::NOTICE, false
|
||||
);
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
$this->assertFalse($test->hasDebugRecords());
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FilterHandler::handle
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testHandleWithBadCallbackThrowsException()
|
||||
{
|
||||
$handler = new FilterHandler(
|
||||
function ($record, $handler) {
|
||||
return 'foo';
|
||||
}
|
||||
);
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
}
|
||||
}
|
||||
@@ -1,279 +0,0 @@
|
||||
<?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;
|
||||
use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
|
||||
use Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy;
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
class FingersCrossedHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::__construct
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::handle
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::activate
|
||||
*/
|
||||
public function testHandleBuffers()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FingersCrossedHandler($test);
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
$this->assertFalse($test->hasDebugRecords());
|
||||
$this->assertFalse($test->hasInfoRecords());
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$handler->close();
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
$this->assertTrue(count($test->getRecords()) === 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::handle
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::activate
|
||||
*/
|
||||
public function testHandleStopsBufferingAfterTrigger()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FingersCrossedHandler($test);
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->close();
|
||||
$this->assertTrue($test->hasWarningRecords());
|
||||
$this->assertTrue($test->hasDebugRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::handle
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::activate
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::reset
|
||||
*/
|
||||
public function testHandleResetBufferingAfterReset()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FingersCrossedHandler($test);
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->reset();
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
$handler->close();
|
||||
$this->assertTrue($test->hasWarningRecords());
|
||||
$this->assertTrue($test->hasDebugRecords());
|
||||
$this->assertFalse($test->hasInfoRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::handle
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::activate
|
||||
*/
|
||||
public function testHandleResetBufferingAfterBeingTriggeredWhenStopBufferingIsDisabled()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FingersCrossedHandler($test, Logger::WARNING, 0, false, false);
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
$handler->close();
|
||||
$this->assertTrue($test->hasWarningRecords());
|
||||
$this->assertTrue($test->hasDebugRecords());
|
||||
$this->assertFalse($test->hasInfoRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::handle
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::activate
|
||||
*/
|
||||
public function testHandleBufferLimit()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FingersCrossedHandler($test, Logger::WARNING, 2);
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$this->assertTrue($test->hasWarningRecords());
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
$this->assertFalse($test->hasDebugRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::handle
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::activate
|
||||
*/
|
||||
public function testHandleWithCallback()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FingersCrossedHandler(function ($record, $handler) use ($test) {
|
||||
return $test;
|
||||
});
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
$this->assertFalse($test->hasDebugRecords());
|
||||
$this->assertFalse($test->hasInfoRecords());
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
$this->assertTrue(count($test->getRecords()) === 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::handle
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::activate
|
||||
* @expectedException RuntimeException
|
||||
*/
|
||||
public function testHandleWithBadCallbackThrowsException()
|
||||
{
|
||||
$handler = new FingersCrossedHandler(function ($record, $handler) {
|
||||
return 'foo';
|
||||
});
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::isHandling
|
||||
*/
|
||||
public function testIsHandlingAlways()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FingersCrossedHandler($test, Logger::ERROR);
|
||||
$this->assertTrue($handler->isHandling($this->getRecord(Logger::DEBUG)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::__construct
|
||||
* @covers Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy::__construct
|
||||
* @covers Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy::isHandlerActivated
|
||||
*/
|
||||
public function testErrorLevelActivationStrategy()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Logger::WARNING));
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$this->assertFalse($test->hasDebugRecords());
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$this->assertTrue($test->hasDebugRecords());
|
||||
$this->assertTrue($test->hasWarningRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::__construct
|
||||
* @covers Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy::__construct
|
||||
* @covers Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy::isHandlerActivated
|
||||
*/
|
||||
public function testErrorLevelActivationStrategyWithPsrLevel()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy('warning'));
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$this->assertFalse($test->hasDebugRecords());
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$this->assertTrue($test->hasDebugRecords());
|
||||
$this->assertTrue($test->hasWarningRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::__construct
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::activate
|
||||
*/
|
||||
public function testOverrideActivationStrategy()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy('warning'));
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$this->assertFalse($test->hasDebugRecords());
|
||||
$handler->activate();
|
||||
$this->assertTrue($test->hasDebugRecords());
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy::__construct
|
||||
* @covers Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy::isHandlerActivated
|
||||
*/
|
||||
public function testChannelLevelActivationStrategy()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FingersCrossedHandler($test, new ChannelLevelActivationStrategy(Logger::ERROR, array('othertest' => Logger::DEBUG)));
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$this->assertFalse($test->hasWarningRecords());
|
||||
$record = $this->getRecord(Logger::DEBUG);
|
||||
$record['channel'] = 'othertest';
|
||||
$handler->handle($record);
|
||||
$this->assertTrue($test->hasDebugRecords());
|
||||
$this->assertTrue($test->hasWarningRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy::__construct
|
||||
* @covers Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy::isHandlerActivated
|
||||
*/
|
||||
public function testChannelLevelActivationStrategyWithPsrLevels()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FingersCrossedHandler($test, new ChannelLevelActivationStrategy('error', array('othertest' => 'debug')));
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$this->assertFalse($test->hasWarningRecords());
|
||||
$record = $this->getRecord(Logger::DEBUG);
|
||||
$record['channel'] = 'othertest';
|
||||
$handler->handle($record);
|
||||
$this->assertTrue($test->hasDebugRecords());
|
||||
$this->assertTrue($test->hasWarningRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::handle
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::activate
|
||||
*/
|
||||
public function testHandleUsesProcessors()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FingersCrossedHandler($test, Logger::INFO);
|
||||
$handler->pushProcessor(function ($record) {
|
||||
$record['extra']['foo'] = true;
|
||||
|
||||
return $record;
|
||||
});
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$this->assertTrue($test->hasWarningRecords());
|
||||
$records = $test->getRecords();
|
||||
$this->assertTrue($records[0]['extra']['foo']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::close
|
||||
*/
|
||||
public function testPassthruOnClose()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Logger::WARNING), 0, true, true, Logger::INFO);
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
$handler->close();
|
||||
$this->assertFalse($test->hasDebugRecords());
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FingersCrossedHandler::close
|
||||
*/
|
||||
public function testPsrLevelPassthruOnClose()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Logger::WARNING), 0, true, true, LogLevel::INFO);
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
$handler->close();
|
||||
$this->assertFalse($test->hasDebugRecords());
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\FirePHPHandler
|
||||
*/
|
||||
class FirePHPHandlerTest extends TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
TestFirePHPHandler::resetStatic();
|
||||
$_SERVER['HTTP_USER_AGENT'] = 'Monolog Test; FirePHP/1.0';
|
||||
}
|
||||
|
||||
public function testHeaders()
|
||||
{
|
||||
$handler = new TestFirePHPHandler;
|
||||
$handler->setFormatter($this->getIdentityFormatter());
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
|
||||
$expected = array(
|
||||
'X-Wf-Protocol-1' => 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2',
|
||||
'X-Wf-1-Structure-1' => 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1',
|
||||
'X-Wf-1-Plugin-1' => 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3',
|
||||
'X-Wf-1-1-1-1' => 'test',
|
||||
'X-Wf-1-1-1-2' => 'test',
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $handler->getHeaders());
|
||||
}
|
||||
|
||||
public function testConcurrentHandlers()
|
||||
{
|
||||
$handler = new TestFirePHPHandler;
|
||||
$handler->setFormatter($this->getIdentityFormatter());
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
|
||||
$handler2 = new TestFirePHPHandler;
|
||||
$handler2->setFormatter($this->getIdentityFormatter());
|
||||
$handler2->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler2->handle($this->getRecord(Logger::WARNING));
|
||||
|
||||
$expected = array(
|
||||
'X-Wf-Protocol-1' => 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2',
|
||||
'X-Wf-1-Structure-1' => 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1',
|
||||
'X-Wf-1-Plugin-1' => 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3',
|
||||
'X-Wf-1-1-1-1' => 'test',
|
||||
'X-Wf-1-1-1-2' => 'test',
|
||||
);
|
||||
|
||||
$expected2 = array(
|
||||
'X-Wf-1-1-1-3' => 'test',
|
||||
'X-Wf-1-1-1-4' => 'test',
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $handler->getHeaders());
|
||||
$this->assertEquals($expected2, $handler2->getHeaders());
|
||||
}
|
||||
}
|
||||
|
||||
class TestFirePHPHandler extends FirePHPHandler
|
||||
{
|
||||
protected $headers = array();
|
||||
|
||||
public static function resetStatic()
|
||||
{
|
||||
self::$initialized = false;
|
||||
self::$sendHeaders = true;
|
||||
self::$messageIndex = 1;
|
||||
}
|
||||
|
||||
protected function sendHeader($header, $content)
|
||||
{
|
||||
$this->headers[$header] = $content;
|
||||
}
|
||||
|
||||
public function getHeaders()
|
||||
{
|
||||
return $this->headers;
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
<?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\LineFormatter;
|
||||
use Monolog\Logger;
|
||||
use Monolog\TestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Monolog\Handler\FleepHookHandler
|
||||
*/
|
||||
class FleepHookHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Default token to use in tests
|
||||
*/
|
||||
const TOKEN = '123abc';
|
||||
|
||||
/**
|
||||
* @var FleepHookHandler
|
||||
*/
|
||||
private $handler;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (!extension_loaded('openssl')) {
|
||||
$this->markTestSkipped('This test requires openssl extension to run');
|
||||
}
|
||||
|
||||
// Create instances of the handler and logger for convenience
|
||||
$this->handler = new FleepHookHandler(self::TOKEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::__construct
|
||||
*/
|
||||
public function testConstructorSetsExpectedDefaults()
|
||||
{
|
||||
$this->assertEquals(Logger::DEBUG, $this->handler->getLevel());
|
||||
$this->assertEquals(true, $this->handler->getBubble());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getDefaultFormatter
|
||||
*/
|
||||
public function testHandlerUsesLineFormatterWhichIgnoresEmptyArrays()
|
||||
{
|
||||
$record = array(
|
||||
'message' => 'msg',
|
||||
'context' => array(),
|
||||
'level' => Logger::DEBUG,
|
||||
'level_name' => Logger::getLevelName(Logger::DEBUG),
|
||||
'channel' => 'channel',
|
||||
'datetime' => new \DateTime(),
|
||||
'extra' => array(),
|
||||
);
|
||||
|
||||
$expectedFormatter = new LineFormatter(null, null, true, true);
|
||||
$expected = $expectedFormatter->format($record);
|
||||
|
||||
$handlerFormatter = $this->handler->getFormatter();
|
||||
$actual = $handlerFormatter->format($record);
|
||||
|
||||
$this->assertEquals($expected, $actual, 'Empty context and extra arrays should not be rendered');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::__construct
|
||||
*/
|
||||
public function testConnectionStringisConstructedCorrectly()
|
||||
{
|
||||
$this->assertEquals('ssl://' . FleepHookHandler::FLEEP_HOST . ':443', $this->handler->getConnectionString());
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
<?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\FlowdockFormatter;
|
||||
use Monolog\TestCase;
|
||||
use Monolog\Logger;
|
||||
|
||||
/**
|
||||
* @author Dominik Liebler <liebler.dominik@gmail.com>
|
||||
* @see https://www.hipchat.com/docs/api
|
||||
*/
|
||||
class FlowdockHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $res;
|
||||
|
||||
/**
|
||||
* @var FlowdockHandler
|
||||
*/
|
||||
private $handler;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
if (!extension_loaded('openssl')) {
|
||||
$this->markTestSkipped('This test requires openssl to run');
|
||||
}
|
||||
}
|
||||
|
||||
public function testWriteHeader()
|
||||
{
|
||||
$this->createHandler();
|
||||
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 1024);
|
||||
|
||||
$this->assertRegexp('/POST \/v1\/messages\/team_inbox\/.* HTTP\/1.1\\r\\nHost: api.flowdock.com\\r\\nContent-Type: application\/json\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWriteHeader
|
||||
*/
|
||||
public function testWriteContent($content)
|
||||
{
|
||||
$this->assertRegexp('/"source":"test_source"/', $content);
|
||||
$this->assertRegexp('/"from_address":"source@test\.com"/', $content);
|
||||
}
|
||||
|
||||
private function createHandler($token = 'myToken')
|
||||
{
|
||||
$constructorArgs = array($token, Logger::DEBUG);
|
||||
$this->res = fopen('php://memory', 'a');
|
||||
$this->handler = $this->getMock(
|
||||
'\Monolog\Handler\FlowdockHandler',
|
||||
array('fsockopen', 'streamSetTimeout', 'closeSocket'),
|
||||
$constructorArgs
|
||||
);
|
||||
|
||||
$reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString');
|
||||
$reflectionProperty->setAccessible(true);
|
||||
$reflectionProperty->setValue($this->handler, 'localhost:1234');
|
||||
|
||||
$this->handler->expects($this->any())
|
||||
->method('fsockopen')
|
||||
->will($this->returnValue($this->res));
|
||||
$this->handler->expects($this->any())
|
||||
->method('streamSetTimeout')
|
||||
->will($this->returnValue(true));
|
||||
$this->handler->expects($this->any())
|
||||
->method('closeSocket')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$this->handler->setFormatter(new FlowdockFormatter('test_source', 'source@test.com'));
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
<?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 Gelf\Message;
|
||||
use Monolog\TestCase;
|
||||
use Monolog\Logger;
|
||||
use Monolog\Formatter\GelfMessageFormatter;
|
||||
|
||||
class GelfHandlerLegacyTest extends TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
if (!class_exists('Gelf\MessagePublisher') || !class_exists('Gelf\Message')) {
|
||||
$this->markTestSkipped("mlehner/gelf-php not installed");
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/GelfMockMessagePublisher.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\GelfHandler::__construct
|
||||
*/
|
||||
public function testConstruct()
|
||||
{
|
||||
$handler = new GelfHandler($this->getMessagePublisher());
|
||||
$this->assertInstanceOf('Monolog\Handler\GelfHandler', $handler);
|
||||
}
|
||||
|
||||
protected function getHandler($messagePublisher)
|
||||
{
|
||||
$handler = new GelfHandler($messagePublisher);
|
||||
|
||||
return $handler;
|
||||
}
|
||||
|
||||
protected function getMessagePublisher()
|
||||
{
|
||||
return new GelfMockMessagePublisher('localhost');
|
||||
}
|
||||
|
||||
public function testDebug()
|
||||
{
|
||||
$messagePublisher = $this->getMessagePublisher();
|
||||
$handler = $this->getHandler($messagePublisher);
|
||||
|
||||
$record = $this->getRecord(Logger::DEBUG, "A test debug message");
|
||||
$handler->handle($record);
|
||||
|
||||
$this->assertEquals(7, $messagePublisher->lastMessage->getLevel());
|
||||
$this->assertEquals('test', $messagePublisher->lastMessage->getFacility());
|
||||
$this->assertEquals($record['message'], $messagePublisher->lastMessage->getShortMessage());
|
||||
$this->assertEquals(null, $messagePublisher->lastMessage->getFullMessage());
|
||||
}
|
||||
|
||||
public function testWarning()
|
||||
{
|
||||
$messagePublisher = $this->getMessagePublisher();
|
||||
$handler = $this->getHandler($messagePublisher);
|
||||
|
||||
$record = $this->getRecord(Logger::WARNING, "A test warning message");
|
||||
$handler->handle($record);
|
||||
|
||||
$this->assertEquals(4, $messagePublisher->lastMessage->getLevel());
|
||||
$this->assertEquals('test', $messagePublisher->lastMessage->getFacility());
|
||||
$this->assertEquals($record['message'], $messagePublisher->lastMessage->getShortMessage());
|
||||
$this->assertEquals(null, $messagePublisher->lastMessage->getFullMessage());
|
||||
}
|
||||
|
||||
public function testInjectedGelfMessageFormatter()
|
||||
{
|
||||
$messagePublisher = $this->getMessagePublisher();
|
||||
$handler = $this->getHandler($messagePublisher);
|
||||
|
||||
$handler->setFormatter(new GelfMessageFormatter('mysystem', 'EXT', 'CTX'));
|
||||
|
||||
$record = $this->getRecord(Logger::WARNING, "A test warning message");
|
||||
$record['extra']['blarg'] = 'yep';
|
||||
$record['context']['from'] = 'logger';
|
||||
$handler->handle($record);
|
||||
|
||||
$this->assertEquals('mysystem', $messagePublisher->lastMessage->getHost());
|
||||
$this->assertArrayHasKey('_EXTblarg', $messagePublisher->lastMessage->toArray());
|
||||
$this->assertArrayHasKey('_CTXfrom', $messagePublisher->lastMessage->toArray());
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
<?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 Gelf\Message;
|
||||
use Monolog\TestCase;
|
||||
use Monolog\Logger;
|
||||
use Monolog\Formatter\GelfMessageFormatter;
|
||||
|
||||
class GelfHandlerTest extends TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
if (!class_exists('Gelf\Publisher') || !class_exists('Gelf\Message')) {
|
||||
$this->markTestSkipped("graylog2/gelf-php not installed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\GelfHandler::__construct
|
||||
*/
|
||||
public function testConstruct()
|
||||
{
|
||||
$handler = new GelfHandler($this->getMessagePublisher());
|
||||
$this->assertInstanceOf('Monolog\Handler\GelfHandler', $handler);
|
||||
}
|
||||
|
||||
protected function getHandler($messagePublisher)
|
||||
{
|
||||
$handler = new GelfHandler($messagePublisher);
|
||||
|
||||
return $handler;
|
||||
}
|
||||
|
||||
protected function getMessagePublisher()
|
||||
{
|
||||
return $this->getMock('Gelf\Publisher', array('publish'), array(), '', false);
|
||||
}
|
||||
|
||||
public function testDebug()
|
||||
{
|
||||
$record = $this->getRecord(Logger::DEBUG, "A test debug message");
|
||||
$expectedMessage = new Message();
|
||||
$expectedMessage
|
||||
->setLevel(7)
|
||||
->setFacility("test")
|
||||
->setShortMessage($record['message'])
|
||||
->setTimestamp($record['datetime'])
|
||||
;
|
||||
|
||||
$messagePublisher = $this->getMessagePublisher();
|
||||
$messagePublisher->expects($this->once())
|
||||
->method('publish')
|
||||
->with($expectedMessage);
|
||||
|
||||
$handler = $this->getHandler($messagePublisher);
|
||||
|
||||
$handler->handle($record);
|
||||
}
|
||||
|
||||
public function testWarning()
|
||||
{
|
||||
$record = $this->getRecord(Logger::WARNING, "A test warning message");
|
||||
$expectedMessage = new Message();
|
||||
$expectedMessage
|
||||
->setLevel(4)
|
||||
->setFacility("test")
|
||||
->setShortMessage($record['message'])
|
||||
->setTimestamp($record['datetime'])
|
||||
;
|
||||
|
||||
$messagePublisher = $this->getMessagePublisher();
|
||||
$messagePublisher->expects($this->once())
|
||||
->method('publish')
|
||||
->with($expectedMessage);
|
||||
|
||||
$handler = $this->getHandler($messagePublisher);
|
||||
|
||||
$handler->handle($record);
|
||||
}
|
||||
|
||||
public function testInjectedGelfMessageFormatter()
|
||||
{
|
||||
$record = $this->getRecord(Logger::WARNING, "A test warning message");
|
||||
$record['extra']['blarg'] = 'yep';
|
||||
$record['context']['from'] = 'logger';
|
||||
|
||||
$expectedMessage = new Message();
|
||||
$expectedMessage
|
||||
->setLevel(4)
|
||||
->setFacility("test")
|
||||
->setHost("mysystem")
|
||||
->setShortMessage($record['message'])
|
||||
->setTimestamp($record['datetime'])
|
||||
->setAdditional("EXTblarg", 'yep')
|
||||
->setAdditional("CTXfrom", 'logger')
|
||||
;
|
||||
|
||||
$messagePublisher = $this->getMessagePublisher();
|
||||
$messagePublisher->expects($this->once())
|
||||
->method('publish')
|
||||
->with($expectedMessage);
|
||||
|
||||
$handler = $this->getHandler($messagePublisher);
|
||||
$handler->setFormatter(new GelfMessageFormatter('mysystem', 'EXT', 'CTX'));
|
||||
$handler->handle($record);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<?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 Gelf\MessagePublisher;
|
||||
use Gelf\Message;
|
||||
|
||||
class GelfMockMessagePublisher extends MessagePublisher
|
||||
{
|
||||
public function publish(Message $message)
|
||||
{
|
||||
$this->lastMessage = $message;
|
||||
}
|
||||
|
||||
public $lastMessage = null;
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
<?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 GroupHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Monolog\Handler\GroupHandler::__construct
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testConstructorOnlyTakesHandler()
|
||||
{
|
||||
new GroupHandler(array(new TestHandler(), "foo"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\GroupHandler::__construct
|
||||
* @covers Monolog\Handler\GroupHandler::handle
|
||||
*/
|
||||
public function testHandle()
|
||||
{
|
||||
$testHandlers = array(new TestHandler(), new TestHandler());
|
||||
$handler = new GroupHandler($testHandlers);
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
$handler->handle($this->getRecord(Logger::INFO));
|
||||
foreach ($testHandlers as $test) {
|
||||
$this->assertTrue($test->hasDebugRecords());
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
$this->assertTrue(count($test->getRecords()) === 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\GroupHandler::handleBatch
|
||||
*/
|
||||
public function testHandleBatch()
|
||||
{
|
||||
$testHandlers = array(new TestHandler(), new TestHandler());
|
||||
$handler = new GroupHandler($testHandlers);
|
||||
$handler->handleBatch(array($this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO)));
|
||||
foreach ($testHandlers as $test) {
|
||||
$this->assertTrue($test->hasDebugRecords());
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
$this->assertTrue(count($test->getRecords()) === 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\GroupHandler::isHandling
|
||||
*/
|
||||
public function testIsHandling()
|
||||
{
|
||||
$testHandlers = array(new TestHandler(Logger::ERROR), new TestHandler(Logger::WARNING));
|
||||
$handler = new GroupHandler($testHandlers);
|
||||
$this->assertTrue($handler->isHandling($this->getRecord(Logger::ERROR)));
|
||||
$this->assertTrue($handler->isHandling($this->getRecord(Logger::WARNING)));
|
||||
$this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\GroupHandler::handle
|
||||
*/
|
||||
public function testHandleUsesProcessors()
|
||||
{
|
||||
$test = new TestHandler();
|
||||
$handler = new GroupHandler(array($test));
|
||||
$handler->pushProcessor(function ($record) {
|
||||
$record['extra']['foo'] = true;
|
||||
|
||||
return $record;
|
||||
});
|
||||
$handler->handle($this->getRecord(Logger::WARNING));
|
||||
$this->assertTrue($test->hasWarningRecords());
|
||||
$records = $test->getRecords();
|
||||
$this->assertTrue($records[0]['extra']['foo']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\GroupHandler::handle
|
||||
*/
|
||||
public function testHandleBatchUsesProcessors()
|
||||
{
|
||||
$testHandlers = array(new TestHandler(), new TestHandler());
|
||||
$handler = new GroupHandler($testHandlers);
|
||||
$handler->pushProcessor(function ($record) {
|
||||
$record['extra']['foo'] = true;
|
||||
|
||||
return $record;
|
||||
});
|
||||
$handler->handleBatch(array($this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO)));
|
||||
foreach ($testHandlers as $test) {
|
||||
$this->assertTrue($test->hasDebugRecords());
|
||||
$this->assertTrue($test->hasInfoRecords());
|
||||
$this->assertTrue(count($test->getRecords()) === 2);
|
||||
$records = $test->getRecords();
|
||||
$this->assertTrue($records[0]['extra']['foo']);
|
||||
$this->assertTrue($records[1]['extra']['foo']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
<?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());
|
||||
}
|
||||
}
|
||||
@@ -1,279 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @author Rafael Dohms <rafael@doh.ms>
|
||||
* @see https://www.hipchat.com/docs/api
|
||||
*/
|
||||
class HipChatHandlerTest extends TestCase
|
||||
{
|
||||
private $res;
|
||||
/** @var HipChatHandler */
|
||||
private $handler;
|
||||
|
||||
public function testWriteHeader()
|
||||
{
|
||||
$this->createHandler();
|
||||
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 1024);
|
||||
|
||||
$this->assertRegexp('/POST \/v1\/rooms\/message\?format=json&auth_token=.* HTTP\/1.1\\r\\nHost: api.hipchat.com\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function testWriteCustomHostHeader()
|
||||
{
|
||||
$this->createHandler('myToken', 'room1', 'Monolog', true, 'hipchat.foo.bar');
|
||||
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 1024);
|
||||
|
||||
$this->assertRegexp('/POST \/v1\/rooms\/message\?format=json&auth_token=.* HTTP\/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function testWriteV2()
|
||||
{
|
||||
$this->createHandler('myToken', 'room1', 'Monolog', false, 'hipchat.foo.bar', 'v2');
|
||||
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 1024);
|
||||
|
||||
$this->assertRegexp('/POST \/v2\/room\/room1\/notification\?auth_token=.* HTTP\/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function testWriteV2Notify()
|
||||
{
|
||||
$this->createHandler('myToken', 'room1', 'Monolog', true, 'hipchat.foo.bar', 'v2');
|
||||
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 1024);
|
||||
|
||||
$this->assertRegexp('/POST \/v2\/room\/room1\/notification\?auth_token=.* HTTP\/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function testRoomSpaces()
|
||||
{
|
||||
$this->createHandler('myToken', 'room name', 'Monolog', false, 'hipchat.foo.bar', 'v2');
|
||||
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 1024);
|
||||
|
||||
$this->assertRegexp('/POST \/v2\/room\/room%20name\/notification\?auth_token=.* HTTP\/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWriteHeader
|
||||
*/
|
||||
public function testWriteContent($content)
|
||||
{
|
||||
$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
|
||||
*/
|
||||
public function testWriteContentNotify($content)
|
||||
{
|
||||
$this->assertRegexp('/notify=1&message=test1&message_format=text&color=red&room_id=room1&from=Monolog$/', $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWriteV2
|
||||
*/
|
||||
public function testWriteContentV2($content)
|
||||
{
|
||||
$this->assertRegexp('/notify=false&message=test1&message_format=text&color=red&from=Monolog$/', $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testWriteV2Notify
|
||||
*/
|
||||
public function testWriteContentV2Notify($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()
|
||||
{
|
||||
$this->createHandler();
|
||||
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'Backup of database "example" finished in 16 minutes.'));
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 1024);
|
||||
|
||||
$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
|
||||
*/
|
||||
public function testWriteWithErrorLevelsAndColors($level, $expectedColor)
|
||||
{
|
||||
$this->createHandler();
|
||||
$this->handler->handle($this->getRecord($level, 'Backup of database "example" finished in 16 minutes.'));
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 1024);
|
||||
|
||||
$this->assertRegexp('/color='.$expectedColor.'/', $content);
|
||||
}
|
||||
|
||||
public function provideLevelColors()
|
||||
{
|
||||
return array(
|
||||
array(Logger::DEBUG, 'gray'),
|
||||
array(Logger::INFO, 'green'),
|
||||
array(Logger::WARNING, 'yellow'),
|
||||
array(Logger::ERROR, 'red'),
|
||||
array(Logger::CRITICAL, 'red'),
|
||||
array(Logger::ALERT, 'red'),
|
||||
array(Logger::EMERGENCY,'red'),
|
||||
array(Logger::NOTICE, 'green'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideBatchRecords
|
||||
*/
|
||||
public function testHandleBatch($records, $expectedColor)
|
||||
{
|
||||
$this->createHandler();
|
||||
|
||||
$this->handler->handleBatch($records);
|
||||
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 1024);
|
||||
|
||||
$this->assertRegexp('/color='.$expectedColor.'/', $content);
|
||||
}
|
||||
|
||||
public function provideBatchRecords()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
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()),
|
||||
),
|
||||
'red',
|
||||
),
|
||||
array(
|
||||
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()),
|
||||
),
|
||||
'yellow',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
array('level' => Logger::DEBUG, 'message' => 'Just debugging.', 'level_name' => 'debug', 'datetime' => new \DateTime()),
|
||||
array('level' => Logger::NOTICE, 'message' => 'Something noticeable happened.', 'level_name' => 'notice', 'datetime' => new \DateTime()),
|
||||
),
|
||||
'green',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
array('level' => Logger::DEBUG, 'message' => 'Just debugging.', 'level_name' => 'debug', 'datetime' => new \DateTime()),
|
||||
),
|
||||
'gray',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
private function createHandler($token = 'myToken', $room = 'room1', $name = 'Monolog', $notify = false, $host = 'api.hipchat.com', $version = 'v1')
|
||||
{
|
||||
$constructorArgs = array($token, $room, $name, $notify, Logger::DEBUG, true, true, 'text', $host, $version);
|
||||
$this->res = fopen('php://memory', 'a');
|
||||
$this->handler = $this->getMock(
|
||||
'\Monolog\Handler\HipChatHandler',
|
||||
array('fsockopen', 'streamSetTimeout', 'closeSocket'),
|
||||
$constructorArgs
|
||||
);
|
||||
|
||||
$reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString');
|
||||
$reflectionProperty->setAccessible(true);
|
||||
$reflectionProperty->setValue($this->handler, 'localhost:1234');
|
||||
|
||||
$this->handler->expects($this->any())
|
||||
->method('fsockopen')
|
||||
->will($this->returnValue($this->res));
|
||||
$this->handler->expects($this->any())
|
||||
->method('streamSetTimeout')
|
||||
->will($this->returnValue(true));
|
||||
$this->handler->expects($this->any())
|
||||
->method('closeSocket')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$this->handler->setFormatter($this->getIdentityFormatter());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testCreateWithTooLongName()
|
||||
{
|
||||
$hipChatHandler = new HipChatHandler('token', 'room', 'SixteenCharsHere');
|
||||
}
|
||||
|
||||
public function testCreateWithTooLongNameV2()
|
||||
{
|
||||
// creating a handler with too long of a name but using the v2 api doesn't matter.
|
||||
$hipChatHandler = new HipChatHandler('token', 'room', 'SixteenCharsHere', false, Logger::CRITICAL, true, true, 'test', 'api.hipchat.com', 'v2');
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @author Robert Kaufmann III <rok3@rok3.me>
|
||||
* @author Gabriel Machado <gabriel.ms1@hotmail.com>
|
||||
*/
|
||||
class InsightOpsHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $resource;
|
||||
|
||||
/**
|
||||
* @var LogEntriesHandler
|
||||
*/
|
||||
private $handler;
|
||||
|
||||
public function testWriteContent()
|
||||
{
|
||||
$this->createHandler();
|
||||
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'Critical write test'));
|
||||
|
||||
fseek($this->resource, 0);
|
||||
$content = fread($this->resource, 1024);
|
||||
|
||||
$this->assertRegexp('/testToken \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] test.CRITICAL: Critical write test/', $content);
|
||||
}
|
||||
|
||||
public function testWriteBatchContent()
|
||||
{
|
||||
$this->createHandler();
|
||||
$this->handler->handleBatch($this->getMultipleRecords());
|
||||
|
||||
fseek($this->resource, 0);
|
||||
$content = fread($this->resource, 1024);
|
||||
|
||||
$this->assertRegexp('/(testToken \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] .* \[\] \[\]\n){3}/', $content);
|
||||
}
|
||||
|
||||
private function createHandler()
|
||||
{
|
||||
$useSSL = extension_loaded('openssl');
|
||||
$args = array('testToken', 'us', $useSSL, Logger::DEBUG, true);
|
||||
$this->resource = fopen('php://memory', 'a');
|
||||
$this->handler = $this->getMock(
|
||||
'\Monolog\Handler\InsightOpsHandler',
|
||||
array('fsockopen', 'streamSetTimeout', 'closeSocket'),
|
||||
$args
|
||||
);
|
||||
|
||||
$reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString');
|
||||
$reflectionProperty->setAccessible(true);
|
||||
$reflectionProperty->setValue($this->handler, 'localhost:1234');
|
||||
|
||||
$this->handler->expects($this->any())
|
||||
->method('fsockopen')
|
||||
->will($this->returnValue($this->resource));
|
||||
$this->handler->expects($this->any())
|
||||
->method('streamSetTimeout')
|
||||
->will($this->returnValue(true));
|
||||
$this->handler->expects($this->any())
|
||||
->method('closeSocket')
|
||||
->will($this->returnValue(true));
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @author Robert Kaufmann III <rok3@rok3.me>
|
||||
*/
|
||||
class LogEntriesHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $res;
|
||||
|
||||
/**
|
||||
* @var LogEntriesHandler
|
||||
*/
|
||||
private $handler;
|
||||
|
||||
public function testWriteContent()
|
||||
{
|
||||
$this->createHandler();
|
||||
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'Critical write test'));
|
||||
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 1024);
|
||||
|
||||
$this->assertRegexp('/testToken \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] test.CRITICAL: Critical write test/', $content);
|
||||
}
|
||||
|
||||
public function testWriteBatchContent()
|
||||
{
|
||||
$records = array(
|
||||
$this->getRecord(),
|
||||
$this->getRecord(),
|
||||
$this->getRecord(),
|
||||
);
|
||||
$this->createHandler();
|
||||
$this->handler->handleBatch($records);
|
||||
|
||||
fseek($this->res, 0);
|
||||
$content = fread($this->res, 1024);
|
||||
|
||||
$this->assertRegexp('/(testToken \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] .* \[\] \[\]\n){3}/', $content);
|
||||
}
|
||||
|
||||
private function createHandler()
|
||||
{
|
||||
$useSSL = extension_loaded('openssl');
|
||||
$args = array('testToken', $useSSL, Logger::DEBUG, true);
|
||||
$this->res = fopen('php://memory', 'a');
|
||||
$this->handler = $this->getMock(
|
||||
'\Monolog\Handler\LogEntriesHandler',
|
||||
array('fsockopen', 'streamSetTimeout', 'closeSocket'),
|
||||
$args
|
||||
);
|
||||
|
||||
$reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString');
|
||||
$reflectionProperty->setAccessible(true);
|
||||
$reflectionProperty->setValue($this->handler, 'localhost:1234');
|
||||
|
||||
$this->handler->expects($this->any())
|
||||
->method('fsockopen')
|
||||
->will($this->returnValue($this->res));
|
||||
$this->handler->expects($this->any())
|
||||
->method('streamSetTimeout')
|
||||
->will($this->returnValue(true));
|
||||
$this->handler->expects($this->any())
|
||||
->method('closeSocket')
|
||||
->will($this->returnValue(true));
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
<?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;
|
||||
use Monolog\TestCase;
|
||||
|
||||
class MailHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Monolog\Handler\MailHandler::handleBatch
|
||||
*/
|
||||
public function testHandleBatch()
|
||||
{
|
||||
$formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface');
|
||||
$formatter->expects($this->once())
|
||||
->method('formatBatch'); // Each record is formatted
|
||||
|
||||
$handler = $this->getMockForAbstractClass('Monolog\\Handler\\MailHandler');
|
||||
$handler->expects($this->once())
|
||||
->method('send');
|
||||
$handler->expects($this->never())
|
||||
->method('write'); // write is for individual records
|
||||
|
||||
$handler->setFormatter($formatter);
|
||||
|
||||
$handler->handleBatch($this->getMultipleRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\MailHandler::handleBatch
|
||||
*/
|
||||
public function testHandleBatchNotSendsMailIfMessagesAreBelowLevel()
|
||||
{
|
||||
$records = array(
|
||||
$this->getRecord(Logger::DEBUG, 'debug message 1'),
|
||||
$this->getRecord(Logger::DEBUG, 'debug message 2'),
|
||||
$this->getRecord(Logger::INFO, 'information'),
|
||||
);
|
||||
|
||||
$handler = $this->getMockForAbstractClass('Monolog\\Handler\\MailHandler');
|
||||
$handler->expects($this->never())
|
||||
->method('send');
|
||||
$handler->setLevel(Logger::ERROR);
|
||||
|
||||
$handler->handleBatch($records);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Handler\MailHandler::write
|
||||
*/
|
||||
public function testHandle()
|
||||
{
|
||||
$handler = $this->getMockForAbstractClass('Monolog\\Handler\\MailHandler');
|
||||
|
||||
$record = $this->getRecord();
|
||||
$records = array($record);
|
||||
$records[0]['formatted'] = '['.$record['datetime']->format('Y-m-d H:i:s').'] test.WARNING: test [] []'."\n";
|
||||
|
||||
$handler->expects($this->once())
|
||||
->method('send')
|
||||
->with($records[0]['formatted'], $records);
|
||||
|
||||
$handler->handle($record);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user