diff --git a/ext/autoload_php_files.c b/ext/autoload_php_files.c
index 23d786c862f..246008d4c19 100644
--- a/ext/autoload_php_files.c
+++ b/ext/autoload_php_files.c
@@ -248,7 +248,7 @@ static zend_class_entry *dd_perform_autoload(zend_string *class_name, zend_strin
}
}
- if ((get_DD_TRACE_OTEL_ENABLED() || get_DD_METRICS_OTEL_ENABLED()) && zend_string_starts_with_literal(lc_name, "opentelemetry\\") && !DDTRACE_G(otel_is_loaded)) {
+ if ((get_DD_TRACE_OTEL_ENABLED() || get_DD_METRICS_OTEL_ENABLED() || get_DD_LOGS_OTEL_ENABLED()) && zend_string_starts_with_literal(lc_name, "opentelemetry\\") && !DDTRACE_G(otel_is_loaded)) {
DDTRACE_G(otel_is_loaded) = 1;
#if PHP_VERSION_ID >= 70400 && PHP_VERSION_ID < 80000
dd_prev_ast_process = zend_ast_process;
diff --git a/ext/configuration.h b/ext/configuration.h
index c5f271b1efd..24ad8b39269 100644
--- a/ext/configuration.h
+++ b/ext/configuration.h
@@ -242,6 +242,7 @@ enum ddtrace_sidecar_connection_mode {
CONFIG(BOOL, DD_INTEGRATION_METRICS_ENABLED, "true", \
.env_config_fallback = ddtrace_conf_otel_metrics_exporter) \
CONFIG(BOOL, DD_METRICS_OTEL_ENABLED, "false") \
+ CONFIG(BOOL, DD_LOGS_OTEL_ENABLED, "false") \
CONFIG(BOOL, DD_TRACE_OTEL_ENABLED, "false") \
CONFIG(STRING, DD_TRACE_LOG_FILE, "", .ini_change = zai_config_system_ini_change) \
CONFIG(STRING, DD_TRACE_LOG_LEVEL, "error", .ini_change = ddtrace_alter_dd_trace_log_level, \
diff --git a/src/DDTrace/OpenTelemetry/CompositeResolver.php b/src/DDTrace/OpenTelemetry/CompositeResolver.php
index 25f5e754ce2..0ba0753b14a 100644
--- a/src/DDTrace/OpenTelemetry/CompositeResolver.php
+++ b/src/DDTrace/OpenTelemetry/CompositeResolver.php
@@ -19,7 +19,7 @@ class DatadogResolver implements ResolverInterface
public function retrieveValue(string $name): mixed
{
- if (!$this->isMetricsEnabled($name)) {
+ if (!$this->isSignalEnabled($name)) {
return null;
}
@@ -27,7 +27,9 @@ public function retrieveValue(string $name): mixed
return 'delta';
}
- if ($name === 'OTEL_EXPORTER_OTLP_ENDPOINT' || $name === 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT') {
+ if ($name === 'OTEL_EXPORTER_OTLP_ENDPOINT'
+ || $name === 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT'
+ || $name === 'OTEL_EXPORTER_OTLP_LOGS_ENDPOINT') {
return $this->resolveEndpoint($name);
}
@@ -36,66 +38,102 @@ public function retrieveValue(string $name): mixed
public function hasVariable(string $variableName): bool
{
- if ($variableName === 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT' ||
- $variableName === 'OTEL_EXPORTER_OTLP_ENDPOINT' ||
- $variableName === 'OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE') {
+ if ($variableName === 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT'
+ || $variableName === 'OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE') {
return \dd_trace_env_config('DD_METRICS_OTEL_ENABLED');
}
+
+ if ($variableName === 'OTEL_EXPORTER_OTLP_LOGS_ENDPOINT') {
+ return \dd_trace_env_config('DD_LOGS_OTEL_ENABLED');
+ }
+
+ if ($variableName === 'OTEL_EXPORTER_OTLP_ENDPOINT') {
+ return \dd_trace_env_config('DD_METRICS_OTEL_ENABLED')
+ || \dd_trace_env_config('DD_LOGS_OTEL_ENABLED');
+ }
+
return false;
}
- private function isMetricsEnabled(string $name): bool
+ private function isSignalEnabled(string $name): bool
{
- $metricsOnlySettings = [
+ if (in_array($name, [
'OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE',
'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT',
- ];
-
- if (in_array($name, $metricsOnlySettings, true)) {
+ ], true)) {
return \dd_trace_env_config('DD_METRICS_OTEL_ENABLED');
}
+ if ($name === 'OTEL_EXPORTER_OTLP_LOGS_ENDPOINT') {
+ return \dd_trace_env_config('DD_LOGS_OTEL_ENABLED');
+ }
+
return true;
}
private function resolveEndpoint(string $name): string
{
$isMetricsEndpoint = ($name === 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT');
- $protocol = $this->resolveProtocol($isMetricsEndpoint);
+ $isLogsEndpoint = ($name === 'OTEL_EXPORTER_OTLP_LOGS_ENDPOINT');
+ $protocol = $this->resolveProtocol($isMetricsEndpoint, $isLogsEndpoint);
- // Check for user-configured general OTLP endpoint (only when requesting metrics endpoint)
+ // For signal-specific endpoints, check whether the user configured a general OTLP endpoint
+ // and derive the signal path from it rather than the agent address.
if ($isMetricsEndpoint && Configuration::has('OTEL_EXPORTER_OTLP_ENDPOINT')) {
- return $this->buildMetricsEndpointFromGeneral($protocol);
+ return $this->buildSignalEndpointFromGeneral($protocol, Signals::METRICS);
+ }
+
+ if ($isLogsEndpoint && Configuration::has('OTEL_EXPORTER_OTLP_ENDPOINT')) {
+ return $this->buildSignalEndpointFromGeneral($protocol, Signals::LOGS);
}
- return $this->buildEndpointFromAgent($protocol, $isMetricsEndpoint);
+ return $this->buildEndpointFromAgent($protocol, $name);
}
- private function resolveProtocol(bool $metricsSpecific): ?string
+ private function resolveProtocol(bool $metricsSpecific, bool $logsSpecific): string
{
if ($metricsSpecific && Configuration::has('OTEL_EXPORTER_OTLP_METRICS_PROTOCOL')) {
- return Configuration::getEnum('OTEL_EXPORTER_OTLP_METRICS_PROTOCOL');
+ return $this->validateProtocol(Configuration::getEnum('OTEL_EXPORTER_OTLP_METRICS_PROTOCOL'));
+ }
+
+ if ($logsSpecific && Configuration::has('OTEL_EXPORTER_OTLP_LOGS_PROTOCOL')) {
+ return $this->validateProtocol(Configuration::getEnum('OTEL_EXPORTER_OTLP_LOGS_PROTOCOL'));
}
- // Call getEnum without has() check to match original behavior -
- // allows SDK defaults to be applied if they exist
+ // Call getEnum without has() check to match original behavior —
+ // allows SDK defaults to be applied if they exist.
$protocol = Configuration::getEnum('OTEL_EXPORTER_OTLP_PROTOCOL');
- return $protocol ?? self::DEFAULT_PROTOCOL;
+ return $this->validateProtocol($protocol ?? self::DEFAULT_PROTOCOL);
}
- private function buildMetricsEndpointFromGeneral(string $protocol): string
+ private function validateProtocol(string $protocol): string
+ {
+ static $valid = ['grpc', 'http/protobuf', 'http/json', 'http/ndjson'];
+ if (!in_array($protocol, $valid, true)) {
+ trigger_error(
+ "OTEL_EXPORTER_OTLP_PROTOCOL '$protocol' is not recognized. "
+ . "Valid values are: grpc, http/protobuf, http/json, http/ndjson. "
+ . "Falling back to 'http/protobuf'.",
+ E_USER_WARNING
+ );
+ return self::DEFAULT_PROTOCOL;
+ }
+ return $protocol;
+ }
+
+ private function buildSignalEndpointFromGeneral(string $protocol, string $signal): string
{
$generalEndpoint = rtrim(Configuration::getString('OTEL_EXPORTER_OTLP_ENDPOINT'), '/');
if ($this->isGrpc($protocol)) {
- return $generalEndpoint . OtlpUtil::method(Signals::METRICS);
+ return $generalEndpoint . OtlpUtil::method($signal);
}
- return $generalEndpoint . '/v1/metrics';
+ return $generalEndpoint . '/v1/' . $signal;
}
- private function buildEndpointFromAgent(string $protocol, bool $isMetricsEndpoint): string
+ private function buildEndpointFromAgent(string $protocol, string $endpointName): string
{
$agentInfo = $this->resolveAgentInfo();
@@ -107,8 +145,12 @@ private function buildEndpointFromAgent(string $protocol, bool $isMetricsEndpoin
$port = $this->isGrpc($protocol) ? self::GRPC_PORT : self::HTTP_PORT;
$endpoint = $agentInfo['scheme'] . '://' . $agentInfo['host'] . ':' . $port;
- if ($isMetricsEndpoint) {
- return $this->appendMetricsPath($endpoint, $protocol);
+ if ($endpointName === 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT') {
+ return $this->appendSignalPath($endpoint, $protocol, Signals::METRICS);
+ }
+
+ if ($endpointName === 'OTEL_EXPORTER_OTLP_LOGS_ENDPOINT') {
+ return $this->appendSignalPath($endpoint, $protocol, Signals::LOGS);
}
return $endpoint;
@@ -156,13 +198,13 @@ private function resolveAgentInfo(): array
return ['scheme' => $scheme, 'host' => $host];
}
- private function appendMetricsPath(string $endpoint, string $protocol): string
+ private function appendSignalPath(string $endpoint, string $protocol, string $signal): string
{
if ($this->isGrpc($protocol)) {
- return $endpoint . OtlpUtil::method(Signals::METRICS);
+ return $endpoint . OtlpUtil::method($signal);
}
- return $endpoint . '/v1/metrics';
+ return $endpoint . '/v1/' . $signal;
}
private function isGrpc(string $protocol): bool
diff --git a/src/DDTrace/OpenTelemetry/Configuration.php b/src/DDTrace/OpenTelemetry/Configuration.php
index 0aaf52703c6..26f0d8ae9e6 100644
--- a/src/DDTrace/OpenTelemetry/Configuration.php
+++ b/src/DDTrace/OpenTelemetry/Configuration.php
@@ -9,14 +9,25 @@
'OTEL_METRIC_EXPORT_INTERVAL',
'OTEL_METRIC_EXPORT_TIMEOUT',
+ // OpenTelemetry Logs SDK Configurations
+ 'OTEL_LOGS_EXPORTER',
+ 'OTEL_BLRP_SCHEDULE_DELAY',
+ 'OTEL_BLRP_MAX_QUEUE_SIZE',
+ 'OTEL_BLRP_MAX_EXPORT_BATCH_SIZE',
+ 'OTEL_BLRP_EXPORT_TIMEOUT',
+
// OTLP Exporter Configurations
'OTEL_EXPORTER_OTLP_METRICS_PROTOCOL',
+ 'OTEL_EXPORTER_OTLP_LOGS_PROTOCOL',
'OTEL_EXPORTER_OTLP_PROTOCOL',
'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT',
+ 'OTEL_EXPORTER_OTLP_LOGS_ENDPOINT',
'OTEL_EXPORTER_OTLP_ENDPOINT',
'OTEL_EXPORTER_OTLP_METRICS_HEADERS',
+ 'OTEL_EXPORTER_OTLP_LOGS_HEADERS',
'OTEL_EXPORTER_OTLP_HEADERS',
'OTEL_EXPORTER_OTLP_METRICS_TIMEOUT',
+ 'OTEL_EXPORTER_OTLP_LOGS_TIMEOUT',
'OTEL_EXPORTER_OTLP_TIMEOUT',
'OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE',
];
diff --git a/src/DDTrace/OpenTelemetry/Detectors/Environment.php b/src/DDTrace/OpenTelemetry/Detectors/Environment.php
index cf8d74fb4e1..71873127104 100644
--- a/src/DDTrace/OpenTelemetry/Detectors/Environment.php
+++ b/src/DDTrace/OpenTelemetry/Detectors/Environment.php
@@ -10,7 +10,7 @@ function (\DDTrace\HookData $hook) {
$ddEnv = \dd_trace_env_config('DD_ENV');
if ($ddEnv !== '') {
- $attributes['deployment.environment.name'] = $ddEnv;
+ $attributes['deployment.environment'] = $ddEnv;
}
$ddVersion = \dd_trace_env_config('DD_VERSION');
diff --git a/src/DDTrace/OpenTelemetry/Detectors/Host.php b/src/DDTrace/OpenTelemetry/Detectors/Host.php
index e8d2879e066..ceccdfcacca 100644
--- a/src/DDTrace/OpenTelemetry/Detectors/Host.php
+++ b/src/DDTrace/OpenTelemetry/Detectors/Host.php
@@ -1,21 +1,29 @@
$ddHostname]);
}
+ return;
}
- DetectorHelper::mergeAttributes($hook, $attributes);
- });
\ No newline at end of file
+ // DD_TRACE_REPORT_HOSTNAME is not set — strip auto-detected host.name so it
+ // doesn't appear in logs unless explicitly set in OTEL_RESOURCE_ATTRIBUTES.
+ $filtered = [];
+ foreach ($hook->returned->getAttributes() as $key => $value) {
+ if ($key !== 'host.name') {
+ $filtered[$key] = $value;
+ }
+ }
+ $builder = (new AttributesFactory())->builder($filtered);
+ $hook->overrideReturnValue(ResourceInfo::create($builder->build(), $hook->returned->getSchemaUrl()));
+ });
diff --git a/src/DDTrace/OpenTelemetry/OtlpHooks.php b/src/DDTrace/OpenTelemetry/OtlpHooks.php
new file mode 100644
index 00000000000..96f26d5f4db
--- /dev/null
+++ b/src/DDTrace/OpenTelemetry/OtlpHooks.php
@@ -0,0 +1,79 @@
+returned;
+ if (!($future instanceof \OpenTelemetry\SDK\Common\Future\ErrorFuture)) {
+ return;
+ }
+
+ try {
+ $r = new \ReflectionProperty(\OpenTelemetry\SDK\Common\Future\ErrorFuture::class, 'throwable');
+ $r->setAccessible(true);
+ $e = $r->getValue($future);
+ } catch (\Throwable $ignored) {
+ return;
+ }
+
+ if (!($e instanceof \RuntimeException) || $e->getCode() !== 404) {
+ return;
+ }
+
+ static $warned404 = false;
+ if (!$warned404) {
+ $warned404 = true;
+ trigger_error(
+ 'Datadog OpenTelemetry OTLP export received HTTP 404 Not Found. '
+ . 'Ensure Datadog Agent >= 7.48.0 is running and configured to accept OTLP data '
+ . '(set DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_HTTP_ENDPOINT or equivalent).',
+ E_USER_WARNING
+ );
+ }
+ }
+);
+
+// Protocol fallback -------------------------------------------------------
+// The OTel SDK's Protocols::contentType() calls validate() which throws
+// UnexpectedValueException for unknown protocols. We replace an invalid value
+// with 'http/protobuf' before the method body runs, emitting a one-time
+// warning so the user knows their configuration was ignored.
+\DDTrace\install_hook(
+ 'OpenTelemetry\Contrib\Otlp\Protocols::contentType',
+ function (\DDTrace\HookData $hook) {
+ $protocol = $hook->args[0] ?? null;
+ if ($protocol === null) {
+ return;
+ }
+
+ static $valid = ['grpc', 'http/protobuf', 'http/json', 'http/ndjson'];
+ if (in_array($protocol, $valid, true)) {
+ return;
+ }
+
+ static $warnedProtocol = false;
+ if (!$warnedProtocol) {
+ $warnedProtocol = true;
+ trigger_error(
+ "OpenTelemetry OTLP protocol '$protocol' is not recognized. "
+ . "Valid values are: grpc, http/protobuf, http/json, http/ndjson. "
+ . "Falling back to 'http/protobuf'.",
+ E_USER_WARNING
+ );
+ }
+
+ $hook->args[0] = 'http/protobuf';
+ }
+);
diff --git a/src/api/Log/DatadogLogger.php b/src/api/Log/DatadogLogger.php
index da46d599be6..5fa8bf6beac 100644
--- a/src/api/Log/DatadogLogger.php
+++ b/src/api/Log/DatadogLogger.php
@@ -160,7 +160,7 @@ private static function format(string $level, $message, array $context = []): st
private static function handleLogInjection(): array
{
$logInjection = \dd_trace_env_config('DD_LOGS_INJECTION');
- if ($logInjection) {
+ if ($logInjection && !\dd_trace_env_config('DD_LOGS_OTEL_ENABLED')) {
$traceId = \DDTrace\logs_correlation_trace_id();
$spanId = \dd_trace_peek_span_id();
if ($traceId && $spanId) {
diff --git a/src/bridge/_files_opentelemetry.php b/src/bridge/_files_opentelemetry.php
index bd218ea8029..799c8311d4d 100644
--- a/src/bridge/_files_opentelemetry.php
+++ b/src/bridge/_files_opentelemetry.php
@@ -9,6 +9,7 @@
__DIR__ . '/../DDTrace/OpenTelemetry/CachedInstrumentation.php',
__DIR__ . '/../DDTrace/OpenTelemetry/CompositeResolver.php',
__DIR__ . '/../DDTrace/OpenTelemetry/Configuration.php',
+ __DIR__ . '/../DDTrace/OpenTelemetry/OtlpHooks.php',
__DIR__ . '/../DDTrace/OpenTelemetry/Detectors/DetectorHelper.php',
__DIR__ . '/../DDTrace/OpenTelemetry/Detectors/Environment.php',
__DIR__ . '/../DDTrace/OpenTelemetry/Detectors/Host.php',
diff --git a/tests/OpenTelemetry/Integration/LogsTest.php b/tests/OpenTelemetry/Integration/LogsTest.php
new file mode 100644
index 00000000000..68d5277000d
--- /dev/null
+++ b/tests/OpenTelemetry/Integration/LogsTest.php
@@ -0,0 +1,206 @@
+= 1;
+ }
+
+ private static function hasExportersInstalled(): bool
+ {
+ return class_exists('OpenTelemetry\Contrib\Otlp\OtlpUtil');
+ }
+
+ protected function ddSetUp(): void
+ {
+ \dd_trace_serialize_closed_spans();
+ parent::ddSetUp();
+ }
+
+ public function ddTearDown(): void
+ {
+ if (class_exists(ContextStorage::class)) {
+ Context::setStorage(new ContextStorage()); // Reset OpenTelemetry context
+ }
+ parent::ddTearDown();
+ self::putEnv("DD_LOGS_OTEL_ENABLED=");
+ self::putEnv("DD_TRACE_GENERATE_ROOT_SPAN=");
+ \dd_trace_serialize_closed_spans();
+ }
+
+ /**
+ * Test that the OpenTelemetry SDK classes exist when the SDK is installed
+ */
+ public function testOtelSdkClassesExist()
+ {
+ if (!self::isOtelVersionSupported()) {
+ $this->markTestSkipped('OpenTelemetry version 1.0 or higher is required for these tests');
+ }
+
+ $this->assertTrue(
+ class_exists('OpenTelemetry\SDK\Logs\LoggerProvider'),
+ 'OpenTelemetry SDK LoggerProvider should be available'
+ );
+
+ $this->assertTrue(
+ class_exists('OpenTelemetry\SDK\Resource\ResourceInfo'),
+ 'OpenTelemetry SDK ResourceInfo should be available'
+ );
+ }
+
+ /**
+ * Test that the OTLP logs exporter is available when the contrib package is installed
+ */
+ public function testOtelLogsExporterInstalled()
+ {
+ if (!self::isOtelVersionSupported()) {
+ $this->markTestSkipped('OpenTelemetry version 1.0 or higher is required for these tests');
+ }
+
+ if (!self::hasExportersInstalled()) {
+ $this->markTestSkipped('Tests only compatible with the opentelemetry exporters installed');
+ }
+
+ $this->assertTrue(
+ class_exists('OpenTelemetry\Contrib\Otlp\LogsExporter'),
+ 'OTLP LogsExporter should be available'
+ );
+
+ $this->assertTrue(
+ class_exists('OpenTelemetry\Contrib\Otlp\OtlpUtil'),
+ 'OtlpUtil should be available for endpoint configuration'
+ );
+ }
+
+ /**
+ * Test that the OpenTelemetry LoggerProvider is accessible when DD_LOGS_OTEL_ENABLED is set
+ */
+ public function testOtelLogsEnabled()
+ {
+ if (!self::isOtelVersionSupported()) {
+ $this->markTestSkipped('OpenTelemetry version 1.0 or higher is required for these tests');
+ }
+
+ if (!self::hasExportersInstalled()) {
+ $this->markTestSkipped('Tests only compatible with the opentelemetry exporters installed');
+ }
+
+ self::putEnvAndReloadConfig(['DD_LOGS_OTEL_ENABLED=true']);
+
+ $loggerProvider = \OpenTelemetry\API\Globals::loggerProvider();
+
+ $this->assertNotNull(
+ $loggerProvider,
+ 'OpenTelemetry logger provider should be available when DD_LOGS_OTEL_ENABLED is set'
+ );
+ }
+
+ /**
+ * Test that the LoggerProvider is a proxy/noop when DD_LOGS_OTEL_ENABLED is not set
+ * @dataProvider disabledLogsProvider
+ */
+ public function testOtelLogsDisabledAndUnset(?string $envValue)
+ {
+ if (!self::isOtelVersionSupported()) {
+ $this->markTestSkipped('OpenTelemetry version 1.0 or higher is required for these tests');
+ }
+
+ if (!self::hasExportersInstalled()) {
+ $this->markTestSkipped('Tests only compatible with the opentelemetry exporters installed');
+ }
+
+ if ($envValue === null) {
+ self::putEnv("DD_LOGS_OTEL_ENABLED=");
+ } else {
+ self::putEnvAndReloadConfig(["DD_LOGS_OTEL_ENABLED=$envValue"]);
+ }
+
+ // Get the logger provider — should be a proxy/noop when not enabled
+ $loggerProvider = \OpenTelemetry\API\Globals::loggerProvider();
+
+ $providerClass = get_class($loggerProvider);
+ $isProxyOrNoop = (
+ $loggerProvider === null ||
+ strpos($providerClass, 'Proxy') !== false ||
+ strpos($providerClass, 'Noop') !== false
+ );
+
+ $this->assertTrue(
+ $isProxyOrNoop,
+ "OpenTelemetry logs provider should not be auto-configured when DD_LOGS_OTEL_ENABLED is '$envValue'. Got: $providerClass"
+ );
+ }
+
+ public static function disabledLogsProvider(): array
+ {
+ return [
+ 'unset' => [null],
+ 'false' => ['false'],
+ ];
+ }
+
+ /**
+ * Test that DD_LOGS_OTEL_ENABLED configuration option is recognized
+ */
+ public function testDdLogsOtelEnabledConfigExists()
+ {
+ self::putEnvAndReloadConfig(['DD_LOGS_OTEL_ENABLED=true']);
+ $this->assertTrue(
+ \dd_trace_env_config('DD_LOGS_OTEL_ENABLED'),
+ 'DD_LOGS_OTEL_ENABLED should be true when set'
+ );
+
+ self::putEnvAndReloadConfig(['DD_LOGS_OTEL_ENABLED=false']);
+ $this->assertFalse(
+ \dd_trace_env_config('DD_LOGS_OTEL_ENABLED'),
+ 'DD_LOGS_OTEL_ENABLED should be false when set to false'
+ );
+ }
+}
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
index c2817d25d85..399e4f8273d 100644
--- a/tests/phpunit.xml
+++ b/tests/phpunit.xml
@@ -95,6 +95,7 @@
./OpenTelemetry/Integration/InteroperabilityTest.php
./OpenTelemetry/Integration/InternalTelemetryTest.php
./OpenTelemetry/Integration/MetricsTest.php
+ ./OpenTelemetry/Integration/LogsTest.php
./Integrations/Slim/V3_12