Wikia / opentracing-php

MIT License
11 stars 2 forks source link

Discuss context propagation strategies #5

Open beberlei opened 8 years ago

beberlei commented 8 years ago

The specification now defines In Process request context propagation (http://opentracing.io/use-cases/#in-process-request-context-propagation), which is a "nice" way to describe getting the current span id.

We should discuss how to implement this in PHP.

Since PHP is (usually) single threaded and linear I would propose to do "implicit" context propagation through a static class + methods:

$parent = \OpenTracing\Context::getCurrentSpan();
$span $tracer->startSpan('foo', $parent);

or short, if you want to use the global tracer:

$span = \OpenTracing\Context::startSpan('foo');

Its implementation could be:

class Context
{
    private static $currentSpan;

    public static function getCurrentSpan()
    {
        return self::$currentSpan;            
    }

    public static function setCurrentSpan(Span $span)
    {
        return self::$currentSpan = $span;
    }

    public static function startSpan($operationName)
    {
         Tracer::getGlobalTracer()->startSpan($operationName, self::getCurrentSpan());
    }
}

This would solve the 99% use case in PHP easily.

The default Tracers can just call setCurrentSpan($span); whenenver start()+variants, or finish() is called on a span to get the context correctly.

For a Tracer that works with multithreaded (pthreads) or event based react-php, the context would require an alternative implementation. Since code has to be written to be used with both libraries anyways, I would just ignore these cases, because new tracers and new instrumentation has to be written.

wladekb commented 8 years ago

All of the above makes perfect sense for me.

I'm just uncertain about what span should be set as "current" when the finish() method is called. Finding out what was the previous active span is a non-trivial in the current implementation unless we add a non-standard reference to parent span.

@beberlei Any thoughts?

beberlei commented 8 years ago

@wladekb i think the tracer implementation should know that, for example:

public function finish()
{
    Context::setCurrentSpan($this->parent);
}
wladekb commented 8 years ago

Yes and no. Imagine an implementation that does not buffer anything and sends the "start new span" event instantly and would not need to keep that information in the memory any longer. Thus we would actually force implementation to keep the track for the entire Span lifespan.

@beberlei @bensigelman Thoughts?

bhs commented 8 years ago

@wladekb @beberlei I am by no means a PHP expert, though I do understand the big-picture stuff about being nearly-totally stateless between requests, the global context object, etc.

IMO it's reasonable to assume that implementations retain some sort of in-memory representation of a Span up until whenever Span.Finish() is invoked. That said, I am a little nervous about trying to maintain the parentage information in the global context... maybe there should be a single global span for the entire lifetime of the PHP request which can be used as a parent span if nothing else is (locally) available... but if things start happening concurrently within the single PHP request (surely there is some way to make parallel calls to various backends in PHP?) the parentage information becomes ambiguous and I wouldn't want to try and solve that at the OT layer. My two cents.

I will close be reiterating that I'm not a PHP expert :)