Skip to content
This repository was archived by the owner on Dec 5, 2025. It is now read-only.

Commit 75fd52d

Browse files
committed
wip
1 parent ea1b2e7 commit 75fd52d

File tree

59 files changed

+2416
-1424
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+2416
-1424
lines changed

.cursorrules

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

README.md

Lines changed: 92 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,24 @@
55

66
This package provides a simple way to add OpenTelemetry to your Laravel application.
77

8+
## ⚠️ Breaking Changes in Recent Versions
9+
10+
**SpanBuilder API Changes**: The `SpanBuilder::start()` method behavior has been updated for better safety and predictability:
11+
12+
- **Before**: `start()` automatically activated the span's scope, which could cause issues in async scenarios
13+
- **Now**: `start()` only creates the span without activating its scope (safer default behavior)
14+
- **Migration**: If you need the old behavior, use `startAndActivate()` instead of `start()`
15+
16+
```php
17+
// Old code (if you need scope activation)
18+
$span = Measure::span('my-operation')->start(); // This now returns SpanInterface
19+
20+
// New code (for scope activation)
21+
$startedSpan = Measure::span('my-operation')->startAndActivate(); // Returns StartedSpan
22+
```
23+
24+
For most use cases, the new `start()` behavior is safer and recommended. See the [Advanced Span Creation](#advanced-span-creation-with-spanbuilder) section for detailed usage patterns.
25+
826
## Features
927

1028
-**Zero Configuration**: Works out of the box with sensible defaults.
@@ -142,38 +160,96 @@ The `trace` method will:
142160
- Automatically record and re-throw any exceptions that occur within the callback.
143161
- End the span when the callback completes.
144162

163+
### Advanced Span Creation with SpanBuilder
164+
165+
For more control over span lifecycle, you can use the `SpanBuilder` directly through `Measure::span()`. The SpanBuilder provides several methods for different use cases:
166+
167+
#### Basic Span Creation (Recommended for most cases)
168+
169+
```php
170+
// Create a span without activating its scope (safer for async operations)
171+
$span = Measure::span('my-operation')
172+
->setAttribute('operation.type', 'data-processing')
173+
->setSpanKind(SpanKind::KIND_INTERNAL)
174+
->start(); // Returns SpanInterface
175+
176+
// Your business logic here
177+
$result = $this->processData();
178+
179+
// Remember to end the span manually
180+
$span->end();
181+
```
182+
183+
#### Span with Activated Scope
184+
185+
```php
186+
// Create a span and activate its scope (for nested operations)
187+
$startedSpan = Measure::span('parent-operation')
188+
->setAttribute('operation.type', 'user-workflow')
189+
->setSpanKind(SpanKind::KIND_INTERNAL)
190+
->startAndActivate(); // Returns StartedSpan
191+
192+
// Any spans created within this block will be children of this span
193+
$childSpan = Measure::span('child-operation')->start();
194+
$childSpan->end();
195+
196+
// The StartedSpan automatically manages scope cleanup
197+
$startedSpan->end(); // Ends span and detaches scope
198+
```
199+
200+
#### Span with Context (For Manual Propagation)
201+
202+
```php
203+
// Create a span and get both span and context for manual management
204+
[$span, $context] = Measure::span('async-operation')
205+
->setAttribute('operation.async', true)
206+
->startWithContext(); // Returns [SpanInterface, ContextInterface]
207+
208+
// Use context for propagation (e.g., in HTTP headers)
209+
$headers = Measure::propagationHeaders($context);
210+
211+
// Your async operation here
212+
$span->end();
213+
```
214+
145215
### Using Semantic Spans
146216

147217
To promote standardization, the package provides semantic helper methods that create spans with attributes conforming to OpenTelemetry's [Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/).
148218

149219
#### Database Spans
150220
```php
151-
use OpenTelemetry\SemConv\TraceAttributes;
152-
153221
// Manually trace a block of database operations
154-
$user = Measure::database('repository:find-user', function ($span) use ($userId) {
155-
$span->setAttribute(TraceAttributes::DB_STATEMENT, "SELECT * FROM users WHERE id = ?");
222+
$user = Measure::database('SELECT', 'users'); // Quick shortcut for database operations
223+
// Or use the general trace method for more complex operations
224+
$user = Measure::trace('repository:find-user', function ($span) use ($userId) {
225+
$span->setAttribute('db.statement', "SELECT * FROM users WHERE id = ?");
226+
$span->setAttribute('db.table', 'users');
156227
return User::find($userId);
157228
});
158229
```
159230
*Note: If `QueryWatcher` is enabled, individual queries are already traced. This is useful for tracing a larger transaction or a specific business operation involving multiple queries.*
160231

161-
#### Cache Spans
232+
#### HTTP Client Spans
162233
```php
163-
$user = Measure::cache('fetch-user-from-cache', function ($span) use ($userId) {
164-
$span->setAttributes([
165-
'cache.key' => "user:{$userId}",
166-
'cache.ttl' => 3600,
167-
]);
168-
return Cache::remember("user:{$userId}", 3600, fn() => User::find($userId));
234+
// Quick shortcut for HTTP client requests
235+
$response = Measure::httpClient('POST', 'https://api.example.com/users');
236+
// Or use the general trace method for more control
237+
$response = Measure::trace('api-call', function ($span) {
238+
$span->setAttribute('http.method', 'POST');
239+
$span->setAttribute('http.url', 'https://api.example.com/users');
240+
return Http::post('https://api.example.com/users', $data);
169241
});
170242
```
171243

172-
#### Queue Spans
244+
#### Custom Spans
173245
```php
174-
// Manually trace putting a job on the queue
175-
Measure::queue('dispatch-welcome-email', function() use ($user) {
176-
WelcomeEmailJob::dispatch($user);
246+
// For any custom operation, use the general trace method
247+
$result = Measure::trace('process-payment', function ($span) use ($payment) {
248+
$span->setAttribute('payment.amount', $payment->amount);
249+
$span->setAttribute('payment.currency', $payment->currency);
250+
251+
// Your business logic here
252+
return $this->processPayment($payment);
177253
});
178254
```
179255

@@ -221,7 +297,7 @@ Or apply it globally in `app/Http/Kernel.php`:
221297
protected $middlewareGroups = [
222298
'web' => [
223299
// ...
224-
\Overtrue\LaravelOpenTelemetry\Http\Middleware\TraceIdMiddleware::class,
300+
\Overtrue\LaravelOpenTelemetry\Http\Middleware\AddTraceId::class,
225301
],
226302
// ...
227303
];

config/otel.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@
2929
],
3030
],
3131

