mirror of
https://github.com/Seldaek/monolog.git
synced 2025-07-15 10:36:23 +02:00
@ -1,3 +1,7 @@
|
|||||||
|
### Unreleased
|
||||||
|
|
||||||
|
* Deprecated Monolog\DateTimeImmutable in favor of Monolog\JsonSerializableDateTimeImmutable
|
||||||
|
|
||||||
### 3.8.0 (2024-11-12)
|
### 3.8.0 (2024-11-12)
|
||||||
|
|
||||||
* Added `$fileOpenMode` param to `StreamHandler` to define a custom fopen mode to open the log file (#1913)
|
* Added `$fileOpenMode` param to `StreamHandler` to define a custom fopen mode to open the log file (#1913)
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
### 4.0.0
|
||||||
|
|
||||||
|
Overall / notable changes:
|
||||||
|
|
||||||
|
- Monolog\DateTimeImmutable has been removed in favor of Monolog\JsonSerializableDateTimeImmutable.
|
||||||
|
|
||||||
### 3.0.0
|
### 3.0.0
|
||||||
|
|
||||||
Overall / notable changes:
|
Overall / notable changes:
|
||||||
|
@ -11,7 +11,7 @@ message | string | The log message. When the `PsrLogMessag
|
|||||||
level | Monolog\Level case | Severity of the log message. See log levels described in [01-usage.md](01-usage.md#log-levels).
|
level | Monolog\Level case | Severity of the log message. See log levels described in [01-usage.md](01-usage.md#log-levels).
|
||||||
context | array | Arbitrary data passed with the construction of the message. For example the username of the current user or their IP address.
|
context | array | Arbitrary data passed with the construction of the message. For example the username of the current user or their IP address.
|
||||||
channel | string | The channel this message was logged to. This is the name that was passed when the logger was created with `new Logger('channel')`.
|
channel | string | The channel this message was logged to. This is the name that was passed when the logger was created with `new Logger('channel')`.
|
||||||
datetime | Monolog\DateTimeImmutable | Date and time when the message was logged. Class extends `\DateTimeImmutable`.
|
datetime | Monolog\JsonSerializableDateTimeImmutable | Date and time when the message was logged. Class extends `\DateTimeImmutable`.
|
||||||
extra | array | A placeholder array where processors can put additional data. Always available, but empty if there are no processors registered.
|
extra | array | A placeholder array where processors can put additional data. Always available, but empty if there are no processors registered.
|
||||||
|
|
||||||
At first glance `context` and `extra` look very similar, and they are in the sense that they both carry arbitrary data that is related to the log message somehow.
|
At first glance `context` and `extra` look very similar, and they are in the sense that they both carry arbitrary data that is related to the log message somehow.
|
||||||
|
@ -11,38 +11,13 @@
|
|||||||
|
|
||||||
namespace Monolog;
|
namespace Monolog;
|
||||||
|
|
||||||
use DateTimeZone;
|
class_alias(JsonSerializableDateTimeImmutable::class, 'Monolog\DateTimeImmutable');
|
||||||
|
|
||||||
/**
|
if (false) {
|
||||||
* Overrides default json encoding of date time objects
|
/**
|
||||||
*
|
* @deprecated Use \Monolog\JsonSerializableDateTimeImmutable instead.
|
||||||
* @author Menno Holtkamp
|
|
||||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
|
||||||
*/
|
*/
|
||||||
class DateTimeImmutable extends \DateTimeImmutable implements \JsonSerializable
|
class DateTimeImmutable extends JsonSerializableDateTimeImmutable
|
||||||
{
|
|
||||||
private bool $useMicroseconds;
|
|
||||||
|
|
||||||
public function __construct(bool $useMicroseconds, ?DateTimeZone $timezone = null)
|
|
||||||
{
|
{
|
||||||
$this->useMicroseconds = $useMicroseconds;
|
|
||||||
|
|
||||||
// if you like to use a custom time to pass to Logger::addRecord directly,
|
|
||||||
// call modify() or setTimestamp() on this instance to change the date after creating it
|
|
||||||
parent::__construct('now', $timezone);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function jsonSerialize(): string
|
|
||||||
{
|
|
||||||
if ($this->useMicroseconds) {
|
|
||||||
return $this->format('Y-m-d\TH:i:s.uP');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->format('Y-m-d\TH:i:sP');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __toString(): string
|
|
||||||
{
|
|
||||||
return $this->jsonSerialize();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
namespace Monolog\Formatter;
|
namespace Monolog\Formatter;
|
||||||
|
|
||||||
use Monolog\DateTimeImmutable;
|
use Monolog\JsonSerializableDateTimeImmutable;
|
||||||
use Monolog\Utils;
|
use Monolog\Utils;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
use Monolog\LogRecord;
|
use Monolog\LogRecord;
|
||||||
@ -322,9 +322,9 @@ class NormalizerFormatter implements FormatterInterface
|
|||||||
|
|
||||||
protected function formatDate(\DateTimeInterface $date): string
|
protected function formatDate(\DateTimeInterface $date): string
|
||||||
{
|
{
|
||||||
// in case the date format isn't custom then we defer to the custom DateTimeImmutable
|
// in case the date format isn't custom then we defer to the custom JsonSerializableDateTimeImmutable
|
||||||
// formatting logic, which will pick the right format based on whether useMicroseconds is on
|
// formatting logic, which will pick the right format based on whether useMicroseconds is on
|
||||||
if ($this->dateFormat === self::SIMPLE_DATE && $date instanceof DateTimeImmutable) {
|
if ($this->dateFormat === self::SIMPLE_DATE && $date instanceof JsonSerializableDateTimeImmutable) {
|
||||||
return (string) $date;
|
return (string) $date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ use Monolog\Formatter\FormatterInterface;
|
|||||||
use Monolog\Level;
|
use Monolog\Level;
|
||||||
use Monolog\Utils;
|
use Monolog\Utils;
|
||||||
use Monolog\LogRecord;
|
use Monolog\LogRecord;
|
||||||
use Monolog\DateTimeImmutable;
|
use Monolog\JsonSerializableDateTimeImmutable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler sending logs to the ChromePHP extension (http://www.chromephp.com/)
|
* Handler sending logs to the ChromePHP extension (http://www.chromephp.com/)
|
||||||
@ -150,7 +150,7 @@ class ChromePHPHandler extends AbstractProcessingHandler
|
|||||||
message: 'Incomplete logs, chrome header size limit reached',
|
message: 'Incomplete logs, chrome header size limit reached',
|
||||||
level: Level::Warning,
|
level: Level::Warning,
|
||||||
channel: 'monolog',
|
channel: 'monolog',
|
||||||
datetime: new DateTimeImmutable(true),
|
datetime: new JsonSerializableDateTimeImmutable(true),
|
||||||
);
|
);
|
||||||
self::$json['rows'][\count(self::$json['rows']) - 1] = $this->getFormatter()->format($record);
|
self::$json['rows'][\count(self::$json['rows']) - 1] = $this->getFormatter()->format($record);
|
||||||
$json = Utils::jsonEncode(self::$json, Utils::DEFAULT_JSON_FLAGS & ~JSON_UNESCAPED_UNICODE, true);
|
$json = Utils::jsonEncode(self::$json, Utils::DEFAULT_JSON_FLAGS & ~JSON_UNESCAPED_UNICODE, true);
|
||||||
|
48
src/Monolog/JsonSerializableDateTimeImmutable.php
Normal file
48
src/Monolog/JsonSerializableDateTimeImmutable.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?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;
|
||||||
|
|
||||||
|
use DateTimeZone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides default json encoding of date time objects
|
||||||
|
*
|
||||||
|
* @author Menno Holtkamp
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*/
|
||||||
|
class JsonSerializableDateTimeImmutable extends \DateTimeImmutable implements \JsonSerializable
|
||||||
|
{
|
||||||
|
private bool $useMicroseconds;
|
||||||
|
|
||||||
|
public function __construct(bool $useMicroseconds, ?DateTimeZone $timezone = null)
|
||||||
|
{
|
||||||
|
$this->useMicroseconds = $useMicroseconds;
|
||||||
|
|
||||||
|
// if you like to use a custom time to pass to Logger::addRecord directly,
|
||||||
|
// call modify() or setTimestamp() on this instance to change the date after creating it
|
||||||
|
parent::__construct('now', $timezone);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jsonSerialize(): string
|
||||||
|
{
|
||||||
|
if ($this->useMicroseconds) {
|
||||||
|
return $this->format('Y-m-d\TH:i:s.uP');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->format('Y-m-d\TH:i:sP');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return $this->jsonSerialize();
|
||||||
|
}
|
||||||
|
}
|
@ -323,12 +323,13 @@ class Logger implements LoggerInterface, ResettableInterface
|
|||||||
* @param int $level The logging level (a Monolog or RFC 5424 level)
|
* @param int $level The logging level (a Monolog or RFC 5424 level)
|
||||||
* @param string $message The log message
|
* @param string $message The log message
|
||||||
* @param mixed[] $context The log context
|
* @param mixed[] $context The log context
|
||||||
* @param DateTimeImmutable|null $datetime Optional log date to log into the past or future
|
* @param JsonSerializableDateTimeImmutable|null $datetime Optional log date to log into the past or future
|
||||||
|
*
|
||||||
* @return bool Whether the record has been processed
|
* @return bool Whether the record has been processed
|
||||||
*
|
*
|
||||||
* @phpstan-param value-of<Level::VALUES>|Level $level
|
* @phpstan-param value-of<Level::VALUES>|Level $level
|
||||||
*/
|
*/
|
||||||
public function addRecord(int|Level $level, string $message, array $context = [], DateTimeImmutable|null $datetime = null): bool
|
public function addRecord(int|Level $level, string $message, array $context = [], JsonSerializableDateTimeImmutable|null $datetime = null): bool
|
||||||
{
|
{
|
||||||
if (\is_int($level) && isset(self::RFC_5424_LEVELS[$level])) {
|
if (\is_int($level) && isset(self::RFC_5424_LEVELS[$level])) {
|
||||||
$level = self::RFC_5424_LEVELS[$level];
|
$level = self::RFC_5424_LEVELS[$level];
|
||||||
@ -356,7 +357,7 @@ class Logger implements LoggerInterface, ResettableInterface
|
|||||||
$recordInitialized = \count($this->processors) === 0;
|
$recordInitialized = \count($this->processors) === 0;
|
||||||
|
|
||||||
$record = new LogRecord(
|
$record = new LogRecord(
|
||||||
datetime: $datetime ?? new DateTimeImmutable($this->microsecondTimestamps, $this->timezone),
|
datetime: $datetime ?? new JsonSerializableDateTimeImmutable($this->microsecondTimestamps, $this->timezone),
|
||||||
channel: $this->name,
|
channel: $this->name,
|
||||||
level: self::toMonologLevel($level),
|
level: self::toMonologLevel($level),
|
||||||
message: $message,
|
message: $message,
|
||||||
@ -518,7 +519,7 @@ class Logger implements LoggerInterface, ResettableInterface
|
|||||||
public function isHandling(int|string|Level $level): bool
|
public function isHandling(int|string|Level $level): bool
|
||||||
{
|
{
|
||||||
$record = new LogRecord(
|
$record = new LogRecord(
|
||||||
datetime: new DateTimeImmutable($this->microsecondTimestamps, $this->timezone),
|
datetime: new JsonSerializableDateTimeImmutable($this->microsecondTimestamps, $this->timezone),
|
||||||
channel: $this->name,
|
channel: $this->name,
|
||||||
message: '',
|
message: '',
|
||||||
level: self::toMonologLevel($level),
|
level: self::toMonologLevel($level),
|
||||||
|
@ -60,7 +60,7 @@ class PsrLogMessageProcessor implements ProcessorInterface
|
|||||||
if (null === $val || \is_scalar($val) || (\is_object($val) && method_exists($val, "__toString"))) {
|
if (null === $val || \is_scalar($val) || (\is_object($val) && method_exists($val, "__toString"))) {
|
||||||
$replacements[$placeholder] = $val;
|
$replacements[$placeholder] = $val;
|
||||||
} elseif ($val instanceof \DateTimeInterface) {
|
} elseif ($val instanceof \DateTimeInterface) {
|
||||||
if (null === $this->dateFormat && $val instanceof \Monolog\DateTimeImmutable) {
|
if (null === $this->dateFormat && $val instanceof \Monolog\JsonSerializableDateTimeImmutable) {
|
||||||
// handle monolog dates using __toString if no specific dateFormat was asked for
|
// handle monolog dates using __toString if no specific dateFormat was asked for
|
||||||
// so that it follows the useMicroseconds flag
|
// so that it follows the useMicroseconds flag
|
||||||
$replacements[$placeholder] = (string) $val;
|
$replacements[$placeholder] = (string) $val;
|
||||||
|
@ -14,7 +14,7 @@ namespace Monolog\Test;
|
|||||||
use Monolog\Level;
|
use Monolog\Level;
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
use Monolog\LogRecord;
|
use Monolog\LogRecord;
|
||||||
use Monolog\DateTimeImmutable;
|
use Monolog\JsonSerializableDateTimeImmutable;
|
||||||
use Monolog\Formatter\FormatterInterface;
|
use Monolog\Formatter\FormatterInterface;
|
||||||
use Psr\Log\LogLevel;
|
use Psr\Log\LogLevel;
|
||||||
use ReflectionProperty;
|
use ReflectionProperty;
|
||||||
@ -34,7 +34,7 @@ class TestCase extends \PHPUnit\Framework\TestCase
|
|||||||
*
|
*
|
||||||
* @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $level
|
* @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $level
|
||||||
*/
|
*/
|
||||||
protected function getRecord(int|string|Level $level = Level::Warning, string|\Stringable $message = 'test', array $context = [], string $channel = 'test', \DateTimeImmutable $datetime = new DateTimeImmutable(true), array $extra = []): LogRecord
|
protected function getRecord(int|string|Level $level = Level::Warning, string|\Stringable $message = 'test', array $context = [], string $channel = 'test', \DateTimeImmutable $datetime = new JsonSerializableDateTimeImmutable(true), array $extra = []): LogRecord
|
||||||
{
|
{
|
||||||
return new LogRecord(
|
return new LogRecord(
|
||||||
message: (string) $message,
|
message: (string) $message,
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
namespace Monolog\Formatter;
|
namespace Monolog\Formatter;
|
||||||
|
|
||||||
use Monolog\DateTimeImmutable;
|
use Monolog\JsonSerializableDateTimeImmutable;
|
||||||
use Monolog\Test\TestCase;
|
use Monolog\Test\TestCase;
|
||||||
|
|
||||||
class ScalarFormatterTest extends TestCase
|
class ScalarFormatterTest extends TestCase
|
||||||
@ -57,7 +57,7 @@ class ScalarFormatterTest extends TestCase
|
|||||||
'baz' => false,
|
'baz' => false,
|
||||||
'bam' => [1, 2, 3],
|
'bam' => [1, 2, 3],
|
||||||
'bat' => ['foo' => 'bar'],
|
'bat' => ['foo' => 'bar'],
|
||||||
'bap' => $dt = new DateTimeImmutable(true),
|
'bap' => $dt = new JsonSerializableDateTimeImmutable(true),
|
||||||
'ban' => $exception,
|
'ban' => $exception,
|
||||||
]));
|
]));
|
||||||
|
|
||||||
|
@ -556,7 +556,7 @@ class LoggerTest extends TestCase
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers Logger::setTimezone
|
* @covers Logger::setTimezone
|
||||||
* @covers DateTimeImmutable::__construct
|
* @covers JsonSerializableDateTimeImmutable::__construct
|
||||||
*/
|
*/
|
||||||
public function testTimezoneIsRespectedInUTC()
|
public function testTimezoneIsRespectedInUTC()
|
||||||
{
|
{
|
||||||
@ -578,7 +578,7 @@ class LoggerTest extends TestCase
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers Logger::setTimezone
|
* @covers Logger::setTimezone
|
||||||
* @covers DateTimeImmutable::__construct
|
* @covers JsonSerializableDateTimeImmutable::__construct
|
||||||
*/
|
*/
|
||||||
public function testTimezoneIsRespectedInOtherTimezone()
|
public function testTimezoneIsRespectedInOtherTimezone()
|
||||||
{
|
{
|
||||||
@ -807,7 +807,7 @@ class LoggerTest extends TestCase
|
|||||||
$logger->pushHandler($loggingHandler);
|
$logger->pushHandler($loggingHandler);
|
||||||
$logger->pushHandler($testHandler);
|
$logger->pushHandler($testHandler);
|
||||||
|
|
||||||
$datetime = (new DateTimeImmutable($microseconds))->modify('2022-03-04 05:06:07');
|
$datetime = (new JsonSerializableDateTimeImmutable($microseconds))->modify('2022-03-04 05:06:07');
|
||||||
$logger->addRecord(Level::Debug, 'test', [], $datetime);
|
$logger->addRecord(Level::Debug, 'test', [], $datetime);
|
||||||
|
|
||||||
list($record) = $testHandler->getRecords();
|
list($record) = $testHandler->getRecords();
|
||||||
|
Reference in New Issue
Block a user