Skip to content

Commit

Permalink
Merge pull request #47 from beberlei/in_process_propagation2_improvem…
Browse files Browse the repository at this point in the history
…ents

Change Pythonic to PHPonic behavior with regard to scopes.
  • Loading branch information
jcchavezs authored Feb 9, 2018
2 parents 8a7ab2d + d1160e1 commit c6c586f
Show file tree
Hide file tree
Showing 15 changed files with 411 additions and 116 deletions.
255 changes: 156 additions & 99 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,134 +26,192 @@ composer require opentracing/opentracing
## Usage

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

### Singleton initialization

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

```php
use OpenTracing\GlobalTracer;
use AnOpenTracingImplementation\MyTracer;

GlobalTracer::set(new MyTracer());
use OpenTracing\GlobalTracer;

GlobalTracer::set(new MyTracerImplementation());
```

### Creating a Span given an existing Request

To start a new `Span`, you can use the `StartSpanFromContext` method.
To start a new `Span`, you can use the `startActiveSpan` method.

```php
use OpenTracing\Formats;
use OpenTracing\GlobalTracer;
use OpenTracing\Formats;
use OpenTracing\GlobalTracer;

...

$spanContext = GlobalTracer::get()->extract(
Formats\HTTP_HEADERS,
getallheaders()
);

function doSomething() {
...

$spanContext = GlobalTracer::get()->extract(
Formats\HTTP_HEADERS,
$request->getHeaders()
);

function doSomething(SpanContext $spanContext, ...) {
...

$span = GlobalTracer::get()->startSpan('my_span', [
'child_of' => $spanContext,
]);

...

$span->log([
'event' => 'soft error',
'type' => 'cache timeout',
'waiter.millis' => 1500,
])

$span->finish();
}
$span = GlobalTracer::get()->startActiveSpan('my_span', ['child_of' => $spanContext]);

...

$span->log([
'event' => 'soft error',
'type' => 'cache timeout',
'waiter.millis' => 1500,
])

$span->finish();
}
```

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

It's always possible to create a "root" `Span` with no parent or other causal
reference.
It's always possible to create a "root" `Span` with no parent or other causal reference.

```php
$span = $tracer->startSpan('my_span');
...
$span->finish();
$span = $tracer->startActiveSpan('my_first_span');
...
$span->finish();
```

### Active Spans and Scope Manager

When using the `Tracer::startActiveSpan` function the underlying tracer uses an
abstraction called scope manager to keep track of the currently active span.

Starting an active span will always use the currently active span as a parent.
If no parent is available, then the newly created span is considered to be the
root span of the trace.

Unless you are using asynchronuous code that tracks multiple spans at the same
time, such as when using cURL Multi Exec or MySQLi Polling you are better
of just using `Tracer::startActiveSpan` everywhere in your application.

The currently active span gets automatically closed and deactivated from the scope
when you call `$span->finish()` as you can see in the previous example.

If you don't want a span to automatically close when `Span::finish()` is called
then you must pass the option `'close_span_on_finish'=> false,` to the `$options`
argument of `startActiveSpan`.

An example of a linear, two level deep span tree using active spans looks like
this in PHP code:

```php
$root = $tracer->startActiveSpan('php');

$controller = $tracer->startActiveSpan('controller');

$http = $tracer->startActiveSpan('http');
file_get_contents('http://php.net');
$http->finish();

$controller->finish();
$root->finish();
```

### Creating a (child) Span given an existing (parent) Span
#### Creating a child span assigning parent manually

```php
function xyz(Span $parentSpan, ...) {
...
$span = GlobalTracer::get()->startSpan(
'my_span',
[
'child_of' => $parentSpan,
]
);

$span->finish();
...
}
$parent = GlobalTracer::get()->startSpan('parent');

$child = GlobalTracer::get()->startSpan('child', [
'child_of' => $parent
]);

...

$child->finish();

...

$parent->finish();
```

#### Creating a child span using automatic active span management

Every new span will take the active span as parent and it will take its spot.