32+
/**
33+
* HTTP Client Configuration
34+
*/
35+
'http_client' => [
36+
/**
37+
* Global Request Middleware Configuration
38+
* Automatically adds OpenTelemetry propagation headers to all HTTP requests
39+
*/
40+
'propagation_middleware' => [
41+
'enabled' => env('OTEL_HTTP_CLIENT_PROPAGATION_ENABLED', true),
42+
],
43+
],
44+
3245
/**
3346
* Watchers Configuration
3447
*
@@ -45,7 +58,7 @@
4558
'watchers' => [
4659
\Overtrue\LaravelOpenTelemetry\Watchers\CacheWatcher::class,
4760
\Overtrue\LaravelOpenTelemetry\Watchers\QueryWatcher::class,
48-
\Overtrue\LaravelOpenTelemetry\Watchers\HttpClientWatcher::class,
61+
\Overtrue\LaravelOpenTelemetry\Watchers\HttpClientWatcher::class, // 已添加智能重复检测,可以同时使用
4962
\Overtrue\LaravelOpenTelemetry\Watchers\ExceptionWatcher::class,
5063
\Overtrue\LaravelOpenTelemetry\Watchers\AuthenticateWatcher::class,
5164
\Overtrue\LaravelOpenTelemetry\Watchers\EventWatcher::class,

examples/configuration_guide.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
/**
4+
* Laravel OpenTelemetry Configuration Guide
5+
*
6+
* This file demonstrates how to use the new HTTP client configuration options
7+
*/
8+
9+
// 1. Check if OpenTelemetry is enabled
10+
if (config('otel.enabled', true)) {
11+
echo "OpenTelemetry is enabled\n";
12+
} else {
13+
echo "OpenTelemetry is disabled\n";
14+
}
15+
16+
// 2. Check tracer name
17+
$tracerName = config('otel.tracer_name', 'overtrue.laravel-open-telemetry');
18+
echo "Tracer name: {$tracerName}\n";
19+
20+
// 3. Check middleware configuration
21+
$traceIdEnabled = config('otel.middleware.trace_id.enabled', true);
22+
$traceIdGlobal = config('otel.middleware.trace_id.global', true);
23+
$traceIdHeaderName = config('otel.middleware.trace_id.header_name', 'X-Trace-Id');
24+
25+
echo "Trace ID Middleware enabled: " . ($traceIdEnabled ? 'Yes' : 'No') . "\n";
26+
echo "Trace ID Middleware global: " . ($traceIdGlobal ? 'Yes' : 'No') . "\n";
27+
echo "Trace ID Header name: {$traceIdHeaderName}\n";
28+
29+
// 4. Check new HTTP client configuration
30+
$httpClientPropagationEnabled = config('otel.http_client.propagation_middleware.enabled', true);
31+
echo "HTTP Client propagation middleware enabled: " . ($httpClientPropagationEnabled ? 'Yes' : 'No') . "\n";
32+
33+
// 5. View all available watchers
34+
$watchers = config('otel.watchers', []);
35+
echo "Available watchers:\n";
36+
foreach ($watchers as $watcher) {
37+
echo " - {$watcher}\n";
38+
}
39+
40+
// 6. Environment variable configuration examples
41+
echo "\n=== Environment Variable Examples ===\n";
42+
echo "OTEL_ENABLED=true\n";
43+
echo "OTEL_TRACER_NAME=my-app\n";
44+
echo "OTEL_TRACE_ID_MIDDLEWARE_ENABLED=true\n";
45+
echo "OTEL_TRACE_ID_MIDDLEWARE_GLOBAL=true\n";
46+
echo "OTEL_TRACE_ID_HEADER_NAME=X-Custom-Trace-Id\n";
47+
echo "OTEL_HTTP_CLIENT_PROPAGATION_ENABLED=true\n";
48+
49+
// 7. Demonstrate how to use in code
50+
use Overtrue\LaravelOpenTelemetry\Facades\Measure;
51+
use Illuminate\Support\Facades\Http;
52+
53+
// Fully automatic HTTP request tracing
54+
// No manual code needed - all requests through Http facade are automatically traced with context propagation
55+
$response = Http::get('https://httpbin.org/ip');
56+
57+
// View tracing status
58+
$status = Measure::getStatus();
59+
echo "\n=== Tracing Status ===\n";
60+
echo "Recording: " . ($status['is_recording'] ? 'Yes' : 'No') . "\n";
61+
echo "Current trace ID: " . ($status['current_trace_id'] ?? 'None') . "\n";
62+
echo "Active spans count: " . $status['active_spans_count'] . "\n";
63+
echo "Tracer provider: " . $status['tracer_provider']['class'] . "\n";
64+
65+
// 8. How to disable HTTP client propagation middleware
66+
echo "\n=== How to Disable HTTP Client Propagation ===\n";
67+
echo "In your .env file, set:\n";
68+
echo "OTEL_HTTP_CLIENT_PROPAGATION_ENABLED=false\n";
69+
echo "\nOr in config/otel.php:\n";
70+
echo "'http_client' => [\n";
71+
echo " 'propagation_middleware' => [\n";
72+
echo " 'enabled' => false,\n";
73+
echo " ],\n";
74+
echo "],\n";

0 commit comments

Comments
 (0)