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

Commit c6c586f

Browse files
authored
Merge pull request #47 from beberlei/in_process_propagation2_improvements
Change Pythonic to PHPonic behavior with regard to scopes.
2 parents 8a7ab2d + d1160e1 commit c6c586f

File tree

15 files changed

+411
-116
lines changed

15 files changed

+411
-116
lines changed

README.md

Lines changed: 156 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -26,134 +26,192 @@ composer require opentracing/opentracing
2626
## Usage
2727

2828
When consuming this library one really only need to worry about a couple of key
29-
abstractions: the `Tracer::startSpan` method, the `Span` interface, and binding
30-
a `Tracer` at bootstrap time. Here are code snippets demonstrating some important
31-
use cases:
29+
abstractions: the `Tracer::startActiveSpan` and `Tracer::startSpan` method,
30+
the `Span` interface, and binding a `Tracer` at bootstrap time. Here are code snippets
31+
demonstrating some important use cases:
3232

3333
### Singleton initialization
3434

3535
The simplest starting point is to set the global tracer. As early as possible, do:
3636

3737
```php
38-
use OpenTracing\GlobalTracer;
39-
use AnOpenTracingImplementation\MyTracer;
40-
41-
GlobalTracer::set(new MyTracer());
38+
use OpenTracing\GlobalTracer;
39+
40+
GlobalTracer::set(new MyTracerImplementation());
4241
```
4342

4443
### Creating a Span given an existing Request
4544

46-
To start a new `Span`, you can use the `StartSpanFromContext` method.
45+
To start a new `Span`, you can use the `startActiveSpan` method.
4746

4847
```php
49-
use OpenTracing\Formats;
50-
use OpenTracing\GlobalTracer;
48+
use OpenTracing\Formats;
49+
use OpenTracing\GlobalTracer;
50+
51+
...
52+
53+
$spanContext = GlobalTracer::get()->extract(
54+
Formats\HTTP_HEADERS,
55+
getallheaders()
56+
);
5157

58+
function doSomething() {
5259
...
5360

54-
$spanContext = GlobalTracer::get()->extract(
55-
Formats\HTTP_HEADERS,
56-
$request->getHeaders()
57-
);
58-
59-
function doSomething(SpanContext $spanContext, ...) {
60-
...
61-
62-
$span = GlobalTracer::get()->startSpan('my_span', [
63-
'child_of' => $spanContext,
64-
]);
65-
66-
...
67-
68-
$span->log([
69-
'event' => 'soft error',
70-
'type' => 'cache timeout',
71-
'waiter.millis' => 1500,
72-
])
73-
74-
$span->finish();
75-
}
61+
$span = GlobalTracer::get()->startActiveSpan('my_span', ['child_of' => $spanContext]);
62+
63+
...
64+
65+
$span->log([
66+
'event' => 'soft error',
67+
'type' => 'cache timeout',
68+
'waiter.millis' => 1500,
69+
])
70+
71+
$span->finish();
72+
}
7673
```
7774

7875
### Starting an empty trace by creating a "root span"
7976

80-
It's always possible to create a "root" `Span` with no parent or other causal
81-
reference.
77+
It's always possible to create a "root" `Span` with no parent or other causal reference.
8278

8379
```php
84-
$span = $tracer->startSpan('my_span');
85-
...
86-
$span->finish();
80+
$span = $tracer->startActiveSpan('my_first_span');
81+
...
82+
$span->finish();
83+
```
84+
85+
### Active Spans and Scope Manager
86+
87+
When using the `Tracer::startActiveSpan` function the underlying tracer uses an
88+
abstraction called scope manager to keep track of the currently active span.
89+
90+
Starting an active span will always use the currently active span as a parent.
91+
If no parent is available, then the newly created span is considered to be the
92+
root span of the trace.
93+
94+
Unless you are using asynchronuous code that tracks multiple spans at the same
95+
time, such as when using cURL Multi Exec or MySQLi Polling you are better
96+
of just using `Tracer::startActiveSpan` everywhere in your application.
97+
98+
The currently active span gets automatically closed and deactivated from the scope
99+
when you call `$span->finish()` as you can see in the previous example.
100+
101+
If you don't want a span to automatically close when `Span::finish()` is called
102+
then you must pass the option `'close_span_on_finish'=> false,` to the `$options`
103+
argument of `startActiveSpan`.
104+
105+
An example of a linear, two level deep span tree using active spans looks like
106+
this in PHP code:
107+
108+
```php
109+
$root = $tracer->startActiveSpan('php');
110+
111+
$controller = $tracer->startActiveSpan('controller');
112+
113+
$http = $tracer->startActiveSpan('http');
114+
file_get_contents('http://php.net');
115+
$http->finish();
116+
117+
$controller->finish();
118+
$root->finish();
87119
```
88120

