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

Allow using custom Recorder and add option to always record spans #158

Merged
merged 4 commits into from
Jul 3, 2020
Merged
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
6 changes: 4 additions & 2 deletions src/Zipkin/DefaultTracing.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ public function __construct(
CurrentTraceContext $currentTraceContext,
bool $isNoop,
Propagation $propagation,
bool $supportsJoin
bool $supportsJoin,
bool $alwaysReportSpans = false
) {
$this->tracer = new Tracer(
$localEndpoint,
Expand All @@ -51,7 +52,8 @@ public function __construct(
$usesTraceId128bits,
$currentTraceContext,
$isNoop,
$supportsJoin
$supportsJoin,
$alwaysReportSpans
);

$this->propagation = $propagation;
Expand Down
20 changes: 18 additions & 2 deletions src/Zipkin/Recording/Span.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,20 +127,27 @@ final class Span
*/
private $localEndpoint;

/**
* @var bool|null
*/
private $isSampled;

private function __construct(
string $traceId,
?string $parentId,
string $spanId,
bool $debug,
bool $shared,
Endpoint $localEndpoint
Endpoint $localEndpoint,
?bool $isSampled = false
Copy link
Contributor

Choose a reason for hiding this comment

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

I will also move this before endpoint as we changed the order already.

) {
$this->traceId = $traceId;
$this->parentId = $parentId;
$this->spanId = $spanId;
$this->debug = $debug;
$this->shared = $shared;
$this->localEndpoint = $localEndpoint;
$this->isSampled = $isSampled;
}

/**
Expand All @@ -156,7 +163,8 @@ public static function createFromContext(TraceContext $context, Endpoint $localE
$context->getSpanId(),
$context->isDebug(),
$context->isShared(),
$localEndpoint
$localEndpoint,
$context->isSampled()
Copy link
Member

Choose a reason for hiding this comment

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

ps one slight thing here is that in brave the "handler" has 2 arguments. since it has the context as one of the args, we don't need to also copy isSampled to the span.

  @Override public boolean end(TraceContext context, MutableSpan span, Cause cause) {
    if (!alwaysReportSpans && !Boolean.TRUE.equals(context.sampled())) return true;
--snip--

Copy link
Member

Choose a reason for hiding this comment

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

I'm not saying to change this, just mentioning a reference. it is fine to also copy it to the span, just it should be immutable (appears to be the case!)

);
}

Expand Down Expand Up @@ -225,6 +233,14 @@ public function setRemoteEndpoint(Endpoint $remoteEndpoint): void
$this->remoteEndpoint = $remoteEndpoint;
}

/**
* @return bool
*/
public function isSampled(): bool
{
return $this->isSampled === true;
Copy link
Contributor

Choose a reason for hiding this comment

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

Got a question here @adriancole @drolando: what we are saying here is whether this is sampled or not (and then dispatch the span to different reporters accordingly) but what about debug? if something is sampled=false but debug=true then we will dispatch it to the local sampled reporter, isn't?

Copy link
Contributor

Choose a reason for hiding this comment

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

Probably it is better we change this into shouldRecord which also checks the debug flag?

Copy link
Contributor

Choose a reason for hiding this comment

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

Giving a second thought, I think it is responsability of the user to decide what to do when sampled=false and debug=true.

}

/**
* Completes and reports the span
*
Expand Down
12 changes: 10 additions & 2 deletions src/Zipkin/Tracer.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,19 @@ final class Tracer
*/
private $supportsJoin;

/**
* @var bool
*/
private $alwaysReportSpans;

/**
* @param Endpoint $localEndpoint
* @param Reporter $reporter
* @param Sampler $sampler
* @param bool $usesTraceId128bits
* @param CurrentTraceContext $currentTraceContext
* @param bool $isNoop
* @param bool $alwaysReportSpans
*/
public function __construct(
Endpoint $localEndpoint,
Expand All @@ -63,14 +69,16 @@ public function __construct(
bool $usesTraceId128bits,
CurrentTraceContext $currentTraceContext,
bool $isNoop,
bool $supportsJoin = true
bool $supportsJoin = true,
bool $alwaysReportSpans = false
) {
$this->recorder = new Recorder($localEndpoint, $reporter, $isNoop);
$this->sampler = $sampler;
$this->usesTraceId128bits = $usesTraceId128bits;
$this->currentTraceContext = $currentTraceContext;
$this->isNoop = $isNoop;
$this->supportsJoin = $supportsJoin;
$this->alwaysReportSpans = $alwaysReportSpans;
}

/**
Expand Down Expand Up @@ -393,7 +401,7 @@ private function ensureSampled(TraceContext $context): Span
*/
private function toSpan(TraceContext $context): Span
{
if (!$this->isNoop && $context->isSampled()) {
if (!$this->isNoop && ($context->isSampled() || $this->alwaysReportSpans)) {
return new RealSpan($context, $this->recorder);
}

Expand Down
25 changes: 24 additions & 1 deletion src/Zipkin/TracingBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ class TracingBuilder
*/
private $propagation = null;

/**
* @var bool
*/
private $alwaysReportSpans = false;

public static function create(): self
{
return new self();
Expand Down Expand Up @@ -183,6 +188,23 @@ public function supportingJoin(bool $supportsJoin): self
return $this;
}

/**
* True means that spans will always be recorded, even if the current trace is not sampled.
* Defaults to False.
*
* This has the side effect that your reporter will receive all spans, irrespective of the
* sampling decision. Use this if you want to have some custom smart logic in the reporter
* that needs to have access to both sampled and unsampled traces.
*
* @param bool $alwaysReportSpans
* @return $this
*/
public function alwaysReportingSpans(bool $alwaysReportSpans): self
{
$this->alwaysReportSpans = $alwaysReportSpans;
return $this;
}

/**
* @return DefaultTracing
*/
Expand All @@ -209,7 +231,8 @@ public function build(): Tracing
$currentTraceContext,
$this->isNoop,
$propagation,
$this->supportsJoin && $propagation->supportsJoin()
$this->supportsJoin && $propagation->supportsJoin(),
$this->alwaysReportSpans
);
}
}
55 changes: 55 additions & 0 deletions tests/Unit/TracingBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Zipkin\Tracing;
use Zipkin\Endpoint;
use Zipkin\Reporters\Noop;
use Zipkin\Reporters\InMemory;
use Zipkin\TracingBuilder;
use Zipkin\Propagation\Getter;
use Zipkin\Propagation\Setter;
Expand Down Expand Up @@ -85,4 +86,58 @@ private function randomBool()
{
return (bool) mt_rand(0, 1);
}

public function testAlwaysEmitSpans()
Copy link
Contributor

Choose a reason for hiding this comment

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

I will also change this test into alwaysReportSpans.

{
// If `alwaysReportingSpans(true)` is called, we should be emitting the
// spans even if the trace isn't sampled
$endpoint = Endpoint::createAsEmpty();
$reporter = new InMemory();
$sampler = BinarySampler::createAsNeverSample();

$tracing = TracingBuilder::create()
->havingLocalServiceName(self::SERVICE_NAME)
->havingLocalEndpoint($endpoint)
->havingReporter($reporter)
->havingSampler($sampler)
->alwaysReportingSpans(true)
->build();
$tracer = $tracing->getTracer();

$span = $tracer->newTrace();
$span->setName('test');
$span->start();
$span->finish();

$tracer->flush();
$spans = $reporter->flush();
Copy link
Member

Choose a reason for hiding this comment

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

I don't fully understand why we are using another word. Ex alwaysReportSpans would make sense to have reporter report. alwaysEmitSpans would makes sense to have emitter emit :)

here's a related post on naming the TL;DR; being that we make enough words at this point https://publicobject.com/2020/06/06/synonyms-are-bad/

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oh yeah that's a better name

$this->assertCount(1, $spans);
$this->assertFalse($spans[0]->isSampled());
}

public function testDontEmitByDefault()
{
// By default, let's verify that we don't emit any span if the
// trace isn't sampled.
$endpoint = Endpoint::createAsEmpty();
$reporter = new InMemory();
$sampler = BinarySampler::createAsNeverSample();

$tracing = TracingBuilder::create()
->havingLocalServiceName(self::SERVICE_NAME)
->havingLocalEndpoint($endpoint)
->havingReporter($reporter)
->havingSampler($sampler)
->build();
$tracer = $tracing->getTracer();

$span = $tracer->newTrace();
$span->setName('test');
$span->start();
$span->finish();

$tracer->flush();
$spans = $reporter->flush();
$this->assertCount(0, $spans);
}
}