Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

👷 Laravel instrumentation 1.1.x #269

Open
wants to merge 36 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4c7f2c9
Laravel: removed older hook/register.
ChrisLightfootWild Jun 8, 2024
e2e039a
Laravel: add new Hook interface for SPI.
ChrisLightfootWild Jun 8, 2024
65e413e
Laravel: load Laravel instruments via SPI.
ChrisLightfootWild Jun 8, 2024
1deb2b4
Laravel: watchers accept TracerInterface.
ChrisLightfootWild Jun 8, 2024
98af07f
Laravel: hook Foundation\Application.
ChrisLightfootWild Jun 9, 2024
1ba04c2
Laravel: convert more hooks.
ChrisLightfootWild Jun 9, 2024
f3428c5
Laravel: added LaravelComponentProvider and LaravelConfiguration.
ChrisLightfootWild Jun 9, 2024
bb09763
Laravel: PoC composer changes for SPI.
ChrisLightfootWild Jun 10, 2024
c1ed471
Laravel: register with SPI ServiceLoader in case SPI plugin is not al…
ChrisLightfootWild Jun 19, 2024
3d9beb3
Laravel: enabled spi-config.autoload-files composer config for SPI pl…
ChrisLightfootWild Jun 30, 2024
9788fdd
Merge remote-tracking branch 'upstream/main' into spi/laravel
ChrisLightfootWild Jun 30, 2024
60ba83a
Laravel: fix return type.
ChrisLightfootWild Jul 1, 2024
d5cdeca
Laravel: updates after AutoInstrumentation in API was merged to main.
ChrisLightfootWild Aug 25, 2024
e494ac2
Laravel: use Configuration\ConfigProperties API for instrumentation r…
ChrisLightfootWild Aug 27, 2024
ea2e4bb
Laravel: use updated TraceAttributeValues::MESSAGING_OPERATION_TYPE_*…
ChrisLightfootWild Aug 27, 2024
4231acd
Merge remote-tracking branch 'upstream/main' into spi/laravel
ChrisLightfootWild Aug 30, 2024
ea05ad4
Laravel: added ComponentProvider namespace.
ChrisLightfootWild Oct 2, 2024
d67da56
Laravel: bump otel dependencies to 1.1.
ChrisLightfootWild Oct 2, 2024
190f628
Laravel: respect current way of disabling instrumentation.
ChrisLightfootWild Oct 2, 2024
7412881
Laravel: sem-conv 1.24.
ChrisLightfootWild Oct 2, 2024
d2887bc
Laravel: bump phpunit.
ChrisLightfootWild Oct 2, 2024
cf6deaf
Laravel: tests bootstrap via SPI.
ChrisLightfootWild Oct 2, 2024
c53a6db
Merge remote-tracking branch 'upstream/main' into spi/laravel
ChrisLightfootWild Oct 2, 2024
3eec435
Laravel: skip PHP 8.0 in CI.
ChrisLightfootWild Oct 2, 2024
45a6932
Laravel: lint.
ChrisLightfootWild Oct 2, 2024
ee8cebe
Laravel: nullify missing attributes to reduce noise.
ChrisLightfootWild Oct 2, 2024
a6a677e
Laravel: remove dev-dependencies which are not explicitly required.
ChrisLightfootWild Oct 2, 2024
6a8d0ef
Laravel: bump target_php_version in phan.
ChrisLightfootWild Oct 3, 2024
60fc781
Laravel: suppress PhanTypeMismatchReturn in LaravelComponentProvider.
ChrisLightfootWild Oct 3, 2024
0d7dcf4
Laravel: remove property_exists check that supported Laravel versions…
ChrisLightfootWild Oct 3, 2024
16dc809
Laravel: pass instrumentation Context to hooks
ChrisLightfootWild Oct 24, 2024
fc1df3f
Laravel: suppress PhanDeprecatedClassConstant for deprecated sem-conv…
ChrisLightfootWild Oct 24, 2024
c9a83fe
Laravel: drop ext-opentelemetry hard requirement.
ChrisLightfootWild Oct 24, 2024
44440df
Merge remote-tracking branch 'upstream/main' into spi/laravel
ChrisLightfootWild Oct 25, 2024
a3cf950
Laravel: use TextMapPropagatorInterface from InstrumentationContext i…
ChrisLightfootWild Oct 26, 2024
504796e
Merge remote-tracking branch 'upstream/main' into spi/laravel
ChrisLightfootWild Oct 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 18 additions & 9 deletions src/Instrumentation/Laravel/_register.php
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
<?php
/**
* This file must *only* be used to register SPI components, as it
* will be pruned automatically via the tbachert/spi plugin.
*/