89-
### Creating a (child) Span given an existing (parent) Span
121+
#### Creating a child span assigning parent manually
90122

91123
```php
92-
function xyz(Span $parentSpan, ...) {
93-
...
94-
$span = GlobalTracer::get()->startSpan(
95-
'my_span',
96-
[
97-
'child_of' => $parentSpan,
98-
]
99-
);
100-
101-
$span->finish();
102-
...
103-
}
124+
$parent = GlobalTracer::get()->startSpan('parent');
125+
126+
$child = GlobalTracer::get()->startSpan('child', [
127+
'child_of' => $parent
128+
]);
129+
130+
...
131+
132+
$child->finish();
133+
134+
...
135+
136+
$parent->finish();
137+
```
138+
139+
#### Creating a child span using automatic active span management
140+
141+
Every new span will take the active span as parent and it will take its spot.
142+
143+
```php
144+
$parent = GlobalTracer::get()->startActiveSpan('parent');
145+
146+
...
147+
148+
/*
149+
* Since the parent span has been created by using startActiveSpan we don't need
150+
* to pass a reference for this child span
151+
*/
152+
$child = GlobalTracer::get()->startActiveSpan('my_second_span');
153+
154+
...
155+
156+
$child->finish();
157+
158+
...
159+
160+
$parent->finish();
104161
```
105162

106163
### Serializing to the wire
107164

108165
```php
109-
use OpenTracing\GlobalTracer;
110-
use OpenTracing\Formats;
111-
112-
...
113-
114-
$tracer = GlobalTracer::get();
115-
116-
$spanContext = $tracer->extract(
166+
use GuzzleHttp\Client;
167+
use OpenTracing\Formats;
168+
169+
...
170+
171+
$tracer = GlobalTracer::get();
172+
173+
$spanContext = $tracer->extract(
174+
Formats\HTTP_HEADERS,
175+
getallheaders()
176+
);
177+
178+
try {
179+
$span = $tracer->startSpan('my_span', ['child_of' => $spanContext]);
180+
181+
$client = new Client;
182+
183+
$headers = [];
184+
185+
$tracer->inject(
186+
$span->getContext(),
117187
Formats\HTTP_HEADERS,
118-
$request->getHeaders()
188+
$headers
119189
);
120-
121-
try {
122-
$span = $tracer->startSpan('my_span', ['child_of' => $spanContext]);
123-
124-
$client = new GuzzleHttp\Client;
125-
126-
$headers = [];
127-
128-
$tracer->inject(
129-
$span->getContext(),
130-
Formats\HTTP_HEADERS,
131-
$headers
132-
);
133-
134-
$request = new \GuzzleHttp\Psr7\Request('GET', 'http://myservice', $headers);
135-
$client->send($request);
136-
...
137-
} catch (\Exception $e) {
138-
...
139-
}
140-
...
190+
191+
$request = new \GuzzleHttp\Psr7\Request('GET', 'http://myservice', $headers);
192+
$client->send($request);
193+
...
194+
195+
} catch (\Exception $e) {
196+
...
197+
}
198+
...
141199
```
142200

143201
### Deserializing from the wire
144202

145-
When using http header for context propagation you can use either the `Request` or the `$_SERVER` variable:
203+
When using http header for context propagation you can use either the `Request` or the `$_SERVER`
204+
variable:
146205

147206
```php
148-
use OpenTracing\GlobalTracer;
149-
use OpenTracing\Formats;
150-
151-
$request = Request::createFromGlobals();
152-
$tracer = GlobalTracer::get();
153-
$spanContext = $tracer->extract(Formats\HTTP_HEADERS, $request->getHeaders());
154-
$tracer->startSpan('my_span', [
155-
'child_of' => $spanContext,
156-
]);
207+
use OpenTracing\GlobalTracer;
208+
use OpenTracing\Formats;
209+
210+
$tracer = GlobalTracer::get();
211+
$spanContext = $tracer->extract(Formats\HTTP_HEADERS, getallheaders());
212+
$tracer->startSpan('my_span', [
213+
'child_of' => $spanContext,
214+
]);
157215
```
158216

159217
### Flushing Spans
@@ -167,31 +225,30 @@ cause problems for Tracer implementations. This is why the PHP API contains a
167225
```php
168226
use OpenTracing\GlobalTracer;
169227

170-
// Do application work, buffer spans in memory
171228
$application->run();
172229

173-
fastcgi_finish_request();
174-
175-
$tracer = GlobalTracer::get();
176-
$tracer->flush(); // release buffer to backend
230+
register_shutdown_function(function() use ($tracer) {
231+
/* Flush the tracer to the backend */
232+
$tracer = GlobalTracer::get();
233+
$tracer->flush();
234+
});
177235
```
178236

179237
This is optional, tracers can decide to immediately send finished spans to a
180238
backend. The flush call can be implemented as a NO-OP for these tracers.
181239

182-
183240
### Using Span Options
184241

185242
Passing options to the pass can be done using either an array or the
186243
SpanOptions wrapper object. The following keys are valid:
187244

188245
- `start_time` is a float, int or `\DateTime` representing a timestamp with arbitrary precision.
189246
- `child_of` is an object of type `OpenTracing\SpanContext` or `OpenTracing\Span`.
190-
- `references` is an array of `OpenTracing\Reference`.
247+
- `references` is an array of `OpenTracing\Reference`.
191248
- `tags` is an array with string keys and scalar values that represent OpenTracing tags.
192249

193250
```php
194-
$span = $tracer->createSpan('my_span', [
251+
$span = $tracer->startActiveSpan('my_span', [
195252
'child_of' => $spanContext,
196253
'tags' => ['foo' => 'bar'],
197254
'start_time' => time(),
@@ -217,5 +274,5 @@ Tracers will throw an exception if the requested format is not handled by them.
217274

218275
## Coding Style
219276

220-
Opentracing PHP follows the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
277+
OpenTracing PHP follows the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
221278
coding standard and the [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) autoloading standard.

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"psr-4": {
2222
"OpenTracing\\": "./src/OpenTracing/"
2323
},
24-
"files": ["./src/OpenTracing/Ext/Tags.php", "./src/OpenTracing/Formats.php"]
24+
"files": ["./src/OpenTracing/Tags.php", "./src/OpenTracing/Formats.php"]
2525
},
2626
"autoload-dev": {
2727
"psr-4": {

src/OpenTracing/Exceptions/InvalidSpanOption.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,16 @@ public static function forInvalidReferenceSet($value)
9595
is_object($value) ? get_class($value) : gettype($value)
9696
));
9797
}
98+
99+
/**
100+
* @param mixed $value
101+
* @return InvalidSpanOption
102+
*/
103+
public static function forCloseSpanOnFinish($value)
104+
{
105+
return new self(sprintf(
106+
'Invalid type for close_span_on_finish. Expected bool, got %s',
107+
is_object($value) ? get_class($value) : gettype($value)
108+
));
109+
}
98110
}

src/OpenTracing/GlobalTracer.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ final class GlobalTracer
77
/**
88
* @var Tracer
99
*/
10-
private static $instance = null;
10+
private static $instance;
1111

1212
/**
1313
* GlobalTracer::set sets the [singleton] Tracer returned by get().
1414
* Those who use GlobalTracer (rather than directly manage a Tracer instance)
1515
* should call GlobalTracer::set as early as possible in bootstrap, prior to
1616
* start a new span. Prior to calling GlobalTracer::set, any Spans started
17-
* via the `Tracer::startSpan` (etc) globals are noops.
17+
* via the `Tracer::startActiveSpan` (etc) globals are noops.
1818
*
1919
* @param Tracer $tracer
2020
*/
@@ -33,7 +33,7 @@ public static function set(Tracer $tracer)
3333
public static function get()
3434
{
3535
if (self::$instance === null) {
36-
self::$instance = NoopTracer::create();
36+
self::$instance = Tracer::create();
3737
}
3838

3939
return self::$instance;

0 commit comments

Comments
 (0)