Skip to content

Commit 5ea9388

Browse files
authored
Trace attr (#14)
* feat(core): make tracing opt-in per method Previously `#[Trace]` on a class traced all public methods, filtered by include/exclude lists on the class attribute. Method selection now relies solely on the presence of `#[TraceMethod]`, so each method is traced explicitly regardless of visibility. Remove the include/exclude constructor from `Trace`, since scoping is no longer driven by the class attribute. Scan all methods and skip those without `#[TraceMethod]`, moving the attribute lookup into the loop and passing it straight to `scanMethod`. * test(class): align fixtures and tests with opt-in tracing Drop fixtures and cases for the removed include/exclude method filtering and consolidate the per-type argument fixtures onto the shared MixedArgument, since tracing is now opt-in via TraceMethod. Rework MixedVisibility to trace all visibilities and assert every level is hooked. Exclude Fixtures from php-cs-fixer so intentional test shapes aren't reformatted. * docs(readme): reframe messaging around opt-in per-method tracing Rewrite package descriptions and README examples to match the opt-in model shipped in b7e57c9. The old "one tag, full visibility" pitch implied `#[Trace]` alone spans every method, which is no longer true — `#[Trace]` only marks a class and each method needs its own `#[TraceMethod]`. Drop the stale `include`/`exclude` method-selection docs and lead with the value users actually get: capturing what methods received, returned, and threw.
1 parent 5fba849 commit 5ea9388

20 files changed

Lines changed: 88 additions & 387 deletions

.php-cs-fixer.dist.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
$finder = (new PhpCsFixer\Finder())
44
->in([__DIR__ . '/packages', __DIR__ . '/tests'])
5-
->notPath('vendor');
5+
->notPath('vendor')
6+
->exclude('Fixtures');
67

78
return (new PhpCsFixer\Config())
89
->setCacheFile('var/.php-cs-fixer.cache')

packages/core/README.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
[![PHP](https://img.shields.io/packagist/dependency-v/eerzho/opentelemetry-auto-class/php)](https://packagist.org/packages/eerzho/opentelemetry-auto-class)
66
[![License](https://img.shields.io/packagist/l/eerzho/opentelemetry-auto-class)](https://packagist.org/packages/eerzho/opentelemetry-auto-class)
77

8-
One tag, full visibility — every method call in your PHP app shows up in your traces, no boilerplate, no framework required.
8+
Trace what your methods received, returned, and threw — without writing a single span. No framework required.
99

1010
This is a read-only sub-split. Please open issues and pull requests in the [monorepo](https://github.com/eerzho/opentelemetry-auto-class-monorepo).
1111

@@ -40,21 +40,20 @@ class Address
4040
}
4141
```
4242

43-
### 1. `#[Trace]`a span per method
43+
### 1. `#[Trace]`mark a class for tracing
4444

4545
```php
4646
use Eerzho\Instrumentation\Class\Attribute\Trace;
4747

48-
#[Trace(exclude: ['healthCheck'])] // trace every public method but healthCheck
49-
// #[Trace(include: ['pay'])] // or: only pay
48+
#[Trace] // mark the class for tracing
5049
class OrderService
5150
{
5251
public function pay(int $orderId, string $card, Address $address): string {}
5352
public function healthCheck(): bool {}
5453
}
5554
```
5655

57-
### 2. `#[TraceMethod]`capture arguments, return value, and exceptions
56+
### 2. `#[TraceMethod]`trace a method
5857

5958
```php
6059
use Eerzho\Instrumentation\Class\Attribute\TraceMethod;
@@ -64,7 +63,7 @@ use Eerzho\Instrumentation\Class\Attribute\TraceMethod;
6463
public function pay(int $orderId, string $card, Address $address): string {}
6564
```
6665

67-
By default, it captures the arguments and the return value, and records exceptions. Turn each off with `arguments: false`, `return: false`, or `exception: false` (a disabled exception still sets the span status to `ERROR`, only its event is omitted).
66+
A method gets a span with `#[TraceMethod]`. By default, it captures the arguments and the return value, and records exceptions. Turn each off with `arguments: false`, `return: false`, or `exception: false` (a disabled exception still sets the span status to `ERROR`, only its event is omitted).
6867

6968
### 3. `#[TraceProperties]` — expand an object argument
7069

@@ -114,7 +113,7 @@ Each method maps to its `arguments` (`name => position`) plus the `return` and `
114113

115114
### Selecting what to trace
116115

117-
`include` and `exclude` behave the same wherever they appear — `#[Trace]`, `#[TraceMethod]`, `#[TraceProperties]`:
116+
`include` and `exclude` behave the same wherever they appear — `#[TraceMethod]` (arguments) and `#[TraceProperties]` (properties):
118117

119118
| `include` | `exclude` | Result |
120119
|-----------|-----------|-------------------------------------------|
@@ -125,7 +124,7 @@ Each method maps to its `arguments` (`name => position`) plus the `return` and `
125124

126125
An empty `include` means "no allowlist" (everything), **not** "nothing".
127126

128-
Only **public** methods are traced and only **public** properties are expanded — protected and private are ignored.
127+
Only **public** properties are expanded — non-public properties are ignored.
129128

130129
### Argument serialization
131130

@@ -179,7 +178,7 @@ With `exception: false` the status still becomes `ERROR`, but the event above is
179178

180179
1. Skips abstract classes, interfaces, traits, and enums.
181180
2. Reads `#[Trace]` on the class — no attribute, no instrumentation.
182-
3. Collects the public methods allowed by `include` / `exclude`, and for each the arguments, return value, and exception recording configured by `#[TraceMethod]`.
181+
3. Collects every method carrying `#[TraceMethod]`, and for each the arguments, return value, and exception recording it configures.
183182

184183
It returns a `class → method → {arguments, return, exception}` map. `ClassInstrumentation::register()` then installs an `ext-opentelemetry` hook on every mapped method:
185184

packages/core/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "eerzho/opentelemetry-auto-class",
3-
"description": "One tag, full visibility — every method call in your PHP app shows up in your traces, no boilerplate, no framework required.",
3+
"description": "Trace what your methods received, returned, and threw — without writing a single span. No framework required.",
44
"type": "library",
55
"license": "MIT",
66
"keywords": [

packages/core/src/Attribute/Trace.php

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,4 @@
99
#[Attribute(Attribute::TARGET_CLASS)]
1010
final readonly class Trace
1111
{
12-
/**
13-
* @param list<string> $include
14-
* @param list<string> $exclude
15-
*/
16-
public function __construct(
17-
public array $include = [],
18-
public array $exclude = [],
19-
) {
20-
}
2112
}

packages/core/src/AttributeScanner.php

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,15 @@ private static function scanClass(string $class): array
6565
*/
6666
private static function scanMethods(ReflectionClass $class): array
6767
{
68-
$attribute = self::findTrace($class);
69-
if ($attribute === null) {
68+
if (self::findTrace($class) === null) {
7069
return [];
7170
}
7271

7372
$methodsMap = [];
74-
foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
75-
if (self::isAllowed($method->getName(), $attribute->include, $attribute->exclude)) {
76-
$methodsMap[$method->getName()] = self::scanMethod($method);
73+
foreach ($class->getMethods() as $method) {
74+
$attribute = self::findTraceMethod($method);
75+
if ($attribute !== null) {
76+
$methodsMap[$method->getName()] = self::scanMethod($method, $attribute);
7777
}
7878
}
7979

@@ -83,13 +83,8 @@ private static function scanMethods(ReflectionClass $class): array
8383
/**
8484
* @return array{arguments: array<string, int>, return: bool, exception: bool}
8585
*/
86-
private static function scanMethod(ReflectionMethod $method): array
86+
private static function scanMethod(ReflectionMethod $method, TraceMethod $attribute): array
8787
{
88-
$attribute = self::findTraceMethod($method);
89-
if ($attribute === null) {
90-
return ['arguments' => [], 'return' => false, 'exception' => false];
91-
}
92-
9388
$arguments = [];
9489
if ($attribute->arguments) {
9590
foreach ($method->getParameters() as $parameter) {

packages/laravel/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
[![PHP](https://img.shields.io/packagist/dependency-v/eerzho/opentelemetry-auto-class-laravel/php)](https://packagist.org/packages/eerzho/opentelemetry-auto-class-laravel)
66
[![License](https://img.shields.io/packagist/l/eerzho/opentelemetry-auto-class-laravel)](https://packagist.org/packages/eerzho/opentelemetry-auto-class-laravel)
77

8-
One tag, full visibility — every method call in your Laravel app shows up in your traces, zero config.
8+
Trace what your Laravel methods received, returned, and threw — without writing a single span.
99

1010
The Laravel integration for [opentelemetry-auto-class](https://github.com/eerzho/opentelemetry-auto-class) — your classes are discovered and registered automatically.
1111

@@ -52,14 +52,14 @@ use Eerzho\Instrumentation\Class\Attribute\Trace;
5252
use Eerzho\Instrumentation\Class\Attribute\TraceMethod;
5353
use Eerzho\Instrumentation\Class\Attribute\TraceProperties;
5454

55-
#[Trace(exclude: ['healthCheck'])] // trace public methods, but hide "healthCheck"
55+
#[Trace] // mark the class for tracing
5656
class OrderService
5757
{
5858
// span "App\Services\OrderService::pay"
5959
#[TraceMethod(exclude: ['card'])] // hide "card" from the span
6060
public function pay(int $orderId, string $card, Address $address): void {}
6161

62-
public function healthCheck(): bool {}
62+
public function healthCheck(): bool {} // no #[TraceMethod] -> not traced
6363
}
6464

6565
#[TraceProperties(exclude: ['zip'])] // expand public props, but hide "zip"

packages/laravel/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "eerzho/opentelemetry-auto-class-laravel",
3-
"description": "One tag, full visibility — every method call in your Laravel app shows up in your traces, zero config.",
3+
"description": "Trace what your Laravel methods received, returned, and threw — without writing a single span.",
44
"type": "library",
55
"license": "MIT",
66
"keywords": [

packages/symfony/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
[![PHP](https://img.shields.io/packagist/dependency-v/eerzho/opentelemetry-auto-class-symfony/php)](https://packagist.org/packages/eerzho/opentelemetry-auto-class-symfony)
66
[![License](https://img.shields.io/packagist/l/eerzho/opentelemetry-auto-class-symfony)](https://packagist.org/packages/eerzho/opentelemetry-auto-class-symfony)
77

8-
One tag, full visibility — every method call in your Symfony app shows up in your traces, zero config.
8+
Trace what your Symfony methods received, returned, and threw — without writing a single span.
99

1010
The Symfony integration for [opentelemetry-auto-class](https://github.com/eerzho/opentelemetry-auto-class) — your classes are discovered and registered automatically.
1111

@@ -43,14 +43,14 @@ use Eerzho\Instrumentation\Class\Attribute\Trace;
4343
use Eerzho\Instrumentation\Class\Attribute\TraceMethod;
4444
use Eerzho\Instrumentation\Class\Attribute\TraceProperties;
4545

46-
#[Trace(exclude: ['healthCheck'])] // trace public methods, but hide "healthCheck"
46+
#[Trace] // mark the class for tracing
4747
class OrderService
4848
{
4949
// span "App\Service\OrderService::pay"
5050
#[TraceMethod(exclude: ['card'])] // hide "card" from the span
5151
public function pay(int $orderId, string $card, Address $address): void {}
5252

53-
public function healthCheck(): bool {}
53+
public function healthCheck(): bool {} // no #[TraceMethod] -> not traced
5454
}
5555

5656
#[TraceProperties(exclude: ['zip'])] // expand public props, but hide "zip"

packages/symfony/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "eerzho/opentelemetry-auto-class-symfony",
3-
"description": "One tag, full visibility — every method call in your Symfony app shows up in your traces, zero config.",
3+
"description": "Trace what your Symfony methods received, returned, and threw — without writing a single span.",
44
"type": "symfony-bundle",
55
"license": "MIT",
66
"keywords": [

tests/Fixtures/BackedEnumArgument.php

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)