forked from open-telemetry/opentelemetry-php
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
this adds an attribute-based sampler, which can be configured to inspect a semconv attribute on a span, and either sample it in our out by applying a PCRE regex to it. adding an alternative syntax to define samplers and sampler args from env vars. now we also support "sampler1,...,samplerN" chaining of samplers, and the ability to define sampler args via "<samplername>.<arg>=<value>,..."
- Loading branch information
Showing
6 changed files
with
464 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace OpenTelemetry\Example; | ||
|
||
require __DIR__ . '/../../../vendor/autoload.php'; | ||
|
||
use OpenTelemetry\SDK\Trace\TracerProviderFactory; | ||
|
||
//@see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md | ||
putenv('OTEL_RESOURCE_ATTRIBUTES=service.version=1.0.0'); | ||
putenv('OTEL_SERVICE_NAME=example-app'); | ||
putenv('OTEL_PHP_DETECTORS=none'); | ||
putenv('OTEL_LOG_LEVEL=warning'); | ||
putenv('OTEL_TRACES_SAMPLER=parentbased,attribute,traceidratio'); | ||
putenv('OTEL_TRACES_SAMPLER_ARG=attribute.name=http.path,attribute.mode=deny,attribute.pattern=\/health$|\/test$,traceidratio.probability=1.0'); | ||
putenv('OTEL_TRACES_EXPORTER=console'); | ||
|
||
echo 'Starting attribute-based sampler example' . PHP_EOL; | ||
|
||
$tracerProvider = (new TracerProviderFactory())->create(); | ||
|
||
$tracer = $tracerProvider->getTracer('io.opentelemetry.contrib.php'); | ||
|
||
echo 'Starting Tracer' . PHP_EOL; | ||
|
||
$span = $tracer->spanBuilder('root')->setAttribute('http.path', '/health')->startSpan(); | ||
$scope = $span->activate(); | ||
|
||
try { | ||
//this span will be sampled iff the root was sampled (parent-based) | ||
$tracer->spanBuilder('child')->startSpan()->end(); | ||
} finally { | ||
$scope->detach(); | ||
} | ||
$span->end(); | ||
|
||
$tracerProvider->shutdown(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace OpenTelemetry\SDK\Trace\Sampler; | ||
|
||
use InvalidArgumentException; | ||
use OpenTelemetry\API\Behavior\LogsMessagesTrait; | ||
use OpenTelemetry\Context\ContextInterface; | ||
use OpenTelemetry\SDK\Common\Attribute\AttributesInterface; | ||
use OpenTelemetry\SDK\Trace\SamplerInterface; | ||
use OpenTelemetry\SDK\Trace\SamplingResult; | ||
|
||
/** | ||
* @phan-file-suppress PhanParamTooFewUnpack | ||
* | ||
* Attribute-based sampler for root spans. | ||
* "allow" mode: only sample root span if attribute exists and matches the pattern, else do not sample | ||
* "deny" mode: do not sample root span if attribute exists and matches the pattern, else defer to next sampler | ||
*/ | ||
class AttributeBasedSampler implements SamplerInterface | ||
{ | ||
use LogsMessagesTrait; | ||
|
||
public const ALLOW = 'allow'; | ||
public const DENY = 'deny'; | ||
public const MODES = [ | ||
self::ALLOW, | ||
self::DENY, | ||
]; | ||
|
||
private SamplerInterface $delegate; | ||
private string $mode; | ||
private string $attribute; | ||
private string $pattern; | ||
|
||
/** | ||
* @param SamplerInterface $delegate The sampler to defer to if a decision is not made by this sampler | ||
* @param string $mode Sampling mode (deny or allow) | ||
* @param string $attribute The SemConv trace attribute to test against, eg http.path, http.method | ||
* @param string $pattern The PCRE regex pattern to match against, eg /\/health$|\/test$/ | ||
*/ | ||
public function __construct(SamplerInterface $delegate, string $mode, string $attribute, string $pattern) | ||
{ | ||
if (!in_array($mode, self::MODES)) { | ||
throw new InvalidArgumentException('Unknown Attribute sampler mode: ' . $mode); | ||
} | ||
$this->delegate = $delegate; | ||
$this->mode = $mode; | ||
$this->attribute = $attribute; | ||
$this->pattern = $pattern; | ||
} | ||
|
||
public function shouldSample(ContextInterface $parentContext, string $traceId, string $spanName, int $spanKind, AttributesInterface $attributes, array $links): SamplingResult | ||
{ | ||
switch ($this->mode) { | ||
case self::ALLOW: | ||
if (!$attributes->has($this->attribute)) { | ||
return new SamplingResult(SamplingResult::DROP); | ||
} | ||
if ($this->matches((string) $attributes->get($this->attribute))) { | ||
return new SamplingResult(SamplingResult::RECORD_AND_SAMPLE); | ||
} | ||
|
||
break; | ||
case self::DENY: | ||
if (!$attributes->has($this->attribute)) { | ||
break; | ||
} | ||
if ($this->matches((string) $attributes->get($this->attribute))) { | ||
return new SamplingResult(SamplingResult::DROP); | ||
} | ||
|
||
break; | ||
default: | ||
//do nothing | ||
} | ||
|
||
return $this->delegate->shouldSample(...func_get_args()); | ||
} | ||
|
||
private function matches(string $value): bool | ||
{ | ||
$result = @preg_match($this->pattern, $value); | ||
if ($result === false) { | ||
self::logWarning('Error when pattern matching attribute', [ | ||
'attribute.name' => $this->attribute, | ||
'attribute.value' => $value, | ||
'pattern' => $this->pattern, | ||
'error' => preg_last_error_msg(), | ||
]); | ||
|
||
return false; | ||
} | ||
|
||
return (bool) $result; | ||
} | ||
|
||
public function getDescription(): string | ||
{ | ||
return sprintf('AttributeSampler{mode=%s,attribute=%s,pattern=%s}+%s', $this->mode, $this->attribute, $this->pattern, $this->delegate->getDescription()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.