Skip to content

Commit

Permalink
optimize resource creation (open-telemetry#1210)
Browse files Browse the repository at this point in the history
* reduce resource creation from sdk autoloader
- instead of creating new resources from various factories, create them once from sdk autoloader and
pass them to the factories (most of which already supported this).
- check env before php.ini for config, since this is the more popular approach and saves some cycles
- cache header from OtlpUtil, to save a couple of calls to Sdk detector
* adding benchmark for resource creation
  • Loading branch information
brettmc authored Jan 13, 2024
1 parent 25726f6 commit 3928b13
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 13 deletions.
15 changes: 10 additions & 5 deletions src/Contrib/Otlp/OtlpUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,16 @@ public static function method(string $signal): string
*/
public static function getUserAgentHeader(): array
{
$resource = (new Sdk())->getResource();
static $header;
if ($header === null) {
$resource = (new Sdk())->getResource();

$header = ['User-Agent' => sprintf(
'OTel OTLP Exporter PHP/%s',
$resource->getAttributes()->get(ResourceAttributes::TELEMETRY_SDK_VERSION) ?: 'unknown'
)];
}

return ['User-Agent' => sprintf(
'OTel OTLP Exporter PHP/%s',
$resource->getAttributes()->get(ResourceAttributes::TELEMETRY_SDK_VERSION) ?: 'unknown'
)];
return $header;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ public static function instance(): self
{
static $instance;
$instance ??= new self([
new PhpIniResolver(),
new EnvironmentResolver(),
new PhpIniResolver(),
]);

return $instance;
Expand Down
5 changes: 3 additions & 2 deletions src/SDK/Logs/LoggerProviderFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@

use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory;
use OpenTelemetry\SDK\Metrics\MeterProviderInterface;
use OpenTelemetry\SDK\Resource\ResourceInfo;
use OpenTelemetry\SDK\Sdk;

class LoggerProviderFactory
{
public function create(?MeterProviderInterface $meterProvider = null): LoggerProviderInterface
public function create(?MeterProviderInterface $meterProvider = null, ?ResourceInfo $resource = null): LoggerProviderInterface
{
if (Sdk::isDisabled()) {
return NoopLoggerProvider::getInstance();
Expand All @@ -19,6 +20,6 @@ public function create(?MeterProviderInterface $meterProvider = null): LoggerPro
$processor = (new LogRecordProcessorFactory())->create($exporter, $meterProvider);
$instrumentationScopeFactory = new InstrumentationScopeFactory((new LogRecordLimitsBuilder())->build()->getAttributeFactory());

return new LoggerProvider($processor, $instrumentationScopeFactory);
return new LoggerProvider($processor, $instrumentationScopeFactory, $resource);
}
}
5 changes: 3 additions & 2 deletions src/SDK/Metrics/MeterProviderFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use OpenTelemetry\SDK\Metrics\MetricExporter\NoopMetricExporter;
use OpenTelemetry\SDK\Metrics\MetricReader\ExportingReader;
use OpenTelemetry\SDK\Registry;
use OpenTelemetry\SDK\Resource\ResourceInfo;
use OpenTelemetry\SDK\Resource\ResourceInfoFactory;
use OpenTelemetry\SDK\Sdk;

Expand All @@ -28,7 +29,7 @@ class MeterProviderFactory
* - "The exporter MUST configure the default aggregation on the basis of instrument kind using the
* OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION variable as described below if it is implemented."
*/
public function create(): MeterProviderInterface
public function create(?ResourceInfo $resource = null): MeterProviderInterface
{
if (Sdk::isDisabled()) {
return new NoopMeterProvider();
Expand All @@ -50,7 +51,7 @@ public function create(): MeterProviderInterface

// @todo "The exporter MUST be paired with a periodic exporting MetricReader"
$reader = new ExportingReader($exporter);
$resource = ResourceInfoFactory::defaultResource();
$resource ??= ResourceInfoFactory::defaultResource();
$exemplarFilter = $this->createExemplarFilter(Configuration::getEnum(Variables::OTEL_METRICS_EXEMPLAR_FILTER));

return MeterProvider::builder()
Expand Down
3 changes: 2 additions & 1 deletion src/SDK/Resource/ResourceInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function serialize(): string
$copyOfAttributesAsArray = array_slice($this->attributes->toArray(), 0); //This may be overly cautious (in trying to avoid mutating the source array)
ksort($copyOfAttributesAsArray); //sort the associative array by keys since the serializer will consider equal arrays different otherwise

//The exact return value doesn't matter, as long as it can distingusih between instances that represent the same/different resources
//The exact return value doesn't matter, as long as it can distinguish between instances that represent the same/different resources
return serialize([
'schemaUrl' => $this->schemaUrl,
'attributes' => $copyOfAttributesAsArray,
Expand All @@ -62,6 +62,7 @@ public function serialize(): string
* resource, the value of the updating resource MUST be picked (even if the updated value is empty)
*
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/resource/sdk.md#merge
* @todo can we optimize this to avoid re-validating the attributes on merge?
*/
public function merge(ResourceInfo $updating): ResourceInfo
{
Expand Down
7 changes: 5 additions & 2 deletions src/SDK/SdkAutoloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use OpenTelemetry\SDK\Logs\LoggerProviderFactory;
use OpenTelemetry\SDK\Metrics\MeterProviderFactory;
use OpenTelemetry\SDK\Propagation\PropagatorFactory;
use OpenTelemetry\SDK\Resource\ResourceInfoFactory;
use OpenTelemetry\SDK\Trace\ExporterFactory;
use OpenTelemetry\SDK\Trace\SamplerFactory;
use OpenTelemetry\SDK\Trace\SpanProcessorFactory;
Expand Down Expand Up @@ -41,15 +42,17 @@ public static function autoload(): bool
}
$emitMetrics = Configuration::getBoolean(Variables::OTEL_PHP_INTERNAL_METRICS_ENABLED);

$resource = ResourceInfoFactory::defaultResource();
$exporter = (new ExporterFactory())->create();
$meterProvider = (new MeterProviderFactory())->create();
$meterProvider = (new MeterProviderFactory())->create($resource);
$spanProcessor = (new SpanProcessorFactory())->create($exporter, $emitMetrics ? $meterProvider : null);
$tracerProvider = (new TracerProviderBuilder())
->addSpanProcessor($spanProcessor)
->setResource($resource)
->setSampler((new SamplerFactory())->create())
->build();

$loggerProvider = (new LoggerProviderFactory())->create($emitMetrics ? $meterProvider : null);
$loggerProvider = (new LoggerProviderFactory())->create($emitMetrics ? $meterProvider : null, $resource);

ShutdownHandler::register([$tracerProvider, 'shutdown']);
ShutdownHandler::register([$meterProvider, 'shutdown']);
Expand Down
20 changes: 20 additions & 0 deletions tests/Benchmark/ResourceCreationBench.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Tests\Benchmark;

use OpenTelemetry\SDK\Resource\ResourceInfoFactory;

class ResourceCreationBench
{
/**
* @Revs({100, 1000})
* @Iterations(10)
* @OutputTimeUnit("microseconds")
*/
public function bench_create_default_resource(): void
{
ResourceInfoFactory::defaultResource();
}
}

0 comments on commit 3928b13

Please sign in to comment.