Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In process propagation #20

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 39 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ The simplest starting point is to set the global tracer. As early as possible, d

### 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You name it startActiveSpan here and then the example uses startManualSpan though. Is this right?


```php
use Psr\Http\Message\RequestInterface;
Expand All @@ -57,9 +57,7 @@ To start a new `Span`, you can use the `StartSpanFromContext` method.
function doSomething(SpanContext $spanContext, ...) {
...

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

...

Expand All @@ -75,35 +73,52 @@ To start a new `Span`, you can use the `StartSpanFromContext` method.

### 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 = $tracer->startActiveSpan('my_first_span');
...
$span->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' => $spanContext,
]
);

$span->finish();
...
}
use OpenTracing\SpanReference\ChildOf;

$parent = GlobalTracer::get()->startManualSpan('parent');

$child = GlobalTracer::get()->startManualSpan('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 GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use OpenTracing\Carriers\HttpHeaders as HttpHeadersCarrier;
use OpenTracing\Context;
use OpenTracing\GlobalTracer;
Expand All @@ -118,11 +133,11 @@ reference.
);

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

$client = new GuzzleHttp\Client;
$client = new Client;

$request = new \GuzzleHttp\Psr7\Request('GET', 'http://myservice');
$request = new Request('GET', 'http://myservice');

$tracer->inject(
$span->context(),
Expand Down Expand Up @@ -163,11 +178,8 @@ cause problems for Tracer implementations. This is why the PHP API contains a
`flush` method that allows to trigger a span sending out of process.

```php
<?php

use OpenTracing\GlobalTracer;

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

fastcgi_finish_request();
Expand All @@ -179,7 +191,6 @@ $tracer->flush(); // release buffer to backend
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
Expand All @@ -191,8 +202,6 @@ SpanOptions wrapper object. The following keys are valid:
- `tags` is an array with string keys and scalar values that represent OpenTracing tags.