declare(strict_types=1);

use Nevay\SPI\ServiceLoader;
use OpenTelemetry\API\Instrumentation\AutoInstrumentation\Instrumentation;
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks;
use OpenTelemetry\Contrib\Instrumentation\Laravel\LaravelInstrumentation;
use OpenTelemetry\SDK\Sdk;

if (class_exists(Sdk::class) && Sdk::isInstrumentationDisabled(LaravelInstrumentation::NAME) === true) {
return;
}
ServiceLoader::register(Instrumentation::class, LaravelInstrumentation::class);

if (extension_loaded('opentelemetry') === false) {
trigger_error('The opentelemetry extension must be loaded in order to autoload the OpenTelemetry Laravel auto-instrumentation', E_USER_WARNING);
ServiceLoader::register(Hooks\Hook::class, Hooks\Illuminate\Console\Command::class);
ChrisLightfootWild marked this conversation as resolved.
Show resolved Hide resolved

return;
}
ServiceLoader::register(Hooks\Hook::class, Hooks\Illuminate\Contracts\Console\Kernel::class);
ServiceLoader::register(Hooks\Hook::class, Hooks\Illuminate\Contracts\Http\Kernel::class);
ServiceLoader::register(Hooks\Hook::class, Hooks\Illuminate\Contracts\Queue\Queue::class);

LaravelInstrumentation::register();
ServiceLoader::register(Hooks\Hook::class, Hooks\Illuminate\Foundation\Console\ServeCommand::class);
ServiceLoader::register(Hooks\Hook::class, Hooks\Illuminate\Foundation\Application::class);

ServiceLoader::register(Hooks\Hook::class, Hooks\Illuminate\Queue\Queue::class);
ServiceLoader::register(Hooks\Hook::class, Hooks\Illuminate\Queue\SyncQueue::class);
ServiceLoader::register(Hooks\Hook::class, Hooks\Illuminate\Queue\Worker::class);
27 changes: 21 additions & 6 deletions src/Instrumentation/Laravel/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,16 @@
"minimum-stability": "dev",
"prefer-stable": true,
"require": {
"php": "^8.0",
"php": "^8.1",
"ext-json": "*",
"ext-opentelemetry": "*",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed based on similar issue raised for PDO instrumentation.

"laravel/framework": "^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0",
"open-telemetry/api": "^1.0",
"open-telemetry/sem-conv": "^1.24"
ChrisLightfootWild marked this conversation as resolved.
Show resolved Hide resolved
"laravel/framework": "^10.0 || ^11.0",
"open-telemetry/opentelemetry": "dev-auto-instrumentation-registration"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.50",
"guzzlehttp/guzzle": "*",
"nunomaduro/collision": "*",
"open-telemetry/sdk": "^1.0",
"orchestra/testbench": ">=7.41.3",
"phan/phan": "^5.0",
"php-http/mock-client": "*",
Expand All @@ -44,11 +42,28 @@
"OpenTelemetry\\Tests\\Contrib\\Instrumentation\\Laravel\\": "tests/"
}
},
"extra": {
"spi-config": {
"autoload-files": true
},
"spi": {
"OpenTelemetry\\Config\\SDK\\Configuration\\ComponentProvider": [
"OpenTelemetry\\Contrib\\Instrumentation\\Laravel\\LaravelComponentProvider"
]
}
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/brettmc/opentelemetry-php"
}
],
"config": {
"lock": false,
"sort-packages": true,
"allow-plugins": {
"php-http/discovery": false
"php-http/discovery": false,
"tbachert/spi": true
}
}
}
22 changes: 22 additions & 0 deletions src/Instrumentation/Laravel/src/Hooks/Hook.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks;

use OpenTelemetry\API\Instrumentation\AutoInstrumentation\HookManager;
use OpenTelemetry\API\Logs\LoggerInterface;
use OpenTelemetry\API\Metrics\MeterInterface;
use OpenTelemetry\API\Trace\TracerInterface;
use OpenTelemetry\Contrib\Instrumentation\Laravel\LaravelConfiguration;

interface Hook
{
public function instrument(
HookManager $hookManager,
LaravelConfiguration $configuration,
LoggerInterface $logger,
MeterInterface $meter,
TracerInterface $tracer,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I actually be passing the *ProviderInterfaces around?

My current understanding would be that I'd have to duplicate the instantiation or provide a Factory to give me back the implementations I want.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think you should. I also think you should just accept the InstrumentationContext here, and retrieve the providers you need for this particular hook (less rework if we add new providers in future). Also, I think the Tracer/Logger/etc for this hook should have a unique name that includes the component being instrumented, eg io.opentelemetry.contrib.php.laravel.kernel - the reason for this is that we can use scope configuration to turn off parts of auto-instrumentation based on that name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @brettmc, all of that sounds sensible. I will look to make the switch.

I will have to have a tinker with the scope configuration here and see how that goes!

): void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,40 @@
namespace OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\Illuminate\Console;

use Illuminate\Console\Command as IlluminateCommand;
use OpenTelemetry\API\Instrumentation\AutoInstrumentation\HookManager;
use OpenTelemetry\API\Logs\LoggerInterface;
use OpenTelemetry\API\Metrics\MeterInterface;
use OpenTelemetry\API\Trace\Span;
use OpenTelemetry\API\Trace\TracerInterface;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\LaravelHook;
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\LaravelHookTrait;
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\Hook;
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\PostHookTrait;
use function OpenTelemetry\Instrumentation\hook;
use OpenTelemetry\Contrib\Instrumentation\Laravel\LaravelConfiguration;
use OpenTelemetry\SemConv\TraceAttributes;
use Throwable;

class Command implements LaravelHook
class Command implements Hook
{
use LaravelHookTrait;
use PostHookTrait;

public function instrument(): void
{
$this->hookExecute();
public function instrument(
HookManager $hookManager,
LaravelConfiguration $configuration,
LoggerInterface $logger,
MeterInterface $meter,
TracerInterface $tracer,
): void {
$this->hookExecute($hookManager, $tracer);
}

protected function hookExecute(): bool
protected function hookExecute(HookManager $hookManager, TracerInterface $tracer): void
{
return hook(
$hookManager->hook(
IlluminateCommand::class,
'execute',
pre: function (IlluminateCommand $command, array $params, string $class, string $function, ?string $filename, ?int $lineno) {
preHook: function (IlluminateCommand $command, array $params, string $class, string $function, ?string $filename, ?int $lineno) use ($tracer) {
/** @psalm-suppress ArgumentTypeCoercion */
$builder = $this->instrumentation
->tracer()
$builder = $tracer
->spanBuilder(sprintf('Command %s', $command->getName() ?: 'unknown'))
->setAttribute(TraceAttributes::CODE_FUNCTION, $function)
->setAttribute(TraceAttributes::CODE_NAMESPACE, $class)
Expand All @@ -45,7 +51,7 @@ protected function hookExecute(): bool

return $params;
},
post: function (IlluminateCommand $command, array $params, ?int $exitCode, ?Throwable $exception) {
postHook: function (IlluminateCommand $command, array $params, ?int $exitCode, ?Throwable $exception) {
$scope = Context::storage()->scope();
if (!$scope) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,47 @@

use Illuminate\Console\Command;
use Illuminate\Contracts\Console\Kernel as KernelContract;
use OpenTelemetry\API\Instrumentation\AutoInstrumentation\HookManager;
use OpenTelemetry\API\Logs\LoggerInterface;
use OpenTelemetry\API\Metrics\MeterInterface;
use OpenTelemetry\API\Trace\Span;
use OpenTelemetry\API\Trace\SpanKind;
use OpenTelemetry\API\Trace\StatusCode;
use OpenTelemetry\API\Trace\TracerInterface;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\Hook;
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\Illuminate\Queue\AttributesBuilder;
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\LaravelHook;
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\LaravelHookTrait;
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\PostHookTrait;
use OpenTelemetry\Contrib\Instrumentation\Laravel\LaravelConfiguration;
use OpenTelemetry\Contrib\Instrumentation\Laravel\LaravelInstrumentation;
use function OpenTelemetry\Instrumentation\hook;
use OpenTelemetry\SemConv\TraceAttributes;
use Throwable;

class Kernel implements LaravelHook
class Kernel implements Hook
{
use AttributesBuilder;
use LaravelHookTrait;
use PostHookTrait;

public function instrument(): void
{
public function instrument(
HookManager $hookManager,
LaravelConfiguration $configuration,
LoggerInterface $logger,
MeterInterface $meter,
TracerInterface $tracer,
): void {
if (LaravelInstrumentation::shouldTraceCli()) {
$this->hookHandle();
$this->hookHandle($hookManager, $tracer);
}
}

private function hookHandle(): bool
private function hookHandle(HookManager $hookManager, TracerInterface $tracer): void
{
return hook(
$hookManager->hook(
KernelContract::class,
'handle',
pre: function (KernelContract $kernel, array $params, string $class, string $function, ?string $filename, ?int $lineno) {
preHook: function (KernelContract $kernel, array $params, string $class, string $function, ?string $filename, ?int $lineno) use ($tracer) {
/** @psalm-suppress ArgumentTypeCoercion */
$builder = $this->instrumentation
->tracer()
$builder = $tracer
->spanBuilder('Artisan handler')
->setSpanKind(SpanKind::KIND_PRODUCER)
->setAttribute(TraceAttributes::CODE_FUNCTION, $function)
Expand All @@ -54,7 +60,7 @@ private function hookHandle(): bool

return $params;
},
post: function (KernelContract $kernel, array $params, ?int $exitCode, ?Throwable $exception) {
postHook: function (KernelContract $kernel, array $params, ?int $exitCode, ?Throwable $exception) {
$scope = Context::storage()->scope();
if (!$scope) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,47 @@
use Illuminate\Http\Request;
use Illuminate\Routing\Route;
use OpenTelemetry\API\Globals;
use OpenTelemetry\API\Instrumentation\AutoInstrumentation\HookManager;
use OpenTelemetry\API\Logs\LoggerInterface;
use OpenTelemetry\API\Metrics\MeterInterface;
use OpenTelemetry\API\Trace\Span;
use OpenTelemetry\API\Trace\SpanInterface;
use OpenTelemetry\API\Trace\SpanKind;
use OpenTelemetry\API\Trace\StatusCode;
use OpenTelemetry\API\Trace\TracerInterface;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\LaravelHook;
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\LaravelHookTrait;
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\Hook;
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\PostHookTrait;
use OpenTelemetry\Contrib\Instrumentation\Laravel\LaravelConfiguration;
use OpenTelemetry\Contrib\Instrumentation\Laravel\Propagators\HeadersPropagator;
use OpenTelemetry\Contrib\Instrumentation\Laravel\Propagators\ResponsePropagationSetter;
use function OpenTelemetry\Instrumentation\hook;
use OpenTelemetry\SemConv\TraceAttributes;
use Symfony\Component\HttpFoundation\Response;
use Throwable;

class Kernel implements LaravelHook
class Kernel implements Hook
{
use LaravelHookTrait;
use PostHookTrait;

public function instrument(): void
{
$this->hookHandle();
public function instrument(
HookManager $hookManager,
LaravelConfiguration $configuration,
LoggerInterface $logger,
MeterInterface $meter,
TracerInterface $tracer,
): void {
$this->hookHandle($hookManager, $tracer);
}

protected function hookHandle(): bool
protected function hookHandle(HookManager $hookManager, TracerInterface $tracer): void
{
return hook(
$hookManager->hook(
KernelContract::class,
'handle',
pre: function (KernelContract $kernel, array $params, string $class, string $function, ?string $filename, ?int $lineno) {
preHook: function (KernelContract $kernel, array $params, string $class, string $function, ?string $filename, ?int $lineno) use ($tracer) {
$request = ($params[0] instanceof Request) ? $params[0] : null;
/** @psalm-suppress ArgumentTypeCoercion */
$builder = $this->instrumentation
->tracer()
$builder = $tracer
->spanBuilder(sprintf('%s', $request?->method() ?? 'unknown'))
->setSpanKind(SpanKind::KIND_SERVER)
->setAttribute(TraceAttributes::CODE_FUNCTION, $function)
Expand Down Expand Up @@ -75,7 +81,7 @@ protected function hookHandle(): bool

return [$request];
},
post: function (KernelContract $kernel, array $params, ?Response $response, ?Throwable $exception) {
postHook: function (KernelContract $kernel, array $params, ?Response $response, ?Throwable $exception) {
$scope = Context::storage()->scope();
if (!$scope) {
return;
Expand Down
Loading