Skip to content

Commit 558ca93

Browse files
authored
Merge branch 'main' into enhance-laravel
2 parents a218139 + ea137c0 commit 558ca93

29 files changed

+4470
-5
lines changed

.github/workflows/php.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ jobs:
5454
'Sampler/RuleBased',
5555
'Shims/OpenTracing',
5656
'Symfony',
57+
'Utils/Test'
5758
]
5859
exclude:
5960

.gitsplit.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ splits:
7878
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/contrib-sampler-rulebased.git"
7979
- prefix: "src/Shims/OpenTracing"
8080
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/contrib-shim-opentracing.git"
81+
- prefix: "src/Utils/Test"
82+
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/contrib-utils-test.git"
8183
# List of references to split (defined as regexp)
8284
origins:
8385
- ^main$

composer.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@
5959
"src/ResourceDetectors/Container/_register.php"
6060
]
6161
},
62+
"autoload-dev": {
63+
"psr-4": {
64+
"OpenTelemetry\\TestUtils\\": "src/",
65+
"OpenTelemetry\\TestUtils\\Tests\\": "tests/"
66+
}
67+
},
6268
"replace": {
6369
"open-telemetry/contrib-aws": "self.version",
6470
"open-telemetry/contrib-sdk-bundle": "self.version",
@@ -81,7 +87,8 @@
8187
"open-telemetry/opentelemetry-logger-monolog": "self.version",
8288
"open-telemetry/detector-container": "self.version",
8389
"open-telemetry/symfony-sdk-bundle": "self.version",
84-
"open-telemetry/opentracing-shim": "self.version"
90+
"open-telemetry/opentracing-shim": "self.version",
91+
"open-telemetry/test-utils": "self.version"
8592
},
8693
"config": {
8794
"sort-packages": true,

docker-compose.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
services:
22
php:
3+
image: opentelemetry-php:local-${PHP_VERSION}-cli
34
build:
45
context: ./docker
56
dockerfile: Dockerfile
67
args:
7-
- PHP_VERSION
8+
- PHP_VERSION:${PHP_VERSION}
89
volumes:
910
- ./:/usr/src/myapp
1011
user: "${PHP_USER}:root"

src/Instrumentation/Doctrine/composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@
2828
"php-http/mock-client": "*",
2929
"phpstan/phpstan": "^1.1",
3030
"phpstan/phpstan-phpunit": "^1.0",
31-
"psalm/plugin-phpunit": "^0.18.4",
31+
"psalm/plugin-phpunit": "^0.19.2",
3232
"open-telemetry/sdk": "^1.0",
3333
"phpunit/phpunit": "^9.5",
34-
"vimeo/psalm": "^5.0"
34+
"vimeo/psalm": "6.4.0"
3535
},
3636
"autoload": {
3737
"psr-4": {
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\Illuminate\Database\Eloquent;
6+
7+
use Illuminate\Database\Eloquent\Model as EloquentModel;
8+
use OpenTelemetry\API\Trace\SpanKind;
9+
use OpenTelemetry\Context\Context;
10+
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\LaravelHook;
11+
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\LaravelHookTrait;
12+
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\PostHookTrait;
13+
use function OpenTelemetry\Instrumentation\hook;
14+
use OpenTelemetry\SemConv\TraceAttributes;
15+
use Throwable;
16+
17+
class Model implements LaravelHook
18+
{
19+
use LaravelHookTrait;
20+
use PostHookTrait;
21+
22+
public function instrument(): void
23+
{
24+
$this->hookFind();
25+
$this->hookPerformInsert();
26+
$this->hookPerformUpdate();
27+
$this->hookDelete();
28+
$this->hookGetModels();
29+
$this->hookDestroy();
30+
$this->hookRefresh();
31+
}
32+
33+
private function hookFind(): void
34+
{
35+
/** @psalm-suppress UnusedFunctionCall */
36+
hook(
37+
\Illuminate\Database\Eloquent\Builder::class,
38+
'find',
39+
pre: function ($builder, array $params, string $class, string $function, ?string $filename, ?int $lineno) {
40+
$model = $builder->getModel();
41+
$builder = $this->instrumentation
42+
->tracer()
43+
->spanBuilder($model::class . '::find')
44+
->setSpanKind(SpanKind::KIND_INTERNAL)
45+
->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function)
46+
->setAttribute(TraceAttributes::CODE_NAMESPACE, $class)
47+
->setAttribute(TraceAttributes::CODE_FILEPATH, $filename)
48+
->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno)
49+
->setAttribute('laravel.eloquent.model', $model::class)
50+
->setAttribute('laravel.eloquent.table', $model->getTable())
51+
->setAttribute('laravel.eloquent.operation', 'find');
52+
53+
$parent = Context::getCurrent();
54+
$span = $builder->startSpan();
55+
Context::storage()->attach($span->storeInContext($parent));
56+
57+
return $params;
58+
},
59+
post: function ($builder, array $params, $result, ?Throwable $exception) {
60+
$this->endSpan($exception);
61+
}
62+
);
63+
}
64+
65+
private function hookPerformUpdate(): void
66+
{
67+
/** @psalm-suppress UnusedFunctionCall */
68+
hook(
69+
EloquentModel::class,
70+
'performUpdate',
71+
pre: function (EloquentModel $model, array $params, string $class, string $function, ?string $filename, ?int $lineno) {
72+
$builder = $this->instrumentation
73+
->tracer()
74+
->spanBuilder($model::class . '::update')
75+
->setSpanKind(SpanKind::KIND_INTERNAL)
76+
->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function)
77+
->setAttribute(TraceAttributes::CODE_NAMESPACE, $class)
78+
->setAttribute(TraceAttributes::CODE_FILEPATH, $filename)
79+
->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno)
80+
->setAttribute('laravel.eloquent.model', $model::class)
81+
->setAttribute('laravel.eloquent.table', $model->getTable())
82+
->setAttribute('laravel.eloquent.operation', 'update');
83+
84+
$parent = Context::getCurrent();
85+
$span = $builder->startSpan();
86+
Context::storage()->attach($span->storeInContext($parent));
87+
88+
return $params;
89+
},
90+
post: function (EloquentModel $model, array $params, $result, ?Throwable $exception) {
91+
$this->endSpan($exception);
92+
}
93+
);
94+
}
95+
96+
private function hookPerformInsert(): void
97+
{
98+
/** @psalm-suppress UnusedFunctionCall */
99+
hook(
100+
EloquentModel::class,
101+
'performInsert',
102+
pre: function (EloquentModel $model, array $params, string $class, string $function, ?string $filename, ?int $lineno) {
103+
$builder = $this->instrumentation
104+
->tracer()
105+
->spanBuilder($model::class . '::create')
106+
->setSpanKind(SpanKind::KIND_INTERNAL)
107+
->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function)
108+
->setAttribute(TraceAttributes::CODE_NAMESPACE, $class)
109+
->setAttribute(TraceAttributes::CODE_FILEPATH, $filename)
110+
->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno)
111+
->setAttribute('laravel.eloquent.model', $model::class)
112+
->setAttribute('laravel.eloquent.table', $model->getTable())
113+
->setAttribute('laravel.eloquent.operation', 'create');
114+
115+
$parent = Context::getCurrent();
116+
$span = $builder->startSpan();
117+
Context::storage()->attach($span->storeInContext($parent));
118+
119+
return $params;
120+
},
121+
post: function (EloquentModel $model, array $params, $result, ?Throwable $exception) {
122+
$this->endSpan($exception);
123+
}
124+
);
125+
}
126+
127+
private function hookDelete(): void
128+
{
129+
/** @psalm-suppress UnusedFunctionCall */
130+
hook(
131+
EloquentModel::class,
132+
'delete',
133+
pre: function (EloquentModel $model, array $params, string $class, string $function, ?string $filename, ?int $lineno) {
134+
$builder = $this->instrumentation
135+
->tracer()
136+
->spanBuilder($model::class . '::delete')
137+
->setSpanKind(SpanKind::KIND_INTERNAL)
138+
->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function)
139+
->setAttribute(TraceAttributes::CODE_NAMESPACE, $class)
140+
->setAttribute(TraceAttributes::CODE_FILEPATH, $filename)
141+
->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno)
142+
->setAttribute('laravel.eloquent.model', $model::class)
143+
->setAttribute('laravel.eloquent.table', $model->getTable())
144+
->setAttribute('laravel.eloquent.operation', 'delete');
145+
146+
$parent = Context::getCurrent();
147+
$span = $builder->startSpan();
148+
Context::storage()->attach($span->storeInContext($parent));
149+
150+
return $params;
151+
},
152+
post: function (EloquentModel $model, array $params, $result, ?Throwable $exception) {
153+
$this->endSpan($exception);
154+
}
155+
);
156+
}
157+
158+
private function hookGetModels(): void
159+
{
160+
/** @psalm-suppress UnusedFunctionCall */
161+
hook(
162+
\Illuminate\Database\Eloquent\Builder::class,
163+
'getModels',
164+
pre: function ($builder, array $params, string $class, string $function, ?string $filename, ?int $lineno) {
165+
$model = $builder->getModel();
166+
$builder = $this->instrumentation
167+
->tracer()
168+
->spanBuilder($model::class . '::get')
169+
->setSpanKind(SpanKind::KIND_INTERNAL)
170+
->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function)
171+
->setAttribute(TraceAttributes::CODE_NAMESPACE, $class)
172+
->setAttribute(TraceAttributes::CODE_FILEPATH, $filename)
173+
->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno)
174+
->setAttribute('laravel.eloquent.model', $model::class)
175+
->setAttribute('laravel.eloquent.table', $model->getTable())
176+
->setAttribute('laravel.eloquent.operation', 'get')
177+
->setAttribute('db.statement', $builder->getQuery()->toSql());
178+
179+
$parent = Context::getCurrent();
180+
$span = $builder->startSpan();
181+
Context::storage()->attach($span->storeInContext($parent));
182+
183+
return $params;
184+
},
185+
post: function ($builder, array $params, $result, ?Throwable $exception) {
186+
$this->endSpan($exception);
187+
}
188+
);
189+
}
190+
191+
private function hookDestroy(): void
192+
{
193+
/** @psalm-suppress UnusedFunctionCall */
194+
hook(
195+
EloquentModel::class,
196+
'destroy',
197+
pre: function ($model, array $params, string $class, string $function, ?string $filename, ?int $lineno) {
198+
$builder = $this->instrumentation
199+
->tracer()
200+
->spanBuilder($model::class . '::destroy')
201+
->setSpanKind(SpanKind::KIND_INTERNAL)
202+
->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function)
203+
->setAttribute(TraceAttributes::CODE_NAMESPACE, $class)
204+
->setAttribute(TraceAttributes::CODE_FILEPATH, $filename)
205+
->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno)
206+
->setAttribute('laravel.eloquent.model', $model::class)
207+
->setAttribute('laravel.eloquent.table', $model->getTable())
208+
->setAttribute('laravel.eloquent.operation', 'destroy');
209+
210+
$parent = Context::getCurrent();
211+
$span = $builder->startSpan();
212+
Context::storage()->attach($span->storeInContext($parent));
213+
214+
return $params;
215+
},
216+
post: function ($model, array $params, $result, ?Throwable $exception) {
217+
$this->endSpan($exception);
218+
}
219+
);
220+
}
221+
222+
private function hookRefresh(): void
223+
{
224+
/** @psalm-suppress UnusedFunctionCall */
225+
hook(
226+
EloquentModel::class,
227+
'refresh',
228+
pre: function (EloquentModel $model, array $params, string $class, string $function, ?string $filename, ?int $lineno) {
229+
$builder = $this->instrumentation
230+
->tracer()
231+
->spanBuilder($model::class . '::refresh')
232+
->setSpanKind(SpanKind::KIND_INTERNAL)
233+
->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function)
234+
->setAttribute(TraceAttributes::CODE_NAMESPACE, $class)
235+
->setAttribute(TraceAttributes::CODE_FILEPATH, $filename)
236+
->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno)
237+
->setAttribute('laravel.eloquent.model', $model::class)
238+
->setAttribute('laravel.eloquent.table', $model->getTable())
239+
->setAttribute('laravel.eloquent.operation', 'refresh');
240+
241+
$parent = Context::getCurrent();
242+
$span = $builder->startSpan();
243+
Context::storage()->attach($span->storeInContext($parent));
244+
245+
return $params;
246+
},
247+
post: function (EloquentModel $model, array $params, $result, ?Throwable $exception) {
248+
$this->endSpan($exception);
249+
}
250+
);
251+
}
252+
}

src/Instrumentation/Laravel/src/LaravelInstrumentation.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public static function register(): void
3333
Hooks\Illuminate\Queue\Worker::hook($instrumentation);
3434
Hooks\Illuminate\Routing\Route::hook($instrumentation);
3535
Hooks\Illuminate\View\View::hook($instrumentation);
36+
Hooks\Illuminate\Database\Eloquent\Model::hook($instrumentation);
3637
}
3738

3839
public static function shouldTraceCli(): bool
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenTelemetry\Tests\Contrib\Instrumentation\Laravel\Fixtures\Models;
6+
7+
use Illuminate\Database\Eloquent\Model;
8+
9+
/**
10+
* @psalm-suppress UnusedClass
11+
*/
12+
class TestModel extends Model
13+
{
14+
protected $table = 'test_models';
15+
protected $fillable = ['name'];
16+
}

0 commit comments

Comments
 (0)