```php
<?php

use OpenTracing\Reference;

$span = $tracer->createSpan('my_span', [
Expand Down Expand Up @@ -221,5 +230,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.
40 changes: 40 additions & 0 deletions src/OpenTracing/ActiveSpanSource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace OpenTracing;

/**
* Keeps track of the current active `Span`.
*/
interface ActiveSpanSource
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we shift the ActiveSpanSource interface, why not shift a ActiveSpanSource implementation?

In my opinion, the ActiveSpanSource is only like a container. And only one implementation is enough.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I understand it this interface would be important to implement for event loops

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jcchavezs is that correct?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I simplified this piece in #45

{
/**
* Activates an `Span`, so that it is used as a parent when creating new spans.
* The implementation must keep track of the active spans sequence, so
* that previous spans can be resumed after a deactivation.
*
* @param Span $span
*/
public function activate(Span $span);

/**
* Returns current active `Span`.
*
* @return Span
*/
public function getActiveSpan();

/**
* Deactivate the given `Span`, restoring the previous active one.
*
* This method must take in consideration that a `Span` may be deactivated
* when it's not really active. In that case, the current active stack
* must not be changed (idempotency).
*
* Do not confuse it with the finish concept:
* - $tracer->getActiveSpanSource()->deactivate($span) the span is not active but still "running"
* - $span->finish() the span is finished and deactivated
*
* @param Span $span
*/
public function deactivate(Span $span);
}
2 changes: 1 addition & 1 deletion src/OpenTracing/GlobalTracer.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ final class GlobalTracer
* 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 Down
24 changes: 24 additions & 0 deletions src/OpenTracing/NoopActiveSpanSource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace OpenTracing;

final class NoopActiveSpanSource implements ActiveSpanSource
{
public static function create()
{
return new self();
}

public function activate(Span $span)
{
}

public function getActiveSpan()
{
return NoopSpan::create();
}

public function deactivate(Span $span)
{
}
}
3 changes: 3 additions & 0 deletions src/OpenTracing/NoopSpan.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public function finish($finishTime = null, array $logRecords = [])
{
}

/**
* {@inheritdoc}
*/
public function overwriteOperationName($newOperationName)
{
}
Expand Down
32 changes: 32 additions & 0 deletions src/OpenTracing/NoopTracer.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@ public static function create()
* {@inheritdoc}
*/
public function startSpan($operationName, $options = [])
{
}

/**
* {@inheritdoc}
*/
public function startActiveSpan($operationName, $options = [])
{

return NoopSpan::create();
}

/**
* {@inheritdoc}
*/
public function startManualSpan($operationName, $options = [])
{
return NoopSpan::create();
}
Expand All @@ -41,4 +57,20 @@ public function extract($format, Reader $carrier)
public function flush()
{
}

/**
* {@inheritdoc}
*/
public function getActiveSpanSource()
{
return NoopActiveSpanSource::create();
}

/**
* {@inheritdoc}
*/
public function getActiveSpan()
{
return NoopSpan::create();
}
}
13 changes: 10 additions & 3 deletions src/OpenTracing/Span.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,19 @@ public function getContext();
/**
* Sets the end timestamp and finalizes Span state.
*
* With the exception of calls to Context() (which are always allowed),
* With the exception of calls to getContext() (which are always allowed),
* finish() must be the last call made to any span instance, and to do
* otherwise leads to undefined behavior
* otherwise leads to undefined behavior but not returning an exception.
*
* As an implementor, make sure you call {@see Tracer::deactivate()}
* otherwise new spans might try to be child of this one.
*
* If the span is already finished, a warning should be logged.
*
* @param float|int|\DateTimeInterface|null $finishTime if passing float or int
* it should represent the timestamp (including as many decimal places as you need)
* @param array $logRecords
* @return void
*/
public function finish($finishTime = null, array $logRecords = []);

Expand All @@ -49,6 +53,7 @@ public function overwriteOperationName($newOperationName);
* If the span is already finished, a warning should be logged.
*
* @param array $tags
* @return void
*/
public function setTags(array $tags);

Expand All @@ -60,6 +65,7 @@ public function setTags(array $tags);
*
* @param array $fields
* @param int|float|\DateTimeInterface $timestamp
* @return void
*/
public function log(array $fields = [], $timestamp = null);

Expand All @@ -71,12 +77,13 @@ public function log(array $fields = [], $timestamp = null);
*
* @param string $key
* @param string $value
* @return void
*/
public function addBaggageItem($key, $value);

/**
* @param string $key
* @return string
* @return string|null returns null when there is not a item under the provided key
*/
public function getBaggageItem($key);
}
2 changes: 1 addition & 1 deletion src/OpenTracing/SpanOptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ final class SpanOptions
private $tags = [];

/**
* @var int|float|\DateTime
* @var int|float|\DateTimeInterface
*/
private $startTime;

Expand Down
48 changes: 44 additions & 4 deletions src/OpenTracing/Tracer.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,28 @@
interface Tracer
{
/**
* Starts and returns a new `Span` representing a unit of work.
*
* This method differs from `startManualSpan` because it uses in-process
* context propagation to keep track of the current active `Span` (if
* available).
*
* Starting a root `Span` with no casual references and a child `Span`
* in a different function, is possible without passing the parent
* reference around:
*
* function handleRequest(Request $request, $userId)
* {
* $rootSpan = $this->tracer->startActiveSpan('request.handler');
* $user = $this->repository->getUser($userId);
* }
*
* function getUser($userId)
* {
* // `$childSpan` has `$rootSpan` as parent.
* $childSpan = $this->tracer->startActiveSpan('db.query');
* }
*
* @param string $operationName
* @param array|SpanOptions $options A set of optional parameters:
* - Zero or more references to related SpanContexts, including a shorthand for ChildOf and
Expand All @@ -25,7 +47,26 @@ interface Tracer
* @throws InvalidSpanOption for invalid option
* @throws InvalidReferencesSet for invalid references set
*/
public function startSpan($operationName, $options = []);
public function startActiveSpan($operationName, $options = []);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reference type between the new created active span and the current active span?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ping @jcchavezs

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When creating a new activeSpan it becomes automatically the child of the existing one: https://github.com/opentracing/opentracing-php/pull/45/files#diff-bd85a3792bd64b152939e0b1b78086e2R19

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about other span relations than child_of?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@felixfbecker that is what startManualSpan is for.


/**
* @param string $operationName
* @param array|SpanOptions $options
* @return Span
* @throws InvalidSpanOption for invalid option
* @throws InvalidReferencesSet for invalid references set
*/
public function startManualSpan($operationName, $options = []);

/**
* @return ActiveSpanSource
*/
public function getActiveSpanSource();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The introduction of ActiveSpanSource is not bad. Because, I implemented the same function in my company's php framework yesterday.

However, the opentracing specification only defines the references. And how to trace the reference is all business of user.


/**
* @return Span
*/
public function getActiveSpan();

/**
* @param SpanContext $spanContext
Expand Down Expand Up @@ -54,9 +95,8 @@ public function extract($format, Reader $carrier);
*
* This method might not be needed depending on the tracing implementation
* but one should make sure this method is called after the request is finished.
* As an implementor, a good idea would be to use an asynchronous message bus
* or use the call to fastcgi_finish_request in order to not to delay the end
* of the request to the client.
* As an implementor, a good idea would be to use register_shutdown_function
* or fastcgi_finish_request in order to not to delay the end of the request to the client.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not an "or" imho, since you can use both. register_shutdown_function is still waiting to finish the communication with the Webserver if you don't use fastcgi_finish_request.

*
* @see register_shutdown_function()
* @see fastcgi_finish_request()
Expand Down