Skip to content

Commit

Permalink
File configuration (#1249)
Browse files Browse the repository at this point in the history
* Add configuration model
* Add metrics and logs configuration model
* Remove accidentally added package dependency
* Fix `$properties` typehint to match config
Default value available -> cannot be null.
* Add configuration example that utilizes env substitution
* Fix/suppress config psalm issues
* Fix/suppress config phpstan issues
* Suppress config phan issues
* Apply cs-fixer
* Change config package version to development version 0.x
* Add README
* Add basic test
* Fix psalm and cs
* Fix composer requirement for PRs
* gitsplit, copy spi config to root composer.json
  • Loading branch information
Nevay authored Apr 1, 2024
0 parents commit c6ac5cb
Show file tree
Hide file tree
Showing 27 changed files with 1,620 additions and 0 deletions.
36 changes: 36 additions & 0 deletions ComponentProvider/Logs/LogRecordExporterConsole.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Config\SDK\ComponentProvider\Logs;

use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Logs\Exporter\ConsoleExporter;
use OpenTelemetry\SDK\Logs\LogRecordExporterInterface;
use OpenTelemetry\SDK\Registry;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;

/**
* @implements ComponentProvider<LogRecordExporterInterface>
*/
final class LogRecordExporterConsole implements ComponentProvider
{

/**
* @param array{} $properties
*/
public function createPlugin(array $properties, Context $context): LogRecordExporterInterface
{
return new ConsoleExporter(Registry::transportFactory('stream')->create(
endpoint: 'php://stdout',
contentType: 'application/json',
));
}

public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
{
return new ArrayNodeDefinition('console');
}
}
75 changes: 75 additions & 0 deletions ComponentProvider/Logs/LogRecordExporterOtlp.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Config\SDK\ComponentProvider\Logs;

use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use Nevay\OTelSDK\Configuration\Validation;
use Nevay\SPI\ServiceProviderDependency\PackageDependency;
use OpenTelemetry\API\Signals;
use OpenTelemetry\Contrib\Otlp\LogsExporter;
use OpenTelemetry\Contrib\Otlp\OtlpUtil;
use OpenTelemetry\Contrib\Otlp\Protocols;
use OpenTelemetry\SDK\Logs\LogRecordExporterInterface;
use OpenTelemetry\SDK\Registry;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;

/**
* @implements ComponentProvider<LogRecordExporterInterface>
*/
#[PackageDependency('open-telemetry/exporter-otlp', '^1.0.5')]
final class LogRecordExporterOtlp implements ComponentProvider
{

/**
* @param array{
* protocol: 'http/protobuf'|'http/json'|'grpc',
* endpoint: string,
* certificate: ?string,
* client_key: ?string,
* client_certificate: ?string,
* headers: array<string, string>,
* compression: 'gzip'|null,
* timeout: int<0, max>,
* } $properties
*/
public function createPlugin(array $properties, Context $context): LogRecordExporterInterface
{
$protocol = $properties['protocol'];

return new LogsExporter(Registry::transportFactory($protocol)->create(
endpoint: $properties['endpoint'] . OtlpUtil::path(Signals::LOGS, $protocol),
contentType: Protocols::contentType($protocol),
headers: $properties['headers'],
compression: $properties['compression'],
timeout: $properties['timeout'],
cacert: $properties['certificate'],
cert: $properties['client_certificate'],
key: $properties['client_certificate'],
));
}

public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
{
$node = new ArrayNodeDefinition('otlp');
$node
->children()
->enumNode('protocol')->isRequired()->values(['http/protobuf', 'http/json', 'grpc'])->end()
->scalarNode('endpoint')->isRequired()->validate()->always(Validation::ensureString())->end()->end()
->scalarNode('certificate')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->scalarNode('client_key')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->scalarNode('client_certificate')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->arrayNode('headers')
->scalarPrototype()->end()
->end()
->enumNode('compression')->values(['gzip'])->defaultNull()->end()
->integerNode('timeout')->min(0)->defaultValue(10)->end()
->end()
;

return $node;
}
}
60 changes: 60 additions & 0 deletions ComponentProvider/Logs/LogRecordProcessorBatch.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Config\SDK\ComponentProvider\Logs;

use Nevay\OTelSDK\Configuration\ComponentPlugin;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Logs\LogRecordExporterInterface;
use OpenTelemetry\SDK\Logs\LogRecordProcessorInterface;
use OpenTelemetry\SDK\Logs\Processor\BatchLogRecordProcessor;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;

/**
* @implements ComponentProvider<LogRecordProcessorInterface>
*/
final class LogRecordProcessorBatch implements ComponentProvider
{

/**
* @param array{
* schedule_delay: int<0, max>,
* export_timeout: int<0, max>,
* max_queue_size: int<0, max>,
* max_export_batch_size: int<0, max>,
* exporter: ComponentPlugin<LogRecordExporterInterface>,
* } $properties
*/
public function createPlugin(array $properties, Context $context): LogRecordProcessorInterface
{
return new BatchLogRecordProcessor(
exporter: $properties['exporter']->create($context),
clock: ClockFactory::getDefault(),
maxQueueSize: $properties['max_queue_size'],
scheduledDelayMillis: $properties['schedule_delay'],
exportTimeoutMillis: $properties['export_timeout'],
maxExportBatchSize: $properties['max_export_batch_size'],
meterProvider: $context->meterProvider,
);
}

public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
{
$node = new ArrayNodeDefinition('batch');
$node
->children()
->integerNode('schedule_delay')->min(0)->defaultValue(5000)->end()
->integerNode('export_timeout')->min(0)->defaultValue(30000)->end()
->integerNode('max_queue_size')->min(0)->defaultValue(2048)->end()
->integerNode('max_export_batch_size')->min(0)->defaultValue(512)->end()
->append($registry->component('exporter', LogRecordExporterInterface::class)->isRequired())
->end()
;

return $node;
}
}
45 changes: 45 additions & 0 deletions ComponentProvider/Logs/LogRecordProcessorSimple.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Config\SDK\ComponentProvider\Logs;

use Nevay\OTelSDK\Configuration\ComponentPlugin;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Logs\LogRecordExporterInterface;
use OpenTelemetry\SDK\Logs\LogRecordProcessorInterface;
use OpenTelemetry\SDK\Logs\Processor\SimpleLogRecordProcessor;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;

/**
* @implements ComponentProvider<LogRecordProcessorInterface>
*/
final class LogRecordProcessorSimple implements ComponentProvider
{

/**
* @param array{
* exporter: ComponentPlugin<LogRecordExporterInterface>,
* } $properties
*/
public function createPlugin(array $properties, Context $context): LogRecordProcessorInterface
{
return new SimpleLogRecordProcessor(
exporter: $properties['exporter']->create($context),
);
}

public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
{
$node = new ArrayNodeDefinition('simple');
$node
->children()
->append($registry->component('exporter', LogRecordExporterInterface::class)->isRequired())
->end()
;

return $node;
}
}
35 changes: 35 additions & 0 deletions ComponentProvider/Metrics/AggregationResolverDefault.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Config\SDK\ComponentProvider\Metrics;

use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Metrics\DefaultAggregationProviderInterface;
use OpenTelemetry\SDK\Metrics\DefaultAggregationProviderTrait;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;

/**
* @implements ComponentProvider<DefaultAggregationProviderInterface>
*/
final class AggregationResolverDefault implements ComponentProvider
{

/**
* @param array{} $properties
*/
public function createPlugin(array $properties, Context $context): DefaultAggregationProviderInterface
{
// TODO Implement proper aggregation providers (default, drop, explicit_bucket_histogram, last_value, sum) to handle advisory
return new class() implements DefaultAggregationProviderInterface {
use DefaultAggregationProviderTrait;
};
}

public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
{
return new ArrayNodeDefinition('default');
}
}
32 changes: 32 additions & 0 deletions ComponentProvider/Metrics/MetricExporterConsole.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Config\SDK\ComponentProvider\Metrics;

use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Metrics\MetricExporter\ConsoleMetricExporter;
use OpenTelemetry\SDK\Metrics\MetricExporterInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;

/**
* @implements ComponentProvider<MetricExporterInterface>
*/
final class MetricExporterConsole implements ComponentProvider
{

/**
* @param array{} $properties
*/
public function createPlugin(array $properties, Context $context): MetricExporterInterface
{
return new ConsoleMetricExporter();
}

public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
{
return new ArrayNodeDefinition('console');
}
}
92 changes: 92 additions & 0 deletions ComponentProvider/Metrics/MetricExporterOtlp.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Config\SDK\ComponentProvider\Metrics;

use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use Nevay\OTelSDK\Configuration\Validation;
use Nevay\SPI\ServiceProviderDependency\PackageDependency;
use OpenTelemetry\API\Signals;
use OpenTelemetry\Contrib\Otlp\MetricExporter;
use OpenTelemetry\Contrib\Otlp\OtlpUtil;
use OpenTelemetry\Contrib\Otlp\Protocols;
use OpenTelemetry\SDK\Metrics\Data\Temporality;
use OpenTelemetry\SDK\Metrics\MetricExporterInterface;
use OpenTelemetry\SDK\Registry;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;

/**
* @implements ComponentProvider<MetricExporterInterface>
*/
#[PackageDependency('open-telemetry/exporter-otlp', '^1.0.5')]
final class MetricExporterOtlp implements ComponentProvider
{

/**
* @param array{
* protocol: 'http/protobuf'|'http/json'|'grpc',
* endpoint: string,
* certificate: ?string,
* client_key: ?string,
* client_certificate: ?string,
* headers: array<string, string>,
* compression: 'gzip'|null,
* timeout: int<0, max>,
* temporality_preference: 'cumulative'|'delta'|'lowmemory',
* default_histogram_aggregation: 'explicit_bucket_histogram',
* } $properties
*/
public function createPlugin(array $properties, Context $context): MetricExporterInterface
{
$protocol = $properties['protocol'];

$temporality = match ($properties['temporality_preference']) {
'cumulative' => Temporality::CUMULATIVE,
'delta' => Temporality::DELTA,
'lowmemory' => null,
};

return new MetricExporter(Registry::transportFactory($protocol)->create(
endpoint: $properties['endpoint'] . OtlpUtil::path(Signals::METRICS, $protocol),
contentType: Protocols::contentType($protocol),
headers: $properties['headers'],
compression: $properties['compression'],
timeout: $properties['timeout'],
cacert: $properties['certificate'],
cert: $properties['client_certificate'],
key: $properties['client_certificate'],
), $temporality);
}

public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
{
$node = new ArrayNodeDefinition('otlp');
$node
->children()
->enumNode('protocol')->isRequired()->values(['http/protobuf', 'http/json', 'grpc'])->end()
->scalarNode('endpoint')->isRequired()->validate()->always(Validation::ensureString())->end()->end()
->scalarNode('certificate')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->scalarNode('client_key')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->scalarNode('client_certificate')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->arrayNode('headers')
->scalarPrototype()->end()
->end()
->enumNode('compression')->values(['gzip'])->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->integerNode('timeout')->min(0)->defaultValue(10)->end()
->enumNode('temporality_preference')
->values(['cumulative', 'delta', 'lowmemory'])
->defaultValue('cumulative')
->end()
->enumNode('default_histogram_aggregation')
->values(['explicit_bucket_histogram'])
->defaultValue('explicit_bucket_histogram')
->end()
->end()
;

return $node;
}
}
Loading

0 comments on commit c6ac5cb

Please sign in to comment.