Skip to content

Commit b10cb8d

Browse files
authored
feat(laravel-auto-instrumentation): use logger provider in logwatcher (#286)
* feat(laravel-auto-instrumentation): use logger provider in logwatcher * style: correctly order import statements * test: update test offsets for logging storage
1 parent 662e25a commit b10cb8d

File tree

5 files changed

+71
-36
lines changed

5 files changed

+71
-36
lines changed

src/Instrumentation/Laravel/src/Hooks/Illuminate/Foundation/Application.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public function instrument(): void
3030
$this->registerWatchers($application, new CacheWatcher());
3131
$this->registerWatchers($application, new ClientRequestWatcher($this->instrumentation));
3232
$this->registerWatchers($application, new ExceptionWatcher());
33-
$this->registerWatchers($application, new LogWatcher());
33+
$this->registerWatchers($application, new LogWatcher($this->instrumentation));
3434
$this->registerWatchers($application, new QueryWatcher($this->instrumentation));
3535
},
3636
);

src/Instrumentation/Laravel/src/Watchers/LogWatcher.php

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,17 @@
66

77
use Illuminate\Contracts\Foundation\Application;
88
use Illuminate\Log\Events\MessageLogged;
9-
use OpenTelemetry\API\Trace\Span;
10-
use OpenTelemetry\Context\Context;
9+
use OpenTelemetry\API\Instrumentation\CachedInstrumentation;
10+
use OpenTelemetry\API\Logs\LogRecord;
11+
use OpenTelemetry\API\Logs\Map\Psr3;
1112

1213
class LogWatcher extends Watcher
1314
{
15+
public function __construct(
16+
private CachedInstrumentation $instrumentation,
17+
) {
18+
}
19+
1420
/** @psalm-suppress UndefinedInterfaceMethod */
1521
public function register(Application $app): void
1622
{
@@ -24,18 +30,16 @@ public function register(Application $app): void
2430
public function recordLog(MessageLogged $log): void
2531
{
2632
$attributes = [
27-
'level' => $log->level,
33+
'context' => json_encode(array_filter($log->context)),
2834
];
2935

30-
$attributes['context'] = json_encode(array_filter($log->context));
36+
$logger = $this->instrumentation->logger();
3137

32-
$message = $log->message;
38+
$record = (new LogRecord($log->message))
39+
->setSeverityText($log->level)
40+
->setSeverityNumber(Psr3::severityNumber($log->level))
41+
->setAttributes($attributes);
3342

34-
$scope = Context::storage()->scope();
35-
if (!$scope) {
36-
return;
37-
}
38-
$span = Span::fromContext($scope->context());
39-
$span->addEvent($message, $attributes);
43+
$logger->emit($record);
4044
}
4145
}

src/Instrumentation/Laravel/tests/Integration/LaravelInstrumentationTest.php

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public function test_cache_log_db(): void
3434
$this->router()->get('/hello', function () {
3535
$text = 'Hello Cruel World';
3636
cache()->forever('opentelemetry', 'opentelemetry');
37-
Log::info('Log info');
37+
Log::info('Log info', ['test' => true]);
3838
cache()->get('opentelemetry.io', 'php');
3939
cache()->get('opentelemetry', 'php');
4040
cache()->forget('opentelemetry');
@@ -46,23 +46,30 @@ public function test_cache_log_db(): void
4646
$this->assertCount(0, $this->storage);
4747
$response = $this->call('GET', '/hello');
4848
$this->assertEquals(200, $response->status());
49-
$this->assertCount(2, $this->storage);
50-
$span = $this->storage[1];
49+
$this->assertCount(3, $this->storage);
50+
$span = $this->storage[2];
5151
$this->assertSame('GET /hello', $span->getName());
5252
$this->assertSame('http://localhost/hello', $span->getAttributes()->get(TraceAttributes::URL_FULL));
53-
$this->assertCount(5, $span->getEvents());
53+
$this->assertCount(4, $span->getEvents());
5454
$this->assertSame('cache set', $span->getEvents()[0]->getName());
55-
$this->assertSame('Log info', $span->getEvents()[1]->getName());
56-
$this->assertSame('cache miss', $span->getEvents()[2]->getName());
57-
$this->assertSame('cache hit', $span->getEvents()[3]->getName());
58-
$this->assertSame('cache forget', $span->getEvents()[4]->getName());
55+
$this->assertSame('cache miss', $span->getEvents()[1]->getName());
56+
$this->assertSame('cache hit', $span->getEvents()[2]->getName());
57+
$this->assertSame('cache forget', $span->getEvents()[3]->getName());
5958

60-
$span = $this->storage[0];
59+
$span = $this->storage[1];
6160
$this->assertSame('sql SELECT', $span->getName());
6261
$this->assertSame('SELECT', $span->getAttributes()->get('db.operation'));
6362
$this->assertSame(':memory:', $span->getAttributes()->get('db.name'));
6463
$this->assertSame('select 1', $span->getAttributes()->get('db.statement'));
6564
$this->assertSame('sqlite', $span->getAttributes()->get('db.system'));
65+
66+
/** @var \OpenTelemetry\SDK\Logs\ReadWriteLogRecord $logRecord */
67+
$logRecord = $this->storage[0];
68+
$this->assertSame('Log info', $logRecord->getBody());
69+
$this->assertSame('info', $logRecord->getSeverityText());
70+
$this->assertSame(9, $logRecord->getSeverityNumber());
71+
$this->assertArrayHasKey('context', $logRecord->getAttributes()->toArray());
72+
$this->assertSame(json_encode(['test' => true]), $logRecord->getAttributes()->toArray()['context']);
6673
}
6774

6875
public function test_low_cardinality_route_span_name(): void

src/Instrumentation/Laravel/tests/Integration/Queue/QueueTest.php

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,15 @@ public function test_it_handles_pushing_to_a_queue(): void
3838
$logger->info('Logged from closure');
3939
});
4040

