Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

auto-instrumentation registration #1304

Merged
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
be76d19
[WIP] Add instrumentation configuration
Nevay Apr 24, 2024
c178431
add autoloading for auto-instrumentations using SPI
brettmc May 6, 2024
31f93c0
allow autoloading and non-autoloading to work
brettmc May 6, 2024
ef343e1
fix attribute
brettmc May 6, 2024
ba765d9
experimental config file
brettmc May 6, 2024
b771c57
fixing invalid dependencies
brettmc May 7, 2024
ba994d5
dont register hook manager globally or in sdk
brettmc May 7, 2024
35feeff
remove unused function, psalm ignore missing extension function
brettmc May 7, 2024
43fc772
possibly fixing type-hint
brettmc May 7, 2024
76ce98f
load config files relative to cwd
brettmc May 7, 2024
73f83e0
fixing hook manager enable/disable + psalm complaints
brettmc May 8, 2024
7e57997
fixing 8.1 psalm error
brettmc May 8, 2024
f29b713
use context to pass providers to instrumentations
brettmc May 8, 2024
20cd7ef
adding tests for sdk::registerGlobal
brettmc May 8, 2024
c8373a3
linting
brettmc May 8, 2024
9ba45be
test coverage for globals
brettmc May 8, 2024
a4d9046
add opentelemetry extension to developer image and actions
brettmc May 9, 2024
e704719
always register instrumentations via SPI
brettmc May 9, 2024
d94d4cc
register globals initializer for file-config sdk
brettmc May 10, 2024
04aa26a
linting
brettmc May 10, 2024
7262680
remove globals init function
brettmc May 10, 2024
579713a
fix phan warning
brettmc May 10, 2024
8fd3724
simplify hook manager
brettmc May 13, 2024
e6f85fe
add todo to deprecate Registry in future
brettmc May 13, 2024
d032942
autoload instrumentations without config
brettmc May 13, 2024
82d62db
fixing phan ref, update doc
brettmc May 14, 2024
0e5ffac
remove phan suppress
brettmc May 14, 2024
de4262b
fix example
brettmc May 14, 2024
be50116
bump SPI to 0.2.1
brettmc May 14, 2024
5798a40
Merge branch 'main' into auto-instrumentation-registration
brettmc May 16, 2024
7acacb6
adding late-binding tracer+provider
brettmc May 17, 2024
77653d4
adding late binding logger and meter providers
brettmc May 18, 2024
c0cd4ed
more late binding test coverage
brettmc May 18, 2024
fe5fe3e
tidy
brettmc May 18, 2024
9459cb0
Merge branch 'main' into auto-instrumentation-registration
brettmc May 21, 2024
1c0e1b5
dont use CoversMethod yet
brettmc May 21, 2024
dcbdc37
Merge branch 'main' into auto-instrumentation-registration
brettmc Jun 20, 2024
4b6deb8
kitchen sink, remove unused var
brettmc Jun 20, 2024
610832b
instrumentation config as a map, per config file spec
brettmc Jun 24, 2024
a85982f
adding general config
brettmc Jun 25, 2024
ccde00d
move general config into sdk
brettmc Jun 25, 2024
552a7e8
test config caching
brettmc Jun 25, 2024
1164e6b
move general instrumentation config to api
brettmc Jun 25, 2024
3695630
avoid bad version of sebastian/exporter
brettmc Jun 25, 2024
7c0131b
bump config yaml files to 0.3
brettmc Jun 25, 2024
90a69ce
fix tests
brettmc Jun 26, 2024
d1b1f6f
Merge branch 'main' into auto-instrumentation-registration
brettmc Jun 28, 2024
3c2ac3f
disable hook manager during file-based init
brettmc Jul 4, 2024
f841065
cleanup
brettmc Jul 4, 2024
898982b
support multiple config files in autoloader
brettmc Jul 15, 2024
668d6e8
Merge branch 'main' into auto-instrumentation-registration
brettmc Jul 19, 2024
51234bd
move hook manager enable/disable out of extension hook manager
brettmc Jul 19, 2024
933dce7
update spi config
brettmc Jul 19, 2024
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
10 changes: 9 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,15 @@
"OpenTelemetry\\Config\\SDK\\ComponentProvider\\Logs\\LogRecordExporterConsole",
"OpenTelemetry\\Config\\SDK\\ComponentProvider\\Logs\\LogRecordExporterOtlp",
"OpenTelemetry\\Config\\SDK\\ComponentProvider\\Logs\\LogRecordProcessorBatch",
"OpenTelemetry\\Config\\SDK\\ComponentProvider\\Logs\\LogRecordProcessorSimple"
"OpenTelemetry\\Config\\SDK\\ComponentProvider\\Logs\\LogRecordProcessorSimple",

"OpenTelemetry\\Example\\ExampleConfigProvider"
],
"OpenTelemetry\\API\\Instrumentation\\AutoInstrumentation\\HookManager": [
"OpenTelemetry\\API\\Instrumentation\\AutoInstrumentation\\ExtensionHookManager"
],
"OpenTelemetry\\API\\Instrumentation\\AutoInstrumentation\\Instrumentation": [
"OpenTelemetry\\Example\\ExampleInstrumentation"
]
}
}
Expand Down
29 changes: 29 additions & 0 deletions deptrac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ deptrac:
collectors:
- type: directory
value: src/SDK/.*
- name: ConfigSDK
collectors:
- type: directory
value: src/Config/SDK/.*
- name: Context
collectors:
- type: directory
Expand Down Expand Up @@ -85,21 +89,46 @@ deptrac:
value: ^GuzzleHttp\\*
- type: className
value: ^Buzz\\*
- name: SPI
collectors:
- type: className
value: ^Nevay\\SPI\\*
- name: SymfonyConfig
collectors:
- type: className
value: ^Symfony\\Component\\Config\\*
- type: className
value: ^Symfony\\Component\\Yaml\\*
- type: className
value: ^Symfony\\Component\\VarExporter\\*

ruleset:
Context:
- FFI
SemConv: ~
ConfigSDK:
- SymfonyConfig
- API
- SDK
- SPI
- PsrLog
- Composer
- Context
- Contrib
- Extension
API:
- Context
- PsrLog
- SPI
SDK:
- +API
- ConfigSDK
- SemConv
- PsrHttp
- HttpPlug
- Composer
- HttpClients
- SPI
Contrib:
- +SDK
- +OtelProto
Expand Down
39 changes: 39 additions & 0 deletions examples/instrumentation/configure_instrumentation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace _;

use Nevay\SPI\ServiceLoader;
use OpenTelemetry\API\Instrumentation\AutoInstrumentation\ExtensionHookManager;
use OpenTelemetry\API\Instrumentation\AutoInstrumentation\Instrumentation;
use OpenTelemetry\Config\SDK\Configuration;
use OpenTelemetry\Config\SDK\Configuration\Context;
use OpenTelemetry\Example\Example;
use const PHP_EOL;

/**
* This example uses SPI (see root composer.json extra.spi) to configure an example auto-instrumentation from a YAML file
*/
// EXAMPLE_INSTRUMENTATION_SPAN_NAME=test1234 php examples/instrumentation/configure_instrumentation.php

require __DIR__ . '/../../vendor/autoload.php';

$sdk = Configuration::parseFile(__DIR__ . '/otel-sdk.yaml')->create(new Context())->setAutoShutdown(true)->build();
$configuration = \OpenTelemetry\Config\SDK\Instrumentation::parseFile(__DIR__ . '/otel-instrumentation.yaml')->create();

$hookManager = new ExtensionHookManager();
$storage = \OpenTelemetry\Context\Context::storage();
$context = new Context($sdk->getTracerProvider(), $sdk->getMeterProvider());

foreach (ServiceLoader::load(Instrumentation::class) as $instrumentation) {
$instrumentation->register($hookManager, $context, $configuration, $storage);
}

$scope = $storage->attach($hookManager->enable($storage->current()));

try {
echo (new Example())->test(), PHP_EOL;
} finally {
$scope->detach();
}
21 changes: 21 additions & 0 deletions examples/instrumentation/configure_instrumentation_global.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace _;

use OpenTelemetry\Example\Example;
use const PHP_EOL;

/**
* This example uses SPI (see root composer.json extra.spi) to configure an example auto-instrumentation from a YAML file.
* The YAML file paths are relative to the current working directory.
*/
// EXAMPLE_INSTRUMENTATION_SPAN_NAME=test1234 php examples/instrumentation/configure_instrumentation_global.php
putenv('OTEL_PHP_AUTOLOAD_ENABLED=true');
putenv('OTEL_EXPERIMENTAL_CONFIG_FILE=examples/instrumentation/otel-sdk.yaml');
putenv('OTEL_PHP_INSTRUMENTATION_CONFIG_FILE=examples/instrumentation/otel-instrumentation.yaml');
brettmc marked this conversation as resolved.
Show resolved Hide resolved

require __DIR__ . '/../../vendor/autoload.php';

echo (new Example())->test(), PHP_EOL;
3 changes: 3 additions & 0 deletions examples/instrumentation/otel-instrumentation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
config:
- example_instrumentation:
span_name: ${EXAMPLE_INSTRUMENTATION_SPAN_NAME:-example span}
7 changes: 7 additions & 0 deletions examples/instrumentation/otel-sdk.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
file_format: '0.1'

tracer_provider:
processors:
- simple:
exporter:
console: {}
14 changes: 14 additions & 0 deletions examples/src/Example.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Example;

final class Example
{

public function test(): int
{
return 42;
}
}
17 changes: 17 additions & 0 deletions examples/src/ExampleConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Example;

use OpenTelemetry\API\Instrumentation\AutoInstrumentation\InstrumentationConfiguration;

final class ExampleConfig implements InstrumentationConfiguration
{

public function __construct(
public readonly string $spanName,
public readonly bool $enabled = true,
) {
}
}
50 changes: 50 additions & 0 deletions examples/src/ExampleConfigProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Example;

use OpenTelemetry\API\Instrumentation\AutoInstrumentation\InstrumentationConfiguration;
use OpenTelemetry\Config\SDK\Configuration\ComponentProvider;
use OpenTelemetry\Config\SDK\Configuration\ComponentProviderRegistry;
use OpenTelemetry\Config\SDK\Configuration\Context;
use OpenTelemetry\Config\SDK\Configuration\Validation;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;

/**
* @implements ComponentProvider<InstrumentationConfiguration>
*/
final class ExampleConfigProvider implements ComponentProvider
{

/**
* @psalm-suppress MoreSpecificImplementedParamType
* @param array{
* span_name: string,
* enabled: bool,
* } $properties
*/
public function createPlugin(array $properties, Context $context): InstrumentationConfiguration
{
return new ExampleConfig(
spanName: $properties['span_name'],
enabled: $properties['enabled'],
);
}

/**
* @psalm-suppress UndefinedInterfaceMethod,PossiblyNullReference
*/
public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
{
$root = new ArrayNodeDefinition('example_instrumentation');
$root
->children()
->scalarNode('span_name')->isRequired()->validate()->always(Validation::ensureString())->end()->end()
->end()
->canBeDisabled()
;

return $root;
}
}
52 changes: 52 additions & 0 deletions examples/src/ExampleInstrumentation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\Example;

use Exception;
use OpenTelemetry\API\Instrumentation\AutoInstrumentation\ConfigurationRegistry;
use OpenTelemetry\API\Instrumentation\AutoInstrumentation\Context;
use OpenTelemetry\API\Instrumentation\AutoInstrumentation\HookManager;
use OpenTelemetry\API\Instrumentation\AutoInstrumentation\Instrumentation;
use OpenTelemetry\API\Trace\Span;
use OpenTelemetry\Context\ContextStorageInterface;

final class ExampleInstrumentation implements Instrumentation
{

public function register(HookManager $hookManager, Context $context, ConfigurationRegistry $configuration, ContextStorageInterface $storage): void
{
$config = $configuration->get(ExampleConfig::class) ?? throw new Exception('example instrumentation must be configured');
if (!$config->enabled) {
return;
}

$tracer = $context->tracerProvider->getTracer('example-instrumentation');

$hookManager->hook(
Example::class,
'test',
static function () use ($tracer, $config, $storage): void {
$context = $storage->current();

$span = $tracer
->spanBuilder($config->spanName)
->setParent($context)
->startSpan();

$storage->attach($span->storeInContext($context));
},
static function () use ($storage): void {
if (!$scope = $storage->scope()) {
return;
}

$scope->detach();

$span = Span::fromContext($scope->context());
$span->end();
}
);
}
}
5 changes: 5 additions & 0 deletions psalm.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@
<referencedClass name="GMP"/>
</errorLevel>
</UndefinedClass>
<UndefinedFunction>
<errorLevel type="suppress">
<referencedFunction name="OpenTelemetry\Instrumentation\hook"/>
</errorLevel>
</UndefinedFunction>
<ArgumentTypeCoercion>
<errorLevel type="suppress">
<directory name="./examples"/>
Expand Down
14 changes: 11 additions & 3 deletions src/API/Globals.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use function assert;
use Closure;
use const E_USER_WARNING;
use OpenTelemetry\API\Behavior\LogsMessagesTrait;
use OpenTelemetry\API\Instrumentation\Configurator;
use OpenTelemetry\API\Instrumentation\ContextKeys;
use OpenTelemetry\API\Logs\EventLoggerProviderInterface;
Expand All @@ -17,13 +17,14 @@
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;
use function sprintf;
use Throwable;
use function trigger_error;

/**
* Provides access to the globally configured instrumentation instances.
*/
final class Globals
{
use LogsMessagesTrait;

/** @var Closure[] */
private static array $initializers = [];
private static ?self $globals = null;
Expand Down Expand Up @@ -73,6 +74,13 @@ public static function registerInitializer(Closure $initializer): void
self::$initializers[] = $initializer;
}

public static function init(): void
{
if (self::$globals === null) {
self::globals();
}
}

/**
* @phan-suppress PhanTypeMismatchReturnNullable
*/
Expand All @@ -90,7 +98,7 @@ private static function globals(): self
try {
$configurator = $initializer($configurator);
} catch (Throwable $e) {
trigger_error(sprintf("Error during opentelemetry initialization: %s\n%s", $e->getMessage(), $e->getTraceAsString()), E_USER_WARNING);
self::logWarning(sprintf("Error during opentelemetry initialization: %s\n%s", $e->getMessage(), $e->getTraceAsString()));
}
}
} finally {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace OpenTelemetry\API\Instrumentation\AutoInstrumentation;

final class ConfigurationRegistry
{

private array $configurations = [];

public function add(InstrumentationConfiguration $configuration): self
{
$this->configurations[$configuration::class] = $configuration;

return $this;
}

/**
* @template C of InstrumentationConfiguration
* @param class-string<C> $id
* @return C|null
*/
public function get(string $id): ?InstrumentationConfiguration
{
return $this->configurations[$id] ?? null;
}
}
Loading
Loading