opentelemetry-php icon indicating copy to clipboard operation
opentelemetry-php copied to clipboard

Exporters not loaded when using auto root span

Open xvilo opened this issue 1 year ago • 6 comments

Describe your environment

  • Run https://github.com/open-telemetry/opentelemetry-php/blob/main/examples/traces/features/auto_root_span.php with OTEL_TRACES_EXPORTER set to otlp

Steps to reproduce

  • Add the auto_root_span.php example script to the public dir of my project
  • Run it with the php -S command from the script
  • Change the putenv OTEL_TRACES_EXPORTER to otlp
  • Then curl to the page I see the following logs in the console:

What is the expected behavior? What did you expect to see? It either:

  • Working
  • Giving errors about no OTLP exporter config being added

What is the actual behavior? It can't load the OLTP exporter as a whole

$ php -S localhost:8080 test_otel.php
[Thu Oct 17 08:56:52 2024] PHP 8.3.12 Development Server (http://localhost:8080) started
[Thu Oct 17 08:56:55 2024] [::1]:44470 Accepted
[Thu Oct 17 08:56:55 2024] OpenTelemetry: [warning] Error during opentelemetry initialization: Span exporter factory not defined for: otlp
#0 /my_project_location/vendor/open-telemetry/sdk/Trace/ExporterFactory.php(28): OpenTelemetry\SDK\Registry::spanExporterFactory()
#1 /my_project_location/vendor/open-telemetry/sdk/SdkAutoloader.php(87): OpenTelemetry\SDK\Trace\ExporterFactory->create()
#2 /my_project_location/vendor/open-telemetry/sdk/SdkAutoloader.php(62): OpenTelemetry\SDK\SdkAutoloader::environmentBasedInitializer()
#3 /my_project_location/vendor/open-telemetry/api/Globals.php(93): OpenTelemetry\SDK\SdkAutoloader::OpenTelemetry\SDK\{closure}()
#4 /my_project_location/vendor/open-telemetry/api/Globals.php(43): OpenTelemetry\API\Globals::globals()
#5 /my_project_location/vendor/open-telemetry/sdk/Trace/AutoRootSpan.php(39): OpenTelemetry\API\Globals::tracerProvider()
#6 /my_project_location/vendor/open-telemetry/sdk/SdkAutoloader.php(69): OpenTelemetry\SDK\Trace\AutoRootSpan::create()
#7 /my_project_location/vendor/open-telemetry/sdk/_autoload.php(5): OpenTelemetry\SDK\SdkAutoloader::autoload()
#8 /my_project_location/vendor/composer/autoload_real.php(43): require('...')
#9 /my_project_location/vendor/composer/autoload_real.php(47): {closure}()
#10 /my_project_location/vendor/autoload.php(25): ComposerAutoloaderInit075534cb7854c559e471b4339a4e7714::getLoader()
#11 /my_project_location/public/test_otel.php(26): require('...')
#12 {main} in /my_project_location/vendor/open-telemetry/api/Globals.php(95)
[Thu Oct 17 08:56:55 2024] [::1]:44470 Closing

Additional notes?

  • Initial discussion: https://cloud-native.slack.com/archives/C01NFPCV44V/p1729091207010589

From my debugging this happens because: The auto root span _register.php is loader earlier in the chain then the _register.php of the oltp exporter, not sure if it's alphabetical or something else in composer? The auto root span kicks of everything in the sdk package, and then also tries to set up the tracer The tracer has an in memory list of registered exporters, which is usually filled through the _register.php scripts. As that didn't happen yet, the exporter does not exist (yet)

If it were to used as a class, e.g. a list of predefined FQCN's then it could work since it would kick in the class loader in the background.

So you either need to find a way to chain these dependencies (don't think there is a composer way), or, from the tracer factory stuffs, directly depend on a list of predefined classes as a fallback. That could work, but will give some overhead if no authoritative classmap is used

xvilo avatar Oct 17 '24 07:10 xvilo

Hi @xvilo . Has there been any update/workaround regarding this issue?

IAmAndre avatar Oct 28 '24 15:10 IAmAndre

Uhm, work is being done on this so it isn’t an issue anymore. (https://github.com/open-telemetry/opentelemetry-php/pull/1412) Another work around for now would be to change the order of the dependencies in your composer.json, and then to dump the autoloader again

xvilo avatar Oct 28 '24 19:10 xvilo

This is how I solved this for Drupal:

https://github.com/LionsAd/opentelemetry-auto-drupal/blob/drupal-instrumentation--mega-pack/src/DrupalAutoRootSpan.php#L19-L25

as long as you have a class, which is constructed way early after the autoloaded classes, you can create the auto root span there.

LionsAd avatar Jan 29 '25 01:01 LionsAd

My current workaround to avoid the race is this:

Add a file to the project with the following content (name it something like _autoload-otel.php):

<?php

declare(strict_types=1);

use OpenTelemetry\SDK\SdkAutoloader;

if (PHP_SAPI !== 'cli') {
  $_SERVER['OTEL_PHP_AUTOLOAD_ENABLED'] = 'true';
  SdkAutoloader::autoload();
}

Then add the path to this file to the projects composer.json as an autoload file:

{
    [...]
    "autoload": {
        "files": [
            "_autoload-otel.php"
        ]
    },
    [...]
}

Note that project autoload files are loaded after dependency autoload files. As a result, when this file is interpreted, all otel extensions had the chance to register themselves. The important thing here is that OTEL_PHP_AUTOLOAD_ENABLED must not be present in the process environment.

Projects which need a way to switch this mechanism on and off just may introduce their own environment variable and check that in the if condition.

The PHP_SAPI condition makes this work with the built-in PHP server. If nobody on the project team is using the built-in server, then that check could maybe left out.

znerol avatar Feb 25 '25 22:02 znerol

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Apr 26 '25 05:04 stale[bot]

is there a way to disable the stale issue not on this?

xvilo avatar Apr 27 '25 09:04 xvilo

This issue has been automatically closed because it has not had recent activity, but it can be reopened. Thank you for your contributions.

stale[bot] avatar Jul 19 '25 05:07 stale[bot]