open-telemetry / opentelemetry-php

The OpenTelemetry PHP Library
https://opentelemetry.io/docs/instrumentation/php/
Apache License 2.0
716 stars 178 forks source link

wordpress auto instrumentation & composer autoloading #920

Closed pdelewski closed 1 year ago

pdelewski commented 1 year ago

Describe your environment PHP 8.2.1 (cli) (built: Jan 12 2023 19:14:53) (NTS) Copyright (c) The PHP Group Zend Engine v4.2.1, Copyright (c) Zend Technologies with Zend OPcache v8.2.1, Copyright (c), by Zend Technologies

Steps to reproduce

composer create-project slim/slim-skeleton:dev-master slimauto composer require opentelemetry-api, opentelemetry-sdk, opentelemetry-sdk-contrib, opentelemetry-auto-wordpress cd slimauto export OTEL_PHP_AUTOLOAD_ENABLED=true export OTEL_TRACES_EXPORTER=zipkin export OTEL_EXPORTER_ZIPKIN_ENDPOINT=http://localhost:9411/api/v2/spans export OTEL_PHP_TRACES_PROCESSOR=simple php -S localhost:8080 -t public public/index.php

or follow steps described https://github.com/open-telemetry/opentelemetry-php-instrumentation/tree/main/bin

What is the actual behavior? What did you see instead?

{
    "statusCode": 500,
    "error": {
        "type": "SERVER_ERROR",
        "description": "WARNING: Error during opentelemetry initialization: Span exporter factory not defined for: zipkin\n#0 \/Users\/pdelewski\/Projects\/slim\/slimautoloading\/slimauto\/vendor\/open-telemetry\/sdk\/Trace\/ExporterFactory.php(29): OpenTelemetry\\SDK\\Registry::spanExporterFactory('zipkin')\n#1 \/Users\/pdelewski\/Projects\/slim\/slimautoloading\/slimauto\/vendor\/open-telemetry\/sdk\/SdkAutoloader.php(42): OpenTelemetry\\SDK\\Trace\\ExporterFactory->create()\n#2 \/Users\/pdelewski\/Projects\/slim\/slimautoloading\/slimauto\/vendor\/open-telemetry\/api\/Common\/Instrumentation\/Globals.php(82): OpenTelemetry\\SDK\\SdkAutoloader::OpenTelemetry\\SDK\\{closure}(Object(OpenTelemetry\\API\\Common\\Instrumentation\\Configurator))\n#3 \/Users\/pdelewski\/Projects\/slim\/slimautoloading\/slimauto\/vendor\/open-telemetry\/api\/Common\/Instrumentation\/Globals.php(43): OpenTelemetry\\API\\Common\\Instrumentation\\Globals::globals()\n#4 \/Users\/pdelewski\/Projects\/slim\/slimautoloading\/slimauto\/vendor\/open-telemetry\/api\/Common\/Instrumentation\/CachedInstrumentation.php(62): OpenTelemetry\\API\\Common\\Instrumentation\\Globals::tracerProvider()\n#5 \/Users\/pdelewski\/Projects\/slim\/slimautoloading\/slimauto\/vendor\/open-telemetry\/opentelemetry-auto-wordpress\/_register.php(23): OpenTelemetry\\API\\Common\\Instrumentation\\CachedInstrumentation->tracer()\n#6 \/Users\/pdelewski\/Projects\/slim\/slimautoloading\/slimauto\/vendor\/composer\/autoload_real.php(41): require('\/Users\/pdelewsk...')\n#7 \/Users\/pdelewski\/Projects\/slim\/slimautoloading\/slimauto\/vendor\/composer\/autoload_real.php(45): ComposerAutoloaderInit8dc00416002513b0b0c1bb1605999644::{closure}('2497cfe3497c24b...', '\/Users\/pdelewsk...')\n#8 \/Users\/pdelewski\/Projects\/slim\/slimautoloading\/slimauto\/vendor\/autoload.php(25): ComposerAutoloaderInit8dc00416002513b0b0c1bb1605999644::getLoader()\n#9 \/Users\/pdelewski\/Projects\/slim\/slimautoloading\/slimauto\/public\/index.php(13): require('\/Users\/pdelewsk...')\n#10 {main}"
    }
}

Additional context

I tried to use zipkin exporter. The problem seems to be related to autoload order as composer loads auto instrumentation packages before sdk and contrib. For instance

        '9ed2f81cfd036362dee12c1eeaff3efb' => __DIR__ . '/..' . '/open-telemetry/opentelemetry-auto-pdo/_register.php',
        'd55f4a7f0a7b914fde9cb74762ff184c' => __DIR__ . '/..' . '/open-telemetry/opentelemetry-auto-psr15/_register.php',
        '58ecdc6bc6b585138831611aa769a744' => __DIR__ . '/..' . '/open-telemetry/opentelemetry-auto-psr18/_register.php',
        'dfdb213a5229dd55e621055ca8fd74e1' => __DIR__ . '/..' . '/open-telemetry/opentelemetry-auto-slim/_register.php',
        '2497cfe3497c24b987ee6916a45b2f1b' => __DIR__ . '/..' . '/open-telemetry/opentelemetry-auto-wordpress/_register.php',
        '591f3a24efb4f9341faf743b03286faa' => __DIR__ . '/..' . '/open-telemetry/sdk-contrib/Grpc/_register.php',
        'aaadcedeedc15ab415814b81abfc3b22' => __DIR__ . '/..' . '/open-telemetry/sdk-contrib/Newrelic/_register.php',
        '1a69ad6042117459888439b23a3bf38b' => __DIR__ . '/..' . '/open-telemetry/sdk-contrib/Otlp/_register.php',
        '10e93c59a197a1de503484647aa332ab' => __DIR__ . '/..' . '/open-telemetry/sdk-contrib/Zipkin/_register.php',

I solved that (brute force solution) by adding into opentelemetry-auto-wordpress\_register.php

\OpenTelemetry\SDK\Registry::registerMetricExporterFactory('otlp', \OpenTelemetry\Contrib\Otlp\MetricExporterFactory::class);
\OpenTelemetry\SDK\Registry::registerTransportFactory('http', \OpenTelemetry\Contrib\Otlp\OtlpHttpTransportFactory::class);
\OpenTelemetry\SDK\Registry::registerSpanExporterFactory('zipkin', \OpenTelemetry\Contrib\Zipkin\SpanExporterFactory::class);

before creating CachedInstrumentation instance, but it's not proper solution.

brettmc commented 1 year ago

I think that the problem here is a race condition specific to the WordPress auto-instrumentation: it tries to start a span (ie actually use the SDK) as part of its autoloading initialisation. A solution might be to instead of prepending the composer autoloader (eg in .htaccess) we instead prepend a php file which runs the autoloader and then starts that span. I think that will ensure that everything is loaded and available before anything tries to use the SDK.