Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use function Flow\Telemetry\DSL\batching_log_processor;
use function Flow\Telemetry\DSL\batching_metric_processor;
use function Flow\Telemetry\DSL\batching_span_processor;
use function Flow\Telemetry\DSL\git_detector;
use function Flow\Telemetry\DSL\logger_provider;
use function Flow\Telemetry\DSL\memory_context_storage;
use function Flow\Telemetry\DSL\meter_provider;
Expand All @@ -40,6 +41,7 @@ public static function create(Configuration $config): Telemetry
{
$telemetryResource = resource_detector()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would pass git_detector() here with other default detectors:

resource_detector([
  os_detector(),
  host_detector(),
  process_detector(),
  composer_detector(),
  environment_detector(),
  git_detector() 
]);

but ideally (can be handled in next pr) we should probably allow users to configure which detectors they want to use

->detect()
->merge(git_detector()->detect())
->merge(resource([
'service.name' => $config->serviceName,
'telemetry.sdk.name' => 'flow-php-phpunit-telemetry',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
use Flow\Telemetry\Resource\Detector\ChainDetector;
use Flow\Telemetry\Resource\Detector\ComposerDetector;
use Flow\Telemetry\Resource\Detector\EnvironmentDetector;
use Flow\Telemetry\Resource\Detector\GitDetector;
use Flow\Telemetry\Resource\Detector\HostDetector;
use Flow\Telemetry\Resource\Detector\ManualDetector;
use Flow\Telemetry\Resource\Detector\OsDetector;
Expand Down Expand Up @@ -244,6 +245,26 @@ public function configure(DefinitionConfigurator $definition): void
->end()
->end()
->end()
->arrayNode('git')
->info(
'Git detector - detects vcs.ref.head.* and vcs.repository.url.full by invoking the git binary. Disabled by default; the remote URL is reported with any embedded credentials stripped.',
)
->addDefaultsIfNotSet()
->children()
->booleanNode('enabled')
->info('Enable the git detector (default: false)')
->defaultFalse()
->end()
->scalarNode('binary')
->info('Path to the git binary (default: "git", resolved from $PATH)')
->defaultValue('git')
->end()
->scalarNode('working_directory')
->info('Directory to run git in (default: %kernel.project_dir%)')
->defaultNull()
->end()
->end()
->end()
->arrayNode('environment')
->info('Environment detector - reads OTEL_SERVICE_NAME and OTEL_RESOURCE_ATTRIBUTES')
->addDefaultsIfNotSet()
Expand Down Expand Up @@ -673,7 +694,7 @@ public function configure(DefinitionConfigurator $definition): void
}

/**
* @param array{resource: array{detectors?: array{enabled?: bool, static?: array{cache?: array{enabled?: bool, path?: null|string}, os?: array{enabled?: bool}, host?: array{enabled?: bool}, service?: array{enabled?: bool}, deployment?: array{enabled?: bool}, environment?: array{enabled?: bool}}, dynamic?: array{process?: array{enabled?: bool}}}, custom?: array<string, mixed>}, clock_service_id?: null|string, framework_logger?: null|string, capture_framework_channels?: bool, channel_attribute_target?: 'scope'|'signal'|'both', context_storage?: array{type?: string, service_id?: null|string}, propagator?: array{type?: string, service_id?: null|string}, exporters?: array<string, array<string, mixed>>, error_handlers?: array<string, array<string, mixed>>, tracer_provider?: array<string, mixed>, meter_provider?: array<string, mixed>, logger_provider?: array<string, mixed>, instrumentation?: array{http_kernel?: array{enabled?: bool, exclude_paths?: array<array{path: string, method?: null|string}>, context_propagation?: bool}, console?: array{enabled?: bool, exclude_commands?: array<string>}, messenger?: array{enabled?: bool, context_propagation?: bool}, twig?: array{enabled?: bool, trace_templates?: bool, trace_blocks?: bool, trace_macros?: bool, exclude_templates?: array<string>}, http_client?: array{enabled?: bool, exclude_clients?: array<string>}, psr18_client?: array{enabled?: bool, exclude_clients?: array<string>}, dbal?: array{enabled?: bool, log_sql?: bool, max_sql_length?: int, exclude_connections?: array<string>}, cache?: array{enabled?: bool, exclude_pools?: array<string>}}, tracers?: array<string, array{version?: string, schema_url?: null|string, attributes?: array{scope?: array<string, mixed>, signal?: array<string, mixed>}}>, meters?: array<string, array{version?: string, schema_url?: null|string, attributes?: array{scope?: array<string, mixed>, signal?: array<string, mixed>}}>, loggers?: array<string, array{version?: string, schema_url?: null|string, attributes?: array{scope?: array<string, mixed>, signal?: array<string, mixed>}}>} $config
* @param array{resource: array{detectors?: array{enabled?: bool, static?: array{cache?: array{enabled?: bool, path?: null|string}, os?: array{enabled?: bool}, host?: array{enabled?: bool}, service?: array{enabled?: bool}, deployment?: array{enabled?: bool}, git?: array{enabled?: bool, binary?: string, working_directory?: null|string}, environment?: array{enabled?: bool}}, dynamic?: array{process?: array{enabled?: bool}}}, custom?: array<string, mixed>}, clock_service_id?: null|string, framework_logger?: null|string, capture_framework_channels?: bool, channel_attribute_target?: 'scope'|'signal'|'both', context_storage?: array{type?: string, service_id?: null|string}, propagator?: array{type?: string, service_id?: null|string}, exporters?: array<string, array<string, mixed>>, error_handlers?: array<string, array<string, mixed>>, tracer_provider?: array<string, mixed>, meter_provider?: array<string, mixed>, logger_provider?: array<string, mixed>, instrumentation?: array{http_kernel?: array{enabled?: bool, exclude_paths?: array<array{path: string, method?: null|string}>, context_propagation?: bool}, console?: array{enabled?: bool, exclude_commands?: array<string>}, messenger?: array{enabled?: bool, context_propagation?: bool}, twig?: array{enabled?: bool, trace_templates?: bool, trace_blocks?: bool, trace_macros?: bool, exclude_templates?: array<string>}, http_client?: array{enabled?: bool, exclude_clients?: array<string>}, psr18_client?: array{enabled?: bool, exclude_clients?: array<string>}, dbal?: array{enabled?: bool, log_sql?: bool, max_sql_length?: int, exclude_connections?: array<string>}, cache?: array{enabled?: bool, exclude_pools?: array<string>}}, tracers?: array<string, array{version?: string, schema_url?: null|string, attributes?: array{scope?: array<string, mixed>, signal?: array<string, mixed>}}>, meters?: array<string, array{version?: string, schema_url?: null|string, attributes?: array{scope?: array<string, mixed>, signal?: array<string, mixed>}}>, loggers?: array<string, array{version?: string, schema_url?: null|string, attributes?: array{scope?: array<string, mixed>, signal?: array<string, mixed>}}>} $config
*/
#[Override]
public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
Expand Down Expand Up @@ -2803,7 +2824,7 @@ private function registerPropagator(array $config, ContainerBuilder $builder): v
}

/**
* @param array{detectors?: array{enabled?: bool, static?: array{cache?: array{enabled?: bool, path?: null|string}, os?: array{enabled?: bool}, host?: array{enabled?: bool}, service?: array{enabled?: bool}, deployment?: array{enabled?: bool}, environment?: array{enabled?: bool}}, dynamic?: array{process?: array{enabled?: bool}}}, custom?: array<string, mixed>} $resourceConfig
* @param array{detectors?: array{enabled?: bool, static?: array{cache?: array{enabled?: bool, path?: null|string}, os?: array{enabled?: bool}, host?: array{enabled?: bool}, service?: array{enabled?: bool}, deployment?: array{enabled?: bool}, git?: array{enabled?: bool, binary?: string, working_directory?: null|string}, environment?: array{enabled?: bool}}, dynamic?: array{process?: array{enabled?: bool}}}, custom?: array<string, mixed>} $resourceConfig
*/
private function registerResource(array $resourceConfig, ContainerBuilder $builder): void
{
Expand Down Expand Up @@ -2850,6 +2871,18 @@ private function registerResource(array $resourceConfig, ContainerBuilder $build
$staticDetectorRefs[] = new Reference('flow.telemetry.resource.detector.deployment');
}

if ($staticConfig['git']['enabled'] ?? false) {
$gitConfig = is_array($staticConfig['git'] ?? null) ? $staticConfig['git'] : [];
$workingDirectory = $gitConfig['working_directory'] ?? null;
$gitBinary = is_string($gitConfig['binary'] ?? null) ? $gitConfig['binary'] : 'git';

$gitDefinition = new Definition(GitDetector::class);
$gitDefinition->setArgument(0, $workingDirectory ?? '%kernel.project_dir%');
$gitDefinition->setArgument(1, $gitBinary);
$builder->setDefinition('flow.telemetry.resource.detector.git', $gitDefinition);
$staticDetectorRefs[] = new Reference('flow.telemetry.resource.detector.git');
}

if (count($customAttributes) > 0) {
$manualDefinition = new Definition(ManualDetector::class);
$manualDefinition->setArgument(0, $customAttributes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
use Flow\Telemetry\Provider\Void\VoidSpanProcessor;
use Flow\Telemetry\Resource;
use Flow\Telemetry\Resource\Detector\CachingDetector;
use Flow\Telemetry\Resource\Detector\GitDetector;
use Flow\Telemetry\Telemetry;
use Flow\Telemetry\Tracer\Processor\BatchingSpanProcessor;
use Flow\Telemetry\Tracer\Processor\CompositeSpanProcessor;
Expand Down Expand Up @@ -113,6 +114,41 @@ public function test_caching_detector_writes_to_configured_path(): void
}
}

public function test_git_detector_is_not_registered_by_default(): void
{
$this->bootKernel([
'config' => static function (TestKernel $kernel): void {
$kernel->addTestExtensionConfig('flow_telemetry', [
'resource' => [],
]);
},
]);

static::assertFalse($this->getContainer()->has('flow.telemetry.resource.detector.git'));
}

public function test_git_detector_is_registered_when_enabled(): void
{
$this->bootKernel([
'config' => static function (TestKernel $kernel): void {
$kernel->addTestExtensionConfig('flow_telemetry', [
'resource' => [
'detectors' => [
'static' => [
'git' => ['enabled' => true],
],
],
],
]);
},
]);

$container = $this->getContainer();

static::assertTrue($container->has('flow.telemetry.resource.detector.git'));
static::assertInstanceOf(GitDetector::class, $container->get('flow.telemetry.resource.detector.git'));
}

public function test_clock_can_be_overridden_with_custom_service(): void
{
$this->bootKernel([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,42 @@ public function test_clock_service_id_can_be_configured(): void
static::assertSame('app.custom_clock', $config['clock_service_id']);
}

public function test_git_detector_can_be_configured(): void
{
$config = $this->context->processConfig([
'resource' => [
'detectors' => [
'static' => [
'git' => [
'enabled' => true,
'binary' => '/usr/bin/git',
'working_directory' => '/srv/app',
],
],
],
],
]);

$git = $config['resource']['detectors']['static']['git'];

static::assertTrue($git['enabled']);
static::assertSame('/usr/bin/git', $git['binary']);
static::assertSame('/srv/app', $git['working_directory']);
}

public function test_git_detector_defaults_to_disabled(): void
{
$config = $this->context->processConfig([
'resource' => [],
]);

$git = $config['resource']['detectors']['static']['git'];

static::assertFalse($git['enabled']);
static::assertSame('git', $git['binary']);
static::assertNull($git['working_directory']);
}

public function test_clock_service_id_defaults_to_null(): void
{
$config = $this->context->processConfig([
Expand Down
13 changes: 13 additions & 0 deletions src/lib/telemetry/src/Flow/Telemetry/DSL/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
use Flow\Telemetry\Resource\Detector\ChainDetector;
use Flow\Telemetry\Resource\Detector\ComposerDetector;
use Flow\Telemetry\Resource\Detector\EnvironmentDetector;
use Flow\Telemetry\Resource\Detector\GitDetector;
use Flow\Telemetry\Resource\Detector\HostDetector;
use Flow\Telemetry\Resource\Detector\ManualDetector;
use Flow\Telemetry\Resource\Detector\OsDetector;
Expand Down Expand Up @@ -1027,6 +1028,18 @@ function composer_detector(): ComposerDetector
return new ComposerDetector();
}

/**
* Create a GitDetector.
*
* @param null|string $workingDirectory Directory to run git in (default: current working directory)
* @param string $gitBinary Path to the git binary (default: "git", resolved from $PATH)
*/
#[DocumentationDSL(module: Module::TELEMETRY, type: DSLType::HELPER)]
function git_detector(?string $workingDirectory = null, string $gitBinary = 'git'): GitDetector
{
return new GitDetector($workingDirectory, $gitBinary);
}

/**
* Create a ManualDetector.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

namespace Flow\Telemetry\Resource\Attribute;

/**
* VCS (Version Control System) attribute keys following OpenTelemetry semantic conventions.
*
* These attribute names correspond to the VCS resource attributes as defined
* in the OpenTelemetry semantic conventions specification.
*
* @see https://opentelemetry.io/docs/specs/semconv/registry/attributes/vcs/
*/
enum VcsAttribute: string
{
/**
* The name of the reference that the HEAD points to.
*
* For a branch this is the branch name, for a tag the tag name.
*
* Example: "main", "v1.0.0"
*/
case REF_HEAD_NAME = 'vcs.ref.head.name';

/**
* The revision (commit SHA) that the HEAD currently points to.
*
* Example: "9d59409acf479dfa0df1c3dad539b4825a8d2bcf"
*/
case REF_HEAD_REVISION = 'vcs.ref.head.revision';

/**
* The type of the reference that the HEAD points to.
*
* Example: "branch", "tag"
*/
case REF_HEAD_TYPE = 'vcs.ref.head.type';

/**
* The full URL of the repository providing the remote.
*
* Example: "https://github.com/flow-php/flow.git"
*/
case REPOSITORY_URL = 'vcs.repository.url.full';
}
Loading
Loading