Skip to content

Commit

Permalink
Deprecate DateTimeImmutable (#1928)
Browse files Browse the repository at this point in the history
Fixes #1926
  • Loading branch information
ruudk authored Dec 5, 2024
1 parent e940004 commit a258e4f
Show file tree
Hide file tree
Showing 12 changed files with 83 additions and 49 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### Unreleased

* Deprecated Monolog\DateTimeImmutable in favor of Monolog\JsonSerializableDateTimeImmutable

### 3.8.0 (2024-11-12)

* Added `$fileOpenMode` param to `StreamHandler` to define a custom fopen mode to open the log file (#1913)
Expand Down
6 changes: 6 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
### 4.0.0

Overall / notable changes:

- Monolog\DateTimeImmutable has been removed in favor of Monolog\JsonSerializableDateTimeImmutable.

### 3.0.0

Overall / notable changes:
Expand Down
2 changes: 1 addition & 1 deletion doc/message-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
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')`.
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.

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.
Expand Down
37 changes: 6 additions & 31 deletions src/Monolog/DateTimeImmutable.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,38 +11,13 @@

namespace Monolog;

use DateTimeZone;
class_alias(JsonSerializableDateTimeImmutable::class, 'Monolog\DateTimeImmutable');

/**
* Overrides default json encoding of date time objects
*
* @author Menno Holtkamp
* @author Jordi Boggiano <[email protected]>
*/
class DateTimeImmutable 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
if (false) {

Check failure on line 16 in src/Monolog/DateTimeImmutable.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1)

If condition is always false.

Check failure on line 16 in src/Monolog/DateTimeImmutable.php

View workflow job for this annotation

GitHub Actions / PHPStan (latest)

If condition is always false.
/**
* @deprecated Use \Monolog\JsonSerializableDateTimeImmutable instead.
*/
class DateTimeImmutable extends JsonSerializableDateTimeImmutable
{
return $this->jsonSerialize();
}
}
6 changes: 3 additions & 3 deletions src/Monolog/Formatter/NormalizerFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace Monolog\Formatter;

use Monolog\DateTimeImmutable;
use Monolog\JsonSerializableDateTimeImmutable;
use Monolog\Utils;
use Throwable;
use Monolog\LogRecord;
Expand Down Expand Up @@ -322,9 +322,9 @@ protected function toJson($data, bool $ignoreErrors = false): 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
if ($this->dateFormat === self::SIMPLE_DATE && $date instanceof DateTimeImmutable) {
if ($this->dateFormat === self::SIMPLE_DATE && $date instanceof JsonSerializableDateTimeImmutable) {
return (string) $date;
}

Expand Down
4 changes: 2 additions & 2 deletions src/Monolog/Handler/ChromePHPHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use Monolog\Level;
use Monolog\Utils;
use Monolog\LogRecord;
use Monolog\DateTimeImmutable;
use Monolog\JsonSerializableDateTimeImmutable;

/**
* Handler sending logs to the ChromePHP extension (http://www.chromephp.com/)
Expand Down Expand Up @@ -150,7 +150,7 @@ protected function send(): void
message: 'Incomplete logs, chrome header size limit reached',
level: Level::Warning,
channel: 'monolog',
datetime: new DateTimeImmutable(true),
datetime: new JsonSerializableDateTimeImmutable(true),
);
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);
Expand Down
48 changes: 48 additions & 0 deletions src/Monolog/JsonSerializableDateTimeImmutable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php declare(strict_types=1);

/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <[email protected]>
*
* 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 <[email protected]>
*/
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();
}
}
9 changes: 5 additions & 4 deletions src/Monolog/Logger.php
Original file line number Diff line number Diff line change
Expand Up @@ -323,12 +323,13 @@ public function useLoggingLoopDetection(bool $detectCycles): self
* @param int $level The logging level (a Monolog or RFC 5424 level)
* @param string $message The log message
* @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
*
* @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])) {
$level = self::RFC_5424_LEVELS[$level];
Expand Down Expand Up @@ -356,7 +357,7 @@ public function addRecord(int|Level $level, string $message, array $context = []
$recordInitialized = \count($this->processors) === 0;

$record = new LogRecord(
datetime: $datetime ?? new DateTimeImmutable($this->microsecondTimestamps, $this->timezone),
datetime: $datetime ?? new JsonSerializableDateTimeImmutable($this->microsecondTimestamps, $this->timezone),
channel: $this->name,
level: self::toMonologLevel($level),
message: $message,
Expand Down Expand Up @@ -518,7 +519,7 @@ public static function toMonologLevel(string|int|Level $level): Level
public function isHandling(int|string|Level $level): bool
{
$record = new LogRecord(
datetime: new DateTimeImmutable($this->microsecondTimestamps, $this->timezone),
datetime: new JsonSerializableDateTimeImmutable($this->microsecondTimestamps, $this->timezone),
channel: $this->name,
message: '',
level: self::toMonologLevel($level),
Expand Down
2 changes: 1 addition & 1 deletion src/Monolog/Processor/PsrLogMessageProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public function __invoke(LogRecord $record): LogRecord
if (null === $val || \is_scalar($val) || (\is_object($val) && method_exists($val, "__toString"))) {
$replacements[$placeholder] = $val;
} 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
// so that it follows the useMicroseconds flag
$replacements[$placeholder] = (string) $val;
Expand Down
4 changes: 2 additions & 2 deletions src/Monolog/Test/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
use Monolog\Level;
use Monolog\Logger;
use Monolog\LogRecord;
use Monolog\DateTimeImmutable;
use Monolog\JsonSerializableDateTimeImmutable;
use Monolog\Formatter\FormatterInterface;
use Psr\Log\LogLevel;
use ReflectionProperty;
Expand All @@ -34,7 +34,7 @@ class TestCase extends \PHPUnit\Framework\TestCase
*
* @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(
message: (string) $message,
Expand Down
4 changes: 2 additions & 2 deletions tests/Monolog/Formatter/ScalarFormatterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace Monolog\Formatter;

use Monolog\DateTimeImmutable;
use Monolog\JsonSerializableDateTimeImmutable;
use Monolog\Test\TestCase;

class ScalarFormatterTest extends TestCase
Expand Down Expand Up @@ -57,7 +57,7 @@ public function testFormat()
'baz' => false,
'bam' => [1, 2, 3],
'bat' => ['foo' => 'bar'],
'bap' => $dt = new DateTimeImmutable(true),
'bap' => $dt = new JsonSerializableDateTimeImmutable(true),
'ban' => $exception,
]));

Expand Down
6 changes: 3 additions & 3 deletions tests/Monolog/LoggerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ function ($tz) {

/**
* @covers Logger::setTimezone
* @covers DateTimeImmutable::__construct
* @covers JsonSerializableDateTimeImmutable::__construct
*/
public function testTimezoneIsRespectedInUTC()
{
Expand All @@ -578,7 +578,7 @@ public function testTimezoneIsRespectedInUTC()

/**
* @covers Logger::setTimezone
* @covers DateTimeImmutable::__construct
* @covers JsonSerializableDateTimeImmutable::__construct
*/
public function testTimezoneIsRespectedInOtherTimezone()
{
Expand Down Expand Up @@ -807,7 +807,7 @@ public function testLogWithDateTime()
$logger->pushHandler($loggingHandler);
$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);

list($record) = $testHandler->getRecords();
Expand Down

0 comments on commit a258e4f

Please sign in to comment.