Skip to content

Commit

Permalink
Upgrade to monolog3
Browse files Browse the repository at this point in the history
  • Loading branch information
jderusse committed Jan 25, 2024
1 parent 50c380a commit 0df7d50
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 53 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"email": "[email protected]"
}],
"require": {
"monolog/monolog": "^2.0",
"monolog/monolog": "^3.0",
"nyholm/dsn": "^2.0",
"nyholm/psr7": "^1.5",
"open-telemetry/api": ">=1.0.2",
Expand Down
2 changes: 1 addition & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
parameters:
level: 8
level: 8
32 changes: 22 additions & 10 deletions spec/Tracing/Instrumentation/LogHandler/TracingHandlerSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
namespace spec\Instrumentation\Tracing\Instrumentation\LogHandler;

use Instrumentation\Tracing\Instrumentation\MainSpanContextInterface;
use Monolog\Logger;
use Monolog\DateTimeImmutable;
use Monolog\Level;
use Monolog\LogRecord;
use OpenTelemetry\API\Trace\SpanInterface;
use OpenTelemetry\API\Trace\TracerProviderInterface;
use PhpSpec\ObjectBehavior;
Expand All @@ -21,13 +23,13 @@ public function it_adds_event_from_all_channels(
MainSpanContextInterface $mainSpanContext,
SpanInterface $span
): void {
$this->beConstructedWith($tracerProvider, $mainSpanContext, Logger::INFO, []);
$this->beConstructedWith($tracerProvider, $mainSpanContext, Level::Info, []);

$mainSpanContext->getMainSpan()->willReturn($span);
$span->addEvent(Argument::any())->willReturn($span);

$this->handle(['message' => 'Error from channel "foo"', 'channel' => 'foo', 'level' => Logger::ERROR, 'extra' => [], 'context' => []]);
$this->handle(['message' => 'Error from channel "bar"', 'channel' => 'bar', 'level' => Logger::ERROR, 'extra' => [], 'context' => []]);
$this->handle($this->createLogRecord('foo'));
$this->handle($this->createLogRecord('bar'));

$span->addEvent('Error from channel "foo"')->shouldHaveBeenCalled();
$span->addEvent('Error from channel "bar"')->shouldHaveBeenCalled();
Expand All @@ -38,13 +40,13 @@ public function it_adds_event_from_specific_channel_only(
MainSpanContextInterface $mainSpanContext,
SpanInterface $span
): void {
$this->beConstructedWith($tracerProvider, $mainSpanContext, Logger::INFO, ['foo']);
$this->beConstructedWith($tracerProvider, $mainSpanContext, Level::Info, ['foo']);

$mainSpanContext->getMainSpan()->willReturn($span);
$span->addEvent(Argument::any())->willReturn($span);

$this->handle(['message' => 'Error from channel "foo"', 'channel' => 'foo', 'level' => Logger::ERROR, 'extra' => [], 'context' => []]);
$this->handle(['message' => 'Error from channel "bar"', 'channel' => 'bar', 'level' => Logger::ERROR, 'extra' => [], 'context' => []]);
$this->handle($this->createLogRecord('foo'));
$this->handle($this->createLogRecord('bar'));

$span->addEvent('Error from channel "foo"')->shouldHaveBeenCalled();
$span->addEvent('Error from channel "bar"')->shouldNotHaveBeenCalled();
Expand All @@ -55,15 +57,25 @@ public function it_ignores_event_from_specific_channel(
MainSpanContextInterface $mainSpanContext,
SpanInterface $span
): void {
$this->beConstructedWith($tracerProvider, $mainSpanContext, Logger::INFO, ['!foo']);
$this->beConstructedWith($tracerProvider, $mainSpanContext, Level::Info, ['!foo']);

$mainSpanContext->getMainSpan()->willReturn($span);
$span->addEvent(Argument::any())->willReturn($span);

$this->handle(['message' => 'Error from channel "foo"', 'channel' => 'foo', 'level' => Logger::ERROR, 'extra' => [], 'context' => []]);
$this->handle(['message' => 'Error from channel "bar"', 'channel' => 'bar', 'level' => Logger::ERROR, 'extra' => [], 'context' => []]);
$this->handle($this->createLogRecord('foo'));
$this->handle($this->createLogRecord('bar'));

$span->addEvent('Error from channel "foo"')->shouldNotHaveBeenCalled();
$span->addEvent('Error from channel "bar"')->shouldHaveBeenCalled();
}

private function createLogRecord(string $chanel): LogRecord
{
return new LogRecord(
new DateTimeImmutable(true),
$chanel,
Level::Error,
'Error from channel "'.$chanel.'"',
);
}
}
6 changes: 5 additions & 1 deletion src/Bridge/GoogleCloud/Logging/Formatter/StdOutFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,16 @@ public function __construct(private string $project)
* @see https://cloud.google.com/logging/docs/agent/configuration#process-payload
* @see https://github.com/GoogleCloudPlatform/fluent-plugin-google-cloud/blob/master/lib/fluent/plugin/out_google_cloud.rb
*/
protected function normalize($data, int $depth = 0)
protected function normalize(mixed $data, int $depth = 0): mixed
{
$data = parent::normalize($data, $depth);
if (!\is_array($data)) {
return $data;
}

if ($depth < 1) {
// Map timestamp
// @phpstan-ignore-next-line
$date = new \DateTime($data['datetime']);
$data['timestamp'] = [
'seconds' => $date->getTimestamp(),
Expand Down
7 changes: 3 additions & 4 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
namespace Instrumentation\DependencyInjection;

use Monolog\Level;
use Monolog\Logger;
use OpenTelemetry\SemConv\ResourceAttributes;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
Expand Down Expand Up @@ -90,9 +89,9 @@ public function getConfigTreeBuilder(): TreeBuilder
->addDefaultsIfNotSet()
->children()
->enumNode('level')
->defaultValue(Logger::INFO)
->values(method_exists(Logger::class, 'getLevels') ? Logger::getLevels() : Level::cases()) // @phpstan-ignore-line
->info(sprintf('One of the %s levels.', Logger::class))
->defaultValue(Level::Info)
->values(Level::cases())
->info(sprintf('One of the %s levels.', Level::class))
->end()
->arrayNode('channels')
->defaultValue([])
Expand Down
5 changes: 3 additions & 2 deletions src/Logging/Formatter/JsonFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@
namespace Instrumentation\Logging\Formatter;

use Monolog\Formatter\JsonFormatter as BaseJsonFormatter;
use Monolog\LogRecord;
use Monolog\Utils;

class JsonFormatter extends BaseJsonFormatter
{
private ?int $lengthLimit = null;

public function format(array $record): string
public function format(LogRecord $record): string
{
$normalized = $this->normalize($record);
$normalized = $this->normalizeRecord($record);

$json = $this->toJson($normalized, true);
$length = \strlen($json);
Expand Down
16 changes: 7 additions & 9 deletions src/Logging/Processor/NormalizeExceptionProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,16 @@
namespace Instrumentation\Logging\Processor;

use Instrumentation\Semantics\Normalizer\ExceptionNormalizer;
use Monolog\LogRecord;
use Monolog\Processor\ProcessorInterface;

class NormalizeExceptionProcessor
class NormalizeExceptionProcessor implements ProcessorInterface
{
/**
* @param array<mixed> $record
*
* @return array<mixed>
*/
public function __invoke(array $record): array
public function __invoke(LogRecord $record): LogRecord
{
if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Throwable) {
$record['context']['exception'] = ExceptionNormalizer::normalizeException($record['context']['exception']);
if (isset($record->context['exception']) && $record->context['exception'] instanceof \Throwable) {
// @phpstan-ignore-next-line
$record->context['exception'] = ExceptionNormalizer::normalizeException($record->context['exception']);
}

return $record;
Expand Down
36 changes: 20 additions & 16 deletions src/Logging/Processor/TraceContextProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@

namespace Instrumentation\Logging\Processor;

use Monolog\LogRecord;
use Monolog\Processor\ProcessorInterface;
use OpenTelemetry\SDK\Trace\Span;

class TraceContextProcessor
class TraceContextProcessor implements ProcessorInterface
{
/**
* @param array{trace:array<string>,span:array<string>,sampled:array<string>,operation:array<string>} $map
Expand All @@ -18,12 +20,7 @@ public function __construct(private array $map)
{
}

/**
* @param array<mixed> $record
*
* @return array<mixed>
*/
public function __invoke(array $record): array
public function __invoke(LogRecord $record): LogRecord
{
$span = Span::getCurrent();
$spanContext = $span->getContext();
Expand All @@ -32,28 +29,35 @@ public function __invoke(array $record): array
return $record;
}

$this->setRecordKey($record, $this->map['trace'], $spanContext->getTraceId());
$this->setRecordKey($record, $this->map['span'], $spanContext->getSpanId());
$this->setRecordKey($record, $this->map['sampled'], $spanContext->isSampled());
$record = $this->withRecordKey($record, $this->map['trace'], $spanContext->getTraceId());
$record = $this->withRecordKey($record, $this->map['span'], $spanContext->getSpanId());
$record = $this->withRecordKey($record, $this->map['sampled'], $spanContext->isSampled());

if ($span instanceof Span) {
$this->setRecordKey($record, $this->map['operation'], $span->getName());
$record = $this->withRecordKey($record, $this->map['operation'], $span->getName());
}

return $record;
}

/**
* @param array<string,mixed> $record
* @param array<string> $keys
* @param string|bool|int $value
* @param array<string> $keys
* @param string|bool|int $value
*/
private function setRecordKey(array &$record, array $keys, $value): void
private function withRecordKey(LogRecord $record, array $keys, $value): LogRecord
{
$temp = &$record;
if ([] === $keys) {
return $record;
}
$first = array_shift($keys);

$array = $record[$first];
$temp = &$array;
foreach ($keys as $key) {
$temp = &$temp[$key];
}
$temp = $value;

return $record->with(...[$first => $array]);
}
}
17 changes: 9 additions & 8 deletions src/Tracing/Instrumentation/LogHandler/TracingHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@

use Instrumentation\Tracing\Instrumentation\MainSpanContextInterface;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Logger;
use Monolog\Level;
use Monolog\LogRecord;
use Monolog\Processor\PsrLogMessageProcessor;
use OpenTelemetry\API\Trace\TracerProviderInterface;
use OpenTelemetry\SDK\Trace\Span;
Expand All @@ -29,7 +30,7 @@ class TracingHandler extends AbstractProcessingHandler
/**
* @param array<string> $channels
*/
public function __construct(protected TracerProviderInterface $tracerProvider, protected MainSpanContextInterface $mainSpanContext, $level = Logger::INFO, private array $channels = [], private string $strategy = self::STRATEGY_MAIN_SPAN, bool $bubble = true)
public function __construct(protected TracerProviderInterface $tracerProvider, protected MainSpanContextInterface $mainSpanContext, $level = Level::Info, private array $channels = [], private string $strategy = self::STRATEGY_MAIN_SPAN, bool $bubble = true)
{
parent::__construct($level, $bubble);

Expand All @@ -43,13 +44,13 @@ public function __construct(protected TracerProviderInterface $tracerProvider, p
$this->channels = array_filter($this->channels, fn (string $channel) => !str_starts_with($channel, '!'));
}

protected function write(array $record): void
protected function write(LogRecord $record): void
{
if ($this->channels && !\in_array($record['channel'], $this->channels)) {
if ($this->channels && !\in_array($record->channel, $this->channels)) {
return;
}

if ($this->excludedChannels && \in_array($record['channel'], $this->excludedChannels)) {
if ($this->excludedChannels && \in_array($record->channel, $this->excludedChannels)) {
return;
}

Expand All @@ -59,10 +60,10 @@ protected function write(array $record): void
default => throw new \InvalidArgumentException(sprintf('Unkown strategy "%s".', $this->strategy))
};

if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Throwable) {
$span->recordException($record['context']['exception'], ['raw_stacktrace' => $record['context']['exception']->getTraceAsString()]);
if (isset($record->context['exception']) && $record->context['exception'] instanceof \Throwable) {
$span->recordException($record->context['exception'], ['raw_stacktrace' => $record->context['exception']->getTraceAsString()]);
} else {
$span->addEvent($record['message']);
$span->addEvent($record->message);
}
}
}
1 change: 0 additions & 1 deletion src/Tracing/Serializer/Normalizer/ErrorNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ public function normalize($exception, string $format = null, array $context = []
*/
public function supportsNormalization($data, string $format = null, array $context = []): bool
{
// @phpstan-ignore-next-line
return $this->decorated->supportsNormalization($data, $format, $context);

Check failure on line 71 in src/Tracing/Serializer/Normalizer/ErrorNormalizer.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1)

Method Symfony\Component\Serializer\Normalizer\NormalizerInterface::supportsNormalization() invoked with 3 parameters, 1-2 required.
}
}

0 comments on commit 0df7d50

Please sign in to comment.