41-
$this->assertEquals('sync process', $this->storage[0]->getName());
42-
$this->assertEquals('Task: A', $this->storage[0]->getEvents()[0]->getName());
43-
41+
/** @var \OpenTelemetry\SDK\Logs\ReadWriteLogRecord $logRecord0 */
42+
$logRecord0 = $this->storage[0];
43+
$this->assertEquals('Task: A', $logRecord0->getBody());
4444
$this->assertEquals('sync process', $this->storage[1]->getName());
45-
$this->assertEquals('Logged from closure', $this->storage[1]->getEvents()[0]->getName());
45+
46+
/** @var \OpenTelemetry\SDK\Logs\ReadWriteLogRecord $logRecord2 */
47+
$logRecord2 = $this->storage[2];
48+
$this->assertEquals('Logged from closure', $logRecord2->getBody());
49+
$this->assertEquals('sync process', $this->storage[3]->getName());
4650
}
4751

4852
public function test_it_can_push_a_message_with_a_delay(): void
@@ -51,19 +55,19 @@ public function test_it_can_push_a_message_with_a_delay(): void
5155
$this->queue->later(new DateInterval('PT10M'), new DummyJob('DateInterval'));
5256
$this->queue->later(new DateTimeImmutable('2024-04-15 22:29:00.123Z'), new DummyJob('DateTime'));
5357

54-
$this->assertEquals('sync create', $this->storage[1]->getName());
58+
$this->assertEquals('sync create', $this->storage[2]->getName());
5559
$this->assertIsInt(
56-
$this->storage[1]->getAttributes()->get('messaging.message.delivery_timestamp'),
60+
$this->storage[2]->getAttributes()->get('messaging.message.delivery_timestamp'),
5761
);
5862

59-
$this->assertEquals('sync create', $this->storage[3]->getName());
63+
$this->assertEquals('sync create', $this->storage[5]->getName());
6064
$this->assertIsInt(
61-
$this->storage[3]->getAttributes()->get('messaging.message.delivery_timestamp'),
65+
$this->storage[5]->getAttributes()->get('messaging.message.delivery_timestamp'),
6266
);
6367

64-
$this->assertEquals('sync create', $this->storage[5]->getName());
68+
$this->assertEquals('sync create', $this->storage[8]->getName());
6569
$this->assertIsInt(
66-
$this->storage[5]->getAttributes()->get('messaging.message.delivery_timestamp'),
70+
$this->storage[8]->getAttributes()->get('messaging.message.delivery_timestamp'),
6771
);
6872
}
6973

@@ -141,9 +145,14 @@ public function test_it_drops_empty_receives(): void
141145
}
142146

143147
/** @psalm-suppress PossiblyInvalidMethodCall */
144-
$this->assertEquals(102, $this->storage->count());
148+
$this->assertEquals(204, $this->storage->count());
149+
150+
/** @var \OpenTelemetry\SDK\Logs\ReadWriteLogRecord $logRecord100 */
151+
$logRecord100 = $this->storage[100];
152+
$this->assertEquals('Task: 500', $logRecord100->getBody());
145153

146-
$this->assertEquals('Task: 500', $this->storage[50]->getEvents()[0]->getName());
147-
$this->assertEquals('Task: More work', $this->storage[100]->getEvents()[0]->getName());
154+
/** @var \OpenTelemetry\SDK\Logs\ReadWriteLogRecord $logRecord200 */
155+
$logRecord200 = $this->storage[200];
156+
$this->assertEquals('Task: More work', $logRecord200->getBody());
148157
}
149158
}

src/Instrumentation/Laravel/tests/Integration/TestCase.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,13 @@
77
use ArrayObject;
88
use OpenTelemetry\API\Instrumentation\Configurator;
99
use OpenTelemetry\Context\ScopeInterface;
10+
use OpenTelemetry\SDK\Common\Attribute\Attributes;
11+
use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory;
12+
use OpenTelemetry\SDK\Logs\Exporter\InMemoryExporter as LogInMemoryExporter;
13+
use OpenTelemetry\SDK\Logs\LoggerProvider;
14+
use OpenTelemetry\SDK\Logs\Processor\SimpleLogRecordProcessor;
1015
use OpenTelemetry\SDK\Trace\ImmutableSpan;
11-
use OpenTelemetry\SDK\Trace\SpanExporter\InMemoryExporter;
16+
use OpenTelemetry\SDK\Trace\SpanExporter\InMemoryExporter as SpanInMemoryExporter;
1217
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
1318
use OpenTelemetry\SDK\Trace\TracerProvider;
1419
use Orchestra\Testbench\TestCase as BaseTestCase;
@@ -18,7 +23,9 @@ abstract class TestCase extends BaseTestCase
1823
protected ScopeInterface $scope;
1924
/** @var ArrayObject|ImmutableSpan[] $storage */
2025
protected ArrayObject $storage;
26+
protected ArrayObject $loggerStorage;
2127
protected TracerProvider $tracerProvider;
28+
protected LoggerProvider $loggerProvider;
2229

2330
public function setUp(): void
2431
{
@@ -27,12 +34,20 @@ public function setUp(): void
2734
$this->storage = new ArrayObject();
2835
$this->tracerProvider = new TracerProvider(
2936
new SimpleSpanProcessor(
30-
new InMemoryExporter($this->storage),
37+
new SpanInMemoryExporter($this->storage),
3138
),
3239
);
3340

41+
$this->loggerProvider = new LoggerProvider(
42+
new SimpleLogRecordProcessor(
43+
new LogInMemoryExporter($this->storage),
44+
),
45+
new InstrumentationScopeFactory(Attributes::factory())
46+
);
47+
3448
$this->scope = Configurator::create()
3549
->withTracerProvider($this->tracerProvider)
50+
->withLoggerProvider($this->loggerProvider)
3651
->activate();
3752
}
3853

0 commit comments

Comments
 (0)