Thanks to visit codestin.com
Credit goes to docs.tracewayapp.com

Symfony
Logs

Logs

Forward your Symfony application logs to Traceway via the OpenTelemetry Logs OTLP endpoint. The recommended path is a Monolog handler that bridges Symfony's standard PSR-3 logger to the OTel Logs SDK — all of your existing $logger->info(...) / $logger->error(...) calls keep working, and each log is automatically linked to the active trace and span.

Install the Logs Packages

composer require \
    open-telemetry/opentelemetry-logger-monolog \
    open-telemetry/sdk \
    open-telemetry/exporter-otlp
  • opentelemetry-logger-monolog — Monolog handler that emits records to the OTel Logs SDK.
  • sdk and exporter-otlp — already installed if you completed the Quick Start, listed here for completeness.

Configure Environment Variables

Extend the env config from the Quick Start to also enable the logs exporter:

# Existing traces + metrics config from the Quick Start
OTEL_PHP_AUTOLOAD_ENABLED=true
OTEL_SERVICE_NAME=my-symfony-app
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=otlp
 
# New: enable OTLP logs
OTEL_LOGS_EXPORTER=otlp
 
OTEL_EXPORTER_OTLP_PROTOCOL=http/json
OTEL_EXPORTER_OTLP_ENDPOINT=https://your-traceway-instance.com/api/otel
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer your-project-token"

OTEL_EXPORTER_OTLP_ENDPOINT is the base URL — the logs exporter appends /v1/logs automatically. No extra endpoint config is needed.

Wire the Monolog Handler

Register the OTel Monolog handler in config/packages/monolog.yaml so every channel (app, request, security, doctrine, …) is forwarded to Traceway:

# config/packages/monolog.yaml
monolog:
    handlers:
        traceway:
            type: service
            id: OpenTelemetry\Contrib\Logs\Monolog\Handler
            level: info
            channels: ~   # all channels
 
services:
    OpenTelemetry\Contrib\Logs\Monolog\Handler:
        arguments:
            $loggerProvider: '@OpenTelemetry\API\Logs\LoggerProviderInterface'
            $level: !php/const Monolog\Logger::INFO
            $bubble: true

The $loggerProvider argument is resolved by the OTel PHP autoloader — it's available as a service as soon as OTEL_PHP_AUTOLOAD_ENABLED=true is set.

Set level to the Monolog level threshold you want forwarded. Use debug during early development to verify the pipeline, then raise it to info or warning in production to keep volume under control.

Emit Logs With Trace Context

Inject Symfony's standard Psr\Log\LoggerInterface as usual — the Monolog handler takes care of bridging to OTel, and trace context attaches automatically:

// src/Controller/OrderController.php
namespace App\Controller;
 
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
 
class OrderController
{
    public function __construct(
        private readonly LoggerInterface $logger,
    ) {}
 
    #[Route('/orders', methods: ['POST'])]
    public function create(): Response
    {
        $this->logger->info('order received', ['order.id' => 'ord_123']);
 
        try {
            // ... business logic ...
            $this->logger->info('order processed', ['order.id' => 'ord_123']);
            return new JsonResponse(['status' => 'ok']);
        } catch (\Throwable $e) {
            $this->logger->error('order failed', [
                'order.id' => 'ord_123',
                'exception' => $e->getMessage(),
            ]);
            throw $e;
        }
    }
}

Because the controller runs inside the OTel-instrumented request span, every log emitted here carries that span's trace_id and span_id automatically. Open the endpoint's trace in the Traceway dashboard and the Logs tab will show these records attached.

The same is true for logs emitted inside Messenger handlers, Console commands, and any other code that runs under an active span.

Severity Mapping

Monolog levels are mapped to OpenTelemetry severity numbers (and therefore Traceway's TRACE → FATAL labels) as follows:

Monolog LevelOTLP Severity NumberTraceway Severity
DEBUG5DEBUG
INFO9INFO
NOTICE10INFO
WARNING13WARN
ERROR17ERROR
CRITICAL18ERROR
ALERT19ERROR
EMERGENCY21FATAL

Only records at or above the handler's configured level threshold are forwarded.

Test Your Integration

Add a route that logs at multiple levels, hit it once, and check the Logs page in the Traceway dashboard:

// src/Controller/LogTestController.php
namespace App\Controller;
 
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
 
class LogTestController
{
    public function __construct(
        private readonly LoggerInterface $logger,
    ) {}
 
    #[Route('/log-test', name: 'log_test')]
    public function test(): Response
    {
        $this->logger->debug('debug sample');
        $this->logger->info('info sample', ['request.id' => 'req_1']);
        $this->logger->warning('warning sample');
        $this->logger->error('error sample', ['order.id' => 'ord_1']);
        return new JsonResponse(['emitted' => 4]);
    }
}

Visit /log-test, then open Logs in the dashboard. You should see all four records within a few seconds, each linked to the trace for that request.

Next Steps