sdk autoloading (#854)
* sdk autoloading * use instrumentation initializers * basic sdk + autoloading documentation * exampler filter from config * configuration default types
This commit is contained in:
parent
f083b10909
commit
116e46d964
|
|
@ -64,7 +64,8 @@
|
|||
"src/Context/fiber/initialize_fiber_handler.php",
|
||||
"src/API/Trace/functions.php",
|
||||
"src/SDK/Common/Dev/Compatibility/_load.php",
|
||||
"src/SDK/Common/Util/functions.php"
|
||||
"src/SDK/Common/Util/functions.php",
|
||||
"src/SDK/_autoload.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
|
|
@ -96,7 +97,7 @@
|
|||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"phpunit/phpunit": "^9.3",
|
||||
"psalm/plugin-mockery": "^0.9",
|
||||
"psalm/plugin-phpunit": "^0.16",
|
||||
"psalm/plugin-phpunit": "^0.18",
|
||||
"psalm/psalm": "^4.0",
|
||||
"qossmic/deptrac-shim": "^0.24",
|
||||
"rector/rector": "^0.13.7",
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ deptrac:
|
|||
collectors:
|
||||
- type: className
|
||||
regex: ^OpenTelemetry\\Contrib\\*
|
||||
- name: Extension
|
||||
collectors:
|
||||
- type: className
|
||||
regex: ^OpenTelemetry\\Extension\\*
|
||||
- name: OtelProto
|
||||
collectors:
|
||||
- type: className
|
||||
|
|
@ -110,6 +114,8 @@ deptrac:
|
|||
- Thrift
|
||||
- JaegerThrift
|
||||
- Swoole
|
||||
Extension:
|
||||
- +API
|
||||
OtelProto:
|
||||
- GoogleProtobuf
|
||||
- Grpc
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ services:
|
|||
environment:
|
||||
XDEBUG_MODE: ${XDEBUG_MODE:-off}
|
||||
XDEBUG_CONFIG: ${XDEBUG_CONFIG:-''}
|
||||
PHP_IDE_CONFIG: ${PHP_IDE_CONFIG:-''}
|
||||
zipkin:
|
||||
image: openzipkin/zipkin-slim
|
||||
ports:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
putenv('OTEL_PHP_AUTOLOAD_ENABLED=true');
|
||||
putenv('OTEL_TRACES_EXPORTER=otlp');
|
||||
putenv('OTEL_EXPORTER_OTLP_PROTOCOL=grpc');
|
||||
putenv('OTEL_METRICS_EXPORTER=otlp');
|
||||
putenv('OTEL_EXPORTER_OTLP_METRICS_PROTOCOL=grpc');
|
||||
putenv('OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4317');
|
||||
putenv('OTEL_PHP_TRACES_PROCESSOR=batch');
|
||||
|
||||
// Composer autoloader will execute SDK/_autoload.php which will register global instrumentation from environment configuration
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
$instrumentation = new \OpenTelemetry\API\Common\Instrumentation\CachedInstrumentation('demo');
|
||||
|
||||
$instrumentation->tracer()->spanBuilder('root')->startSpan()->end();
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\CodeQuality\Rector\Array_\CallableThisArrayToAnonymousFunctionRector;
|
||||
use Rector\Config\RectorConfig;
|
||||
use Rector\Core\ValueObject\PhpVersion;
|
||||
use Rector\Set\ValueObject\SetList;
|
||||
|
|
@ -17,4 +18,10 @@ return static function (RectorConfig $rectorConfig): void {
|
|||
SetList::PHP_74,
|
||||
SetList::CODE_QUALITY,
|
||||
]);
|
||||
$rectorConfig->skip([
|
||||
CallableThisArrayToAnonymousFunctionRector::class => [
|
||||
__DIR__ . '/src/SDK/SdkBuilder.php',
|
||||
__DIR__ . '/src/SDK/SdkAutoloader.php',
|
||||
],
|
||||
]);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\Contrib\Otlp;
|
||||
|
||||
interface ContentTypes
|
||||
{
|
||||
public const PROTOBUF = 'application/x-protobuf';
|
||||
public const JSON = 'application/json';
|
||||
public const NDJSON = 'application/x-ndjson';
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\Contrib\Otlp;
|
||||
|
||||
use OpenTelemetry\API\Common\Signal\Signals;
|
||||
use OpenTelemetry\Contrib\Grpc\GrpcTransportFactory;
|
||||
use OpenTelemetry\SDK\Common\Configuration\Configuration;
|
||||
use OpenTelemetry\SDK\Common\Configuration\KnownValues;
|
||||
use OpenTelemetry\SDK\Common\Configuration\Variables;
|
||||
use OpenTelemetry\SDK\Common\Export\Http\PsrTransportFactory;
|
||||
use OpenTelemetry\SDK\Common\Export\TransportInterface;
|
||||
use OpenTelemetry\SDK\Metrics\MetricExporterInterface;
|
||||
use UnexpectedValueException;
|
||||
|
||||
class MetricExporterFactory
|
||||
{
|
||||
/**
|
||||
* @psalm-suppress ArgumentTypeCoercion
|
||||
*/
|
||||
public function create(): MetricExporterInterface
|
||||
{
|
||||
$protocol = Configuration::has(Variables::OTEL_EXPORTER_OTLP_METRICS_PROTOCOL)
|
||||
? Configuration::getEnum(Variables::OTEL_EXPORTER_OTLP_METRICS_PROTOCOL)
|
||||
: Configuration::getEnum(Variables::OTEL_EXPORTER_OTLP_PROTOCOL);
|
||||
|
||||
return new MetricExporter($this->buildTransport($protocol));
|
||||
}
|
||||
|
||||
private function buildTransport(string $protocol): TransportInterface
|
||||
{
|
||||
/**
|
||||
* @todo (https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#periodic-exporting-metricreader)
|
||||
* - OTEL_METRIC_EXPORT_INTERVAL
|
||||
* - OTEL_METRIC_EXPORT_TIMEOUT
|
||||
*/
|
||||
$endpoint = Configuration::has(Variables::OTEL_EXPORTER_OTLP_METRICS_ENDPOINT)
|
||||
? Configuration::getString(Variables::OTEL_EXPORTER_OTLP_METRICS_ENDPOINT)
|
||||
: Configuration::getString(Variables::OTEL_EXPORTER_OTLP_ENDPOINT);
|
||||
|
||||
$headers = Configuration::has(Variables::OTEL_EXPORTER_OTLP_METRICS_HEADERS)
|
||||
? Configuration::getMap(Variables::OTEL_EXPORTER_OTLP_METRICS_HEADERS)
|
||||
: Configuration::getMap(Variables::OTEL_EXPORTER_OTLP_HEADERS);
|
||||
$headers += OtlpUtil::getUserAgentHeader();
|
||||
|
||||
switch ($protocol) {
|
||||
case KnownValues::VALUE_GRPC:
|
||||
return (new GrpcTransportFactory())->create(
|
||||
$endpoint . OtlpUtil::method(Signals::METRICS),
|
||||
ContentTypes::PROTOBUF,
|
||||
$headers,
|
||||
);
|
||||
case KnownValues::VALUE_HTTP_PROTOBUF:
|
||||
case KnownValues::VALUE_HTTP_JSON:
|
||||
return PsrTransportFactory::discover()->create(
|
||||
$endpoint,
|
||||
Protocols::contentType($protocol),
|
||||
$headers,
|
||||
);
|
||||
default:
|
||||
throw new UnexpectedValueException('Unknown otlp protocol: ' . $protocol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,10 +14,10 @@ class Protocols
|
|||
public const HTTP_JSON = KnownValues::VALUE_HTTP_JSON;
|
||||
public const HTTP_NDJSON = KnownValues::VALUE_HTTP_NDJSON;
|
||||
private const PROTOCOLS = [
|
||||
self::GRPC => 'application/x-protobuf',
|
||||
self::HTTP_PROTOBUF => 'application/x-protobuf',
|
||||
self::HTTP_JSON => 'application/json',
|
||||
self::HTTP_NDJSON => 'application/x-ndjson',
|
||||
self::GRPC => ContentTypes::PROTOBUF,
|
||||
self::HTTP_PROTOBUF => ContentTypes::PROTOBUF,
|
||||
self::HTTP_JSON => ContentTypes::JSON,
|
||||
self::HTTP_NDJSON => ContentTypes::NDJSON,
|
||||
];
|
||||
|
||||
public static function validate(string $protocol): void
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ class SpanConverter implements SpanConverterInterface
|
|||
}
|
||||
|
||||
$attributesAsJson = json_encode($event->getAttributes()->toArray());
|
||||
if (($attributesAsJson === false) || ($attributesAsJson === '')) {
|
||||
if (($attributesAsJson === false)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class Configuration
|
|||
);
|
||||
}
|
||||
|
||||
public static function getString(string $key, string $default = ''): string
|
||||
public static function getString(string $key, string $default = null): string
|
||||
{
|
||||
return (string) self::validateVariableValue(
|
||||
CompositeResolver::instance()->resolve(
|
||||
|
|
@ -58,7 +58,7 @@ class Configuration
|
|||
);
|
||||
}
|
||||
|
||||
public static function getMixed(string $key, string $default = null)
|
||||
public static function getMixed(string $key, $default = null)
|
||||
{
|
||||
return self::validateVariableValue(
|
||||
CompositeResolver::instance()->resolve(
|
||||
|
|
@ -68,7 +68,7 @@ class Configuration
|
|||
);
|
||||
}
|
||||
|
||||
public static function getMap(string $key, string $default = null): array
|
||||
public static function getMap(string $key, array $default = null): array
|
||||
{
|
||||
return MapParser::parse(
|
||||
CompositeResolver::instance()->resolve(
|
||||
|
|
@ -78,7 +78,7 @@ class Configuration
|
|||
);
|
||||
}
|
||||
|
||||
public static function getList(string $key, string $default = null): array
|
||||
public static function getList(string $key, array $default = null): array
|
||||
{
|
||||
return ListParser::parse(
|
||||
CompositeResolver::instance()->resolve(
|
||||
|
|
@ -98,7 +98,7 @@ class Configuration
|
|||
);
|
||||
}
|
||||
|
||||
public static function getFloat(string $key, string $default = null): float
|
||||
public static function getFloat(string $key, float $default = null): float
|
||||
{
|
||||
return (float) self::validateVariableValue(
|
||||
CompositeResolver::instance()->resolve(
|
||||
|
|
|
|||
|
|
@ -102,4 +102,5 @@ interface Defaults
|
|||
*/
|
||||
public const OTEL_PHP_TRACES_PROCESSOR = 'batch';
|
||||
public const OTEL_PHP_DETECTORS = 'all';
|
||||
public const OTEL_PHP_AUTOLOAD_ENABLED = 'false';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -165,6 +165,7 @@ interface KnownValues
|
|||
self::VALUE_NOOP,
|
||||
self::VALUE_NONE,
|
||||
];
|
||||
public const OTEL_PHP_AUTOLOAD_ENABLED = self::VALUES_BOOLEAN;
|
||||
public const VALUE_DETECTORS_ENVIRONMENT = 'env';
|
||||
public const VALUE_DETECTORS_HOST = 'host';
|
||||
public const VALUE_DETECTORS_OS = 'os';
|
||||
|
|
|
|||
|
|
@ -120,4 +120,5 @@ interface Variables
|
|||
*/
|
||||
public const OTEL_PHP_TRACES_PROCESSOR = 'OTEL_PHP_TRACES_PROCESSOR';
|
||||
public const OTEL_PHP_DETECTORS = 'OTEL_PHP_DETECTORS';
|
||||
public const OTEL_PHP_AUTOLOAD_ENABLED = 'OTEL_PHP_AUTOLOAD_ENABLED';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use OpenTelemetry\SDK\Common\Attribute\Attributes;
|
|||
use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory;
|
||||
use OpenTelemetry\SDK\Common\Time\ClockFactory;
|
||||
use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter\WithSampledTraceExemplarFilter;
|
||||
use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface;
|
||||
use OpenTelemetry\SDK\Metrics\StalenessHandler\ImmediateStalenessHandlerFactory;
|
||||
use OpenTelemetry\SDK\Metrics\View\CriteriaViewRegistry;
|
||||
use OpenTelemetry\SDK\Resource\ResourceInfo;
|
||||
|
|
@ -18,6 +19,7 @@ class MeterProviderBuilder
|
|||
// @var array<MetricReaderInterface>
|
||||
private array $metricReaders = [];
|
||||
private ?ResourceInfo $resource = null;
|
||||
private ?ExemplarFilterInterface $exemplarFilter = null;
|
||||
|
||||
public function registerMetricReader(MetricReaderInterface $reader): self
|
||||
{
|
||||
|
|
@ -33,6 +35,13 @@ class MeterProviderBuilder
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function setExemplarFilter(ExemplarFilterInterface $exemplarFilter): self
|
||||
{
|
||||
$this->exemplarFilter = $exemplarFilter;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addReader(MetricReaderInterface $reader): self
|
||||
{
|
||||
$this->metricReaders[] = $reader;
|
||||
|
|
@ -53,7 +62,7 @@ class MeterProviderBuilder
|
|||
new InstrumentationScopeFactory(Attributes::factory()),
|
||||
$this->metricReaders,
|
||||
new CriteriaViewRegistry(),
|
||||
new WithSampledTraceExemplarFilter(),
|
||||
$this->exemplarFilter ?? new WithSampledTraceExemplarFilter(),
|
||||
new ImmediateStalenessHandlerFactory(),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\SDK\Metrics;
|
||||
|
||||
use OpenTelemetry\SDK\Behavior\LogsMessagesTrait;
|
||||
use OpenTelemetry\SDK\Common\Configuration\Configuration;
|
||||
use OpenTelemetry\SDK\Common\Configuration\KnownValues;
|
||||
use OpenTelemetry\SDK\Common\Configuration\Variables;
|
||||
use OpenTelemetry\SDK\Common\Time\ClockFactory;
|
||||
use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter\AllExemplarFilter;
|
||||
use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter\NoneExemplarFilter;
|
||||
use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilter\WithSampledTraceExemplarFilter;
|
||||
use OpenTelemetry\SDK\Metrics\Exemplar\ExemplarFilterInterface;
|
||||
use OpenTelemetry\SDK\Metrics\MetricExporter\NoopMetricExporter;
|
||||
use OpenTelemetry\SDK\Metrics\MetricReader\ExportingReader;
|
||||
use OpenTelemetry\SDK\Resource\ResourceInfoFactory;
|
||||
use OpenTelemetry\SDK\Sdk;
|
||||
|
||||
class MeterProviderFactory
|
||||
{
|
||||
use LogsMessagesTrait;
|
||||
|
||||
private const KNOWN_EXPORTER_FACTORIES = [
|
||||
KnownValues::VALUE_OTLP => '\OpenTelemetry\Contrib\Otlp\MetricExporterFactory',
|
||||
];
|
||||
|
||||
public function create(): MeterProviderInterface
|
||||
{
|
||||
if (Sdk::isDisabled()) {
|
||||
return new NoopMeterProvider();
|
||||
}
|
||||
$exporterName = Configuration::getString(Variables::OTEL_METRICS_EXPORTER);
|
||||
if ($exporterName === KnownValues::VALUE_NONE) {
|
||||
$exporter = new NoopMetricExporter();
|
||||
} elseif (!array_key_exists($exporterName, self::KNOWN_EXPORTER_FACTORIES)) {
|
||||
self::logError('Factory cannot create exporter: ' . $exporterName);
|
||||
$exporter = new NoopMetricExporter();
|
||||
} else {
|
||||
$factoryClass = self::KNOWN_EXPORTER_FACTORIES[$exporterName];
|
||||
$factory = new $factoryClass();
|
||||
$exporter = $factory->create();
|
||||
}
|
||||
$reader = new ExportingReader($exporter, ClockFactory::getDefault());
|
||||
$resource = ResourceInfoFactory::defaultResource();
|
||||
$exemplarFilter = $this->createExemplarFilter(Configuration::getEnum(Variables::OTEL_METRICS_EXEMPLAR_FILTER));
|
||||
|
||||
return MeterProvider::builder()
|
||||
->setResource($resource)
|
||||
->addReader($reader)
|
||||
->setExemplarFilter($exemplarFilter)
|
||||
->build();
|
||||
}
|
||||
|
||||
private function createExemplarFilter(string $name): ExemplarFilterInterface
|
||||
{
|
||||
switch ($name) {
|
||||
case KnownValues::VALUE_WITH_SAMPLED_TRACE:
|
||||
return new WithSampledTraceExemplarFilter();
|
||||
case KnownValues::VALUE_ALL:
|
||||
return new AllExemplarFilter();
|
||||
case KnownValues::VALUE_NONE:
|
||||
return new NoneExemplarFilter();
|
||||
default:
|
||||
self::logWarning('Unknown exemplar filter: ' . $name);
|
||||
|
||||
return new NoneExemplarFilter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\SDK\Metrics\MetricExporter;
|
||||
|
||||
use OpenTelemetry\SDK\Metrics\MetricExporterInterface;
|
||||
use OpenTelemetry\SDK\Metrics\MetricMetadataInterface;
|
||||
|
||||
class NoopMetricExporter implements MetricExporterInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function temporality(MetricMetadataInterface $metric)
|
||||
{
|
||||
return $metric->temporality();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function export(iterable $batch): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function shutdown(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function forceFlush(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\SDK\Propagation;
|
||||
|
||||
use OpenTelemetry\Context\Propagation\MultiTextMapPropagator;
|
||||
use OpenTelemetry\Context\Propagation\NoopTextMapPropagator;
|
||||
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;
|
||||
use OpenTelemetry\SDK\Behavior\LogsMessagesTrait;
|
||||
use OpenTelemetry\SDK\Common\Configuration\Configuration;
|
||||
use OpenTelemetry\SDK\Common\Configuration\KnownValues;
|
||||
use OpenTelemetry\SDK\Common\Configuration\Variables;
|
||||
|
||||
class PropagatorFactory
|
||||
{
|
||||
use LogsMessagesTrait;
|
||||
|
||||
private const KNOWN_PROPAGATORS = [
|
||||
KnownValues::VALUE_TRACECONTEXT => ['\OpenTelemetry\API\Trace\Propagation\TraceContextPropagator', 'getInstance'],
|
||||
KnownValues::VALUE_BAGGAGE => ['\OpenTelemetry\API\Baggage\Propagation\BaggagePropagator', 'getInstance'],
|
||||
KnownValues::VALUE_B3 => ['\OpenTelemetry\Extension\Propagator\B3\B3Propagator', 'getB3SingleHeaderInstance'],
|
||||
KnownValues::VALUE_B3_MULTI => ['\OpenTelemetry\Extension\Propagator\B3\B3Propagator', 'getB3MultiHeaderInstance'],
|
||||
];
|
||||
|
||||
public function create(): TextMapPropagatorInterface
|
||||
{
|
||||
$propagators = Configuration::getList(Variables::OTEL_PROPAGATORS);
|
||||
switch (count($propagators)) {
|
||||
case 0:
|
||||
return new NoopTextMapPropagator();
|
||||
case 1:
|
||||
return $this->buildPropagator($propagators[0]) ?? new NoopTextMapPropagator();
|
||||
default:
|
||||
return new MultiTextMapPropagator($this->buildPropagators($propagators));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<TextMapPropagatorInterface>
|
||||
*/
|
||||
private function buildPropagators(array $names): array
|
||||
{
|
||||
$propagators = [];
|
||||
foreach ($names as $name) {
|
||||
$propagator = $this->buildPropagator($name);
|
||||
if ($propagator !== null) {
|
||||
$propagators[] = $propagator;
|
||||
}
|
||||
}
|
||||
|
||||
return $propagators;
|
||||
}
|
||||
|
||||
private function buildPropagator(string $name): ?TextMapPropagatorInterface
|
||||
{
|
||||
switch ($name) {
|
||||
case KnownValues::VALUE_NONE:
|
||||
return null;
|
||||
case KnownValues::VALUE_XRAY:
|
||||
case KnownValues::VALUE_OTTRACE:
|
||||
self::logWarning('Unimplemented propagator: ' . $name);
|
||||
|
||||
return null;
|
||||
default:
|
||||
if (!array_key_exists($name, self::KNOWN_PROPAGATORS)) {
|
||||
self::logWarning('Unknown propagator: ' . $name);
|
||||
|
||||
return null;
|
||||
}
|
||||
$parts = self::KNOWN_PROPAGATORS[$name];
|
||||
|
||||
try {
|
||||
return call_user_func($parts);
|
||||
} catch (\Throwable $e) {
|
||||
self::logError(sprintf('Unable to create %s propagator: %s', $name, $e->getMessage()));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1,34 @@
|
|||
# OpenTelemetry SDK
|
||||
# OpenTelemetry SDK
|
||||
|
||||
The OpenTelemetry PHP SDK implements the API, and should be used in conjunction with contributed exporter(s) to generate and export telemetry.
|
||||
|
||||
## Getting started
|
||||
|
||||
### Manual setup
|
||||
|
||||
See https://github.com/open-telemetry/opentelemetry-php/tree/main/examples
|
||||
|
||||
### SDK Builder
|
||||
|
||||
See https://github.com/open-telemetry/opentelemetry-php/blob/main/examples/sdk_builder.php
|
||||
|
||||
### Autoloading
|
||||
|
||||
SDK autoloading works with configuration values provided via the environment (or php.ini).
|
||||
|
||||
The SDK can be automatically created and registered, if the following conditions are met:
|
||||
- `OTEL_PHP_AUTOLOAD_ENABLED=true`
|
||||
- all required [SDK configuration](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#general-sdk-configuration) is provided
|
||||
|
||||
SDK autoloading will be attempted as part of composer's autoloader:
|
||||
|
||||
```php
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
$tracer = OpenTelemetry\API\Common\Instrumentation\Globals::tracerProvider()->getTracer('example');
|
||||
$meter = OpenTelemetry\API\Common\Instrumentation\Globals::meterProvider()->getMeter('example');
|
||||
```
|
||||
|
||||
If autoloading was not successful (or partially successful), no-op implementations of the above may be returned.
|
||||
|
||||
See https://github.com/open-telemetry/opentelemetry-php/blob/main/examples/autoload_sdk.php for a more detailed example.
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ final class Environment implements ResourceDetectorInterface
|
|||
public function getResource(): ResourceInfo
|
||||
{
|
||||
$attributes = Configuration::has(Variables::OTEL_RESOURCE_ATTRIBUTES)
|
||||
? Configuration::getMap(Variables::OTEL_RESOURCE_ATTRIBUTES, '')
|
||||
? Configuration::getMap(Variables::OTEL_RESOURCE_ATTRIBUTES, [])
|
||||
: [];
|
||||
|
||||
//@see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#general-sdk-configuration
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\SDK;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use OpenTelemetry\API\Common\Instrumentation\Configurator;
|
||||
use OpenTelemetry\API\Common\Instrumentation\Globals;
|
||||
use OpenTelemetry\SDK\Common\Configuration\Configuration;
|
||||
use OpenTelemetry\SDK\Common\Configuration\Variables;
|
||||
use OpenTelemetry\SDK\Common\Util\ShutdownHandler;
|
||||
use OpenTelemetry\SDK\Metrics\MeterProviderFactory;
|
||||
use OpenTelemetry\SDK\Propagation\PropagatorFactory;
|
||||
use OpenTelemetry\SDK\Trace\ExporterFactory;
|
||||
use OpenTelemetry\SDK\Trace\SamplerFactory;
|
||||
use OpenTelemetry\SDK\Trace\SpanProcessorFactory;
|
||||
use OpenTelemetry\SDK\Trace\TracerProviderBuilder;
|
||||
|
||||
class SdkAutoloader
|
||||
{
|
||||
private static ?bool $enabled = null;
|
||||
|
||||
public static function autoload(): bool
|
||||
{
|
||||
try {
|
||||
self::$enabled ??= Configuration::getBoolean(Variables::OTEL_PHP_AUTOLOAD_ENABLED);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
//invalid setting, assume false
|
||||
self::$enabled = false;
|
||||
}
|
||||
if (!self::$enabled) {
|
||||
return false;
|
||||
}
|
||||
Globals::registerInitializer(function (Configurator $configurator) {
|
||||
$exporter = (new ExporterFactory())->fromEnvironment();
|
||||
$propagator = (new PropagatorFactory())->create();
|
||||
$meterProvider = (new MeterProviderFactory())->create();
|
||||
$spanProcessor = (new SpanProcessorFactory())->fromEnvironment($exporter, $meterProvider);
|
||||
$tracerProvider = (new TracerProviderBuilder())
|
||||
->addSpanProcessor($spanProcessor)
|
||||
->setSampler((new SamplerFactory())->fromEnvironment())
|
||||
->build();
|
||||
|
||||
ShutdownHandler::register([$tracerProvider, 'shutdown']);
|
||||
ShutdownHandler::register([$meterProvider, 'shutdown']);
|
||||
|
||||
return $configurator
|
||||
->withTracerProvider($tracerProvider)
|
||||
->withMeterProvider($meterProvider)
|
||||
->withPropagator($propagator);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function shutdown(): void
|
||||
{
|
||||
self::$enabled = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,6 @@ use OpenTelemetry\Context\Context;
|
|||
use OpenTelemetry\Context\Propagation\NoopTextMapPropagator;
|
||||
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;
|
||||
use OpenTelemetry\Context\ScopeInterface;
|
||||
use OpenTelemetry\SDK\Common\Future\CancellationInterface;
|
||||
use OpenTelemetry\SDK\Common\Util\ShutdownHandler;
|
||||
use OpenTelemetry\SDK\Metrics\MeterProviderInterface;
|
||||
use OpenTelemetry\SDK\Metrics\NoopMeterProvider;
|
||||
|
|
@ -59,8 +58,9 @@ class SdkBuilder
|
|||
$tracerProvider = $this->tracerProvider ?? new NoopTracerProvider();
|
||||
$meterProvider = $this->meterProvider ?? new NoopMeterProvider();
|
||||
if ($this->autoShutdown) {
|
||||
ShutdownHandler::register(fn (?CancellationInterface $cancellation = null): bool => $tracerProvider->shutdown($cancellation));
|
||||
ShutdownHandler::register(fn (): bool => $meterProvider->shutdown());
|
||||
// rector rule disabled in config, because ShutdownHandler::register() does not keep a strong reference to $this
|
||||
ShutdownHandler::register([$tracerProvider, 'shutdown']);
|
||||
ShutdownHandler::register([$meterProvider, 'shutdown']);
|
||||
}
|
||||
|
||||
return new Sdk(
|
||||
|
|
@ -79,6 +79,7 @@ class SdkBuilder
|
|||
->withMeterProvider($sdk->getMeterProvider())
|
||||
->storeInContext();
|
||||
|
||||
// @todo could auto-shutdown self?
|
||||
return Context::storage()->attach($context);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,13 +9,15 @@ use OpenTelemetry\SDK\Common\Configuration\Configuration;
|
|||
use OpenTelemetry\SDK\Common\Configuration\KnownValues as Values;
|
||||
use OpenTelemetry\SDK\Common\Configuration\Variables as Env;
|
||||
use OpenTelemetry\SDK\Common\Time\ClockFactory;
|
||||
use OpenTelemetry\SDK\Metrics\MeterProviderInterface;
|
||||
use OpenTelemetry\SDK\Metrics\NoopMeterProvider;
|
||||
use OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessor;
|
||||
use OpenTelemetry\SDK\Trace\SpanProcessor\NoopSpanProcessor;
|
||||
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
|
||||
|
||||
class SpanProcessorFactory
|
||||
{
|
||||
public function fromEnvironment(?SpanExporterInterface $exporter = null): SpanProcessorInterface
|
||||
public function fromEnvironment(?SpanExporterInterface $exporter = null, ?MeterProviderInterface $meterProvider = null): SpanProcessorInterface
|
||||
{
|
||||
if ($exporter === null) {
|
||||
return new NoopSpanProcessor();
|
||||
|
|
@ -31,6 +33,8 @@ class SpanProcessorFactory
|
|||
Configuration::getInt(Env::OTEL_BSP_SCHEDULE_DELAY, BatchSpanProcessor::DEFAULT_SCHEDULE_DELAY),
|
||||
Configuration::getInt(Env::OTEL_BSP_EXPORT_TIMEOUT, BatchSpanProcessor::DEFAULT_EXPORT_TIMEOUT),
|
||||
Configuration::getInt(Env::OTEL_BSP_MAX_EXPORT_BATCH_SIZE, BatchSpanProcessor::DEFAULT_MAX_EXPORT_BATCH_SIZE),
|
||||
true, //autoflush
|
||||
$meterProvider ?? new NoopMeterProvider(),
|
||||
);
|
||||
case Values::VALUE_SIMPLE:
|
||||
return new SimpleSpanProcessor($exporter);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
\OpenTelemetry\SDK\SdkAutoloader::autoload();
|
||||
|
|
@ -30,7 +30,8 @@
|
|||
"OpenTelemetry\\SDK\\": "."
|
||||
},
|
||||
"files": [
|
||||
"Common/Util/functions.php"
|
||||
"Common/Util/functions.php",
|
||||
"_autoload.php"
|
||||
]
|
||||
},
|
||||
"suggest": {
|
||||
|
|
|
|||
|
|
@ -51,6 +51,16 @@ class ConfigurationTest extends TestCase
|
|||
];
|
||||
|
||||
private const USER_VALUES = [
|
||||
VariableTypes::STRING => ['foo', 'foo'],
|
||||
VariableTypes::BOOL => ['true', true],
|
||||
VariableTypes::INTEGER => ['42', 42],
|
||||
VariableTypes::ENUM => ['val1', 'val1'],
|
||||
VariableTypes::LIST => [['val1', 'val2'], ['val1','val2']],
|
||||
VariableTypes::MAP => [['var1' => 'val1', 'var2' => 'val2'], ['var1'=>'val1','var2'=>'val2']],
|
||||
VariableTypes::MIXED => ['foo', 'foo'],
|
||||
];
|
||||
|
||||
private const USER_ENV_VALUES = [
|
||||
VariableTypes::STRING => ['foo', 'foo'],
|
||||
VariableTypes::BOOL => ['true', true],
|
||||
VariableTypes::INTEGER => ['42', 42],
|
||||
|
|
@ -210,7 +220,7 @@ class ConfigurationTest extends TestCase
|
|||
}
|
||||
|
||||
/**
|
||||
* @dataProvider userValueProvider
|
||||
* @dataProvider userEnvValueProvider
|
||||
*/
|
||||
public function test_return_user_env_vars(string $methodName, string $variable, string $value, $result)
|
||||
{
|
||||
|
|
@ -225,7 +235,7 @@ class ConfigurationTest extends TestCase
|
|||
/**
|
||||
* @dataProvider userValueProvider
|
||||
*/
|
||||
public function test_return_user_default_value(string $methodName, string $variable, string $defaultValue, $result)
|
||||
public function test_return_user_default_value(string $methodName, string $variable, $defaultValue, $result)
|
||||
{
|
||||
$this->assertSame(
|
||||
$result,
|
||||
|
|
@ -288,6 +298,20 @@ class ConfigurationTest extends TestCase
|
|||
}
|
||||
}
|
||||
|
||||
public function userEnvValueProvider(): Generator
|
||||
{
|
||||
foreach (self::USER_ENV_VALUES as $varType => $values) {
|
||||
[$default, $result] = $values;
|
||||
|
||||
yield $varType => [
|
||||
self::METHOD_NAMES[$varType][0],
|
||||
self::TYPES[$varType][0],
|
||||
$default,
|
||||
$result,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
public function libraryDefaultValueProvider(): Generator
|
||||
{
|
||||
foreach (self::LIBRARY_DEFAULTS as $varType => $values) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\Example\Unit\SDK\Metrics;
|
||||
|
||||
use AssertWell\PHPUnitGlobalState\EnvironmentVariables;
|
||||
use OpenTelemetry\API\Metrics\MeterInterface;
|
||||
use OpenTelemetry\SDK\Common\Configuration\KnownValues;
|
||||
use OpenTelemetry\SDK\Common\Configuration\Variables;
|
||||
use OpenTelemetry\SDK\Metrics\MeterProviderFactory;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers \OpenTelemetry\SDK\Metrics\MeterProviderFactory
|
||||
*/
|
||||
class MeterProviderFactoryTest extends TestCase
|
||||
{
|
||||
use EnvironmentVariables;
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
$this->restoreEnvironmentVariables();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider exporterProvider
|
||||
* @psalm-suppress ArgumentTypeCoercion
|
||||
*/
|
||||
public function test_create(string $exporter): void
|
||||
{
|
||||
$_SERVER[Variables::OTEL_METRICS_EXPORTER] = $exporter;
|
||||
$provider = (new MeterProviderFactory())->create();
|
||||
$this->assertInstanceOf(MeterInterface::class, $provider->getMeter('test'));
|
||||
}
|
||||
|
||||
public function exporterProvider(): array
|
||||
{
|
||||
return [
|
||||
'otlp' => [KnownValues::VALUE_OTLP],
|
||||
'none' => [KnownValues::VALUE_NONE],
|
||||
'unimplemented' => ['foo'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\Tests\Unit\SDK\Propagation;
|
||||
|
||||
use AssertWell\PHPUnitGlobalState\EnvironmentVariables;
|
||||
use OpenTelemetry\API\Baggage\Propagation\BaggagePropagator;
|
||||
use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator;
|
||||
use OpenTelemetry\Context\Propagation\MultiTextMapPropagator;
|
||||
use OpenTelemetry\Context\Propagation\NoopTextMapPropagator;
|
||||
use OpenTelemetry\Extension\Propagator\B3\B3Propagator;
|
||||
use OpenTelemetry\SDK\Common\Configuration\KnownValues;
|
||||
use OpenTelemetry\SDK\Common\Configuration\Variables;
|
||||
use OpenTelemetry\SDK\Propagation\PropagatorFactory;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers OpenTelemetry\SDK\Propagation\PropagatorFactory
|
||||
*/
|
||||
class PropagatorFactoryTest extends TestCase
|
||||
{
|
||||
use EnvironmentVariables;
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
$this->restoreEnvironmentVariables();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider propagatorsProvider
|
||||
* @psalm-suppress ArgumentTypeCoercion
|
||||
*/
|
||||
public function test_create(string $propagators, string $expected): void
|
||||
{
|
||||
$this->setEnvironmentVariable(Variables::OTEL_PROPAGATORS, $propagators);
|
||||
$propagator = (new PropagatorFactory())->create();
|
||||
$this->assertInstanceOf($expected, $propagator);
|
||||
}
|
||||
|
||||
public function propagatorsProvider(): array
|
||||
{
|
||||
return [
|
||||
[KnownValues::VALUE_BAGGAGE, BaggagePropagator::class],
|
||||
[KnownValues::VALUE_TRACECONTEXT, TraceContextPropagator::class],
|
||||
[KnownValues::VALUE_B3, B3Propagator::class],
|
||||
[KnownValues::VALUE_B3_MULTI, B3Propagator::class],
|
||||
[KnownValues::VALUE_NONE, NoopTextMapPropagator::class],
|
||||
[sprintf('%s,%s', KnownValues::VALUE_B3, KnownValues::VALUE_BAGGAGE), MultiTextMapPropagator::class],
|
||||
['unknown', NoopTextMapPropagator::class],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider unimplementedPropagatorProvider
|
||||
*/
|
||||
public function test_unimplemented_propagators(string $propagator): void
|
||||
{
|
||||
$this->setEnvironmentVariable(Variables::OTEL_PROPAGATORS, $propagator);
|
||||
$propagator = (new PropagatorFactory())->create();
|
||||
$this->assertInstanceOf(NoopTextMapPropagator::class, $propagator);
|
||||
}
|
||||
|
||||
public function unimplementedPropagatorProvider(): array
|
||||
{
|
||||
return [
|
||||
[KnownValues::VALUE_OTTRACE],
|
||||
[KnownValues::VALUE_XRAY],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\Tests\Unit\SDK;
|
||||
|
||||
use AssertWell\PHPUnitGlobalState\EnvironmentVariables;
|
||||
use OpenTelemetry\SDK\Common\Configuration\Variables;
|
||||
use OpenTelemetry\SDK\SdkAutoloader;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers \OpenTelemetry\SDK\SdkAutoloader
|
||||
*/
|
||||
class SdkAutoloaderTest extends TestCase
|
||||
{
|
||||
use EnvironmentVariables;
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
SdkAutoloader::shutdown();
|
||||
$this->restoreEnvironmentVariables();
|
||||
}
|
||||
|
||||
public function test_disabled_by_default(): void
|
||||
{
|
||||
$this->assertFalse(SdkAutoloader::autoload());
|
||||
}
|
||||
|
||||
public function test_enabled(): void
|
||||
{
|
||||
$this->setEnvironmentVariable(Variables::OTEL_PHP_AUTOLOAD_ENABLED, 'true');
|
||||
$this->assertTrue(SdkAutoloader::autoload());
|
||||
}
|
||||
|
||||
public function test_disabled_with_invalid_flag(): void
|
||||
{
|
||||
$this->setEnvironmentVariable(Variables::OTEL_PHP_AUTOLOAD_ENABLED, 'invalid-value');
|
||||
$this->assertFalse(SdkAutoloader::autoload());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue