sdk autoloading (#854)

* sdk autoloading
* use instrumentation initializers
* basic sdk + autoloading documentation
* exampler filter from config
* configuration default types
This commit is contained in:
Brett McBride 2022-11-14 08:52:35 +11:00 committed by GitHub
parent f083b10909
commit 116e46d964
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 625 additions and 22 deletions

View File

@ -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",

View File

@ -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

View File

@ -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:

18
examples/autoload_sdk.php Normal file
View File

@ -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();

View File

@ -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',
],
]);
};

View File

@ -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';
}

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -182,7 +182,7 @@ class SpanConverter implements SpanConverterInterface
}
$attributesAsJson = json_encode($event->getAttributes()->toArray());
if (($attributesAsJson === false) || ($attributesAsJson === '')) {
if (($attributesAsJson === false)) {
return null;
}

View File

@ -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(

View File

@ -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';
}

View File

@ -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';

View File

@ -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';
}

View File

@ -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(),
);
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}
}

View File

@ -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.

View File

@ -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

64
src/SDK/SdkAutoloader.php Normal file
View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);

5
src/SDK/_autoload.php Normal file
View File

@ -0,0 +1,5 @@
<?php
declare(strict_types=1);
\OpenTelemetry\SDK\SdkAutoloader::autoload();

View File

@ -30,7 +30,8 @@
"OpenTelemetry\\SDK\\": "."
},
"files": [
"Common/Util/functions.php"
"Common/Util/functions.php",
"_autoload.php"
]
},
"suggest": {

View File

@ -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) {

View File

@ -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'],
];
}
}

View File

@ -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],
];
}
}

View File

@ -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());
}
}