```php
$parent = GlobalTracer::get()->startActiveSpan('parent');

...

/*
* Since the parent span has been created by using startActiveSpan we don't need
* to pass a reference for this child span
*/
$child = GlobalTracer::get()->startActiveSpan('my_second_span');

...

$child->finish();

...

$parent->finish();
```

### Serializing to the wire

```php
use OpenTracing\GlobalTracer;
use OpenTracing\Formats;

...

$tracer = GlobalTracer::get();

$spanContext = $tracer->extract(
use GuzzleHttp\Client;
use OpenTracing\Formats;

...

$tracer = GlobalTracer::get();

$spanContext = $tracer->extract(
Formats\HTTP_HEADERS,
getallheaders()
);

try {
$span = $tracer->startSpan('my_span', ['child_of' => $spanContext]);

$client = new Client;

$headers = [];

$tracer->inject(
$span->getContext(),
Formats\HTTP_HEADERS,
$request->getHeaders()
$headers
);

try {
$span = $tracer->startSpan('my_span', ['child_of' => $spanContext]);

$client = new GuzzleHttp\Client;

$headers = [];

$tracer->inject(
$span->getContext(),
Formats\HTTP_HEADERS,
$headers
);

$request = new \GuzzleHttp\Psr7\Request('GET', 'http://myservice', $headers);
$client->send($request);
...
} catch (\Exception $e) {
...
}
...

$request = new \GuzzleHttp\Psr7\Request('GET', 'http://myservice', $headers);
$client->send($request);
...

} catch (\Exception $e) {
...
}
...
```

### Deserializing from the wire

When using http header for context propagation you can use either the `Request` or the `$_SERVER` variable:
When using http header for context propagation you can use either the `Request` or the `$_SERVER`
variable:

```php
use OpenTracing\GlobalTracer;
use OpenTracing\Formats;

$request = Request::createFromGlobals();
$tracer = GlobalTracer::get();
$spanContext = $tracer->extract(Formats\HTTP_HEADERS, $request->getHeaders());
$tracer->startSpan('my_span', [
'child_of' => $spanContext,
]);
use OpenTracing\GlobalTracer;
use OpenTracing\Formats;

$tracer = GlobalTracer::get();
$spanContext = $tracer->extract(Formats\HTTP_HEADERS, getallheaders());
$tracer->startSpan('my_span', [
'child_of' => $spanContext,
]);
```

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

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

fastcgi_finish_request();

$tracer = GlobalTracer::get();
$tracer->flush(); // release buffer to backend
register_shutdown_function(function() use ($tracer) {
/* Flush the tracer to the backend */
$tracer = GlobalTracer::get();
$tracer->flush();
});
```

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


### Using Span Options

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

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

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

## Coding Style

Opentracing PHP follows the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
OpenTracing PHP follows the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
coding standard and the [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) autoloading standard.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"psr-4": {
"OpenTracing\\": "./src/OpenTracing/"
},
"files": ["./src/OpenTracing/Ext/Tags.php", "./src/OpenTracing/Formats.php"]
"files": ["./src/OpenTracing/Tags.php", "./src/OpenTracing/Formats.php"]
},
"autoload-dev": {
"psr-4": {
Expand Down
12 changes: 12 additions & 0 deletions src/OpenTracing/Exceptions/InvalidSpanOption.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,16 @@ public static function forInvalidReferenceSet($value)
is_object($value) ? get_class($value) : gettype($value)
));
}

/**
* @param mixed $value
* @return InvalidSpanOption
*/
public static function forCloseSpanOnFinish($value)
{
return new self(sprintf(
'Invalid type for close_span_on_finish. Expected bool, got %s',
is_object($value) ? get_class($value) : gettype($value)
));
}
}
6 changes: 3 additions & 3 deletions src/OpenTracing/GlobalTracer.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ final class GlobalTracer
/**
* @var Tracer
*/
private static $instance = null;
private static $instance;

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

return self::$instance;
Expand Down
Loading

0 comments on commit c6c586f

Please sign in to comment.