open-telemetry / opentelemetry-php

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

[opentelemetry-php-contrib] laravel: When loading configuration files, SDK ignores laravel's .env #1436

Open gmhafiz opened 11 hours ago

gmhafiz commented 11 hours ago

Describe your environment

OS: linux debian 12 php: 8.2 laravel: v11 open-telemetry/opentelemetry-auto-laravel: 0.0.28 open-telemetry/sdk: 1.1.2

Steps to reproduce

This is after a normal laravel installation instrumented with open-telemetry/opentelemetry-auto-laravel package. There are two ways of running laravel. Method 1 works with php artisan serve. Method 2 using php-fpm does not read environment variable.

Get it and make a copy of .env file.

git clone git@github.com:gmhafiz/laravel-otlp.git
cd laravel-otlp
cp .env.example .env

Method 1:

Run with

php artisan migrate
php artisan db:seed
php artisan serve

Monitor log for traceID

tail -f storage/logs/laravel.log

Perform a request

curl -v localhost:8000/api/users

Method 2

Run laravel using nginx and php-fpm

docker build -t otlp/laravel .
docker exec -it otlp-laravel php artisan migrate
docker exec -it otlp-laravel php artisan db:seed
docker run --name otlp-laravel --rm -p 8111:80 otlp/laravel

Perform a request

curl -v localhost:8111/api/users

What is the expected behavior?

In both methods, traceID is present. For example.

{"datetime":"2024-11-22T08:27:29.243748+00:00","traceID":"9de4bd0cfce131835f531731e950a397","level":200,"message":"random amount is ","context":[15],"extra":{"hostname":"debianDesktop","app":"Laravel","env":"local"}}

What is the actual behavior? Method 1 has traceID, but in method 2, otel is not enabled (uses noop) and traceID becomes 0000000000000000000000000000000

Additional context

Even though both methods have OTEL_PHP_AUTOLOAD_ENABLED=true set in .env file, only in the first method otel is enabled.

I am unsure the mechanism of php artisan serve is picking up values from .env

In method 2, what I think happened was the SDK tries to load values using both $_SERVER (from EnvironmentResolver.php) and getenv(). And OTEL_PHP_AUTOLOAD_ENABLED variable is false at this point for some reason.

What I have done, or try to attempt:

1) I have tried adding required variables directly into server/vhost.conf like below and it works. but I am unsure about hard coding values like these.

location ~ \.php$ {
    ...
    fastcgi_param OTEL_PHP_AUTOLOAD_ENABLED "true";
    fastcgi_param OTEL_SERVICE_NAME "laravel";
    fastcgi_param OTEL_EXPORTER_OTLP_ENDPOINT "http://localhost:4318";
    fastcgi_param OTEL_EXPORTER_OTLP_PROTOCOL "http/json";
    fastcgi_param OTEL_TRACES_EXPORTER "console";
    fastcgi_param OTEL_METRIC_EXPORTER "none";
    fastcgi_param OTEL_LOGS_EXPORTER "console";
    fastcgi_param OTEL_TRACES_SAMPLER_ARG "1";
}

2) I'm sure adding those variables to server/php.ini will work too because of PhpIniResolver.php, as advised by https://opentelemetry.io/docs/zero-code/php/#phpini-configuration. I want to avoid this method as it will affect all php applications.

While both 1) and 2) works, ideally I want this package to load values using environment variables. But no otel variables are loaded because values set in .env file are not read by the SDK.

Something could be done to open-telemetry/opentelemetry-auto-laravel package to load values from laravel's .env using helper function such as env().

Looking around, many laravel packages publish a config file under config directory. For example in config/database.php, DB_CONNECTION is read using env() helper function.

# config/database.php
<?php

return [
    'default' => env('DB_CONNECTION', 'sqlite'),
]

Laravel reads this config using a config() magic function and uses {{filename.key}} magic string as parameter. For example calling config('database.default') returns the default value set in .env which is 'sqlite'.

Suggestion

Perhaps open-telemetry/opentelemetry-auto-laravel could also publish a config file and then allow it to load those values on top of both EnvironmentResolver.php and PhpIniResolver.php loaded by open-telemetry/sdk package.

This new config file should be limited only for open-telemetry/opentelemetry-auto-laravel package. What do you think?

ChrisLightfootWild commented 9 hours ago

The instrumentation is bootstrapped before Laravel, so the .env configuration will not work.