Skip to main content
This page covers instrumenting a PHP application with the OpenTelemetry SDK to send logs and traces to Bronto over OTLP/HTTP via a local OTel Collector. Logs are bridged via a Monolog handler — no log statement changes needed. Traces are added by configuring a tracer provider alongside the log provider.
If you don’t have a Collector and want to export directly from your application to Bronto, see Direct export to Bronto at the bottom of this page.

Prerequisites

Install dependencies

composer require \
  open-telemetry/api \
  open-telemetry/sdk \
  open-telemetry/exporter-otlp \
  open-telemetry/opentelemetry-logger-monolog \
  monolog/monolog \
  php-http/guzzle7-adapter \
  guzzlehttp/psr7
PackagePurpose
open-telemetry/apiCore OTel API
open-telemetry/sdkSDK — LoggerProvider, processors, resource
open-telemetry/exporter-otlpOTLP/HTTP exporter
open-telemetry/opentelemetry-logger-monologBridges Monolog into OTel
php-http/guzzle7-adapterHTTP client for the exporter

Configure the log bridge

Set up a LoggerProvider with an OTLP exporter and attach the OtelHandler to your Monolog logger.
configure_logging.php
<?php

use Monolog\Logger;
use OpenTelemetry\Contrib\Logs\Monolog\Handler as OtelHandler;
use OpenTelemetry\Contrib\Otlp\LogsExporter;
use OpenTelemetry\Contrib\Otlp\OtlpHttpTransportFactory;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Logs\LoggerProvider;
use OpenTelemetry\SDK\Logs\Processor\BatchLogRecordProcessor;
use OpenTelemetry\SDK\Resource\ResourceInfo;
use OpenTelemetry\SemConv\ResourceAttributes;

function configureOtelLogging(): Logger
{
    $resource = ResourceInfo::create(Attributes::create([
        ResourceAttributes::SERVICE_NAME      => 'my-service',
        ResourceAttributes::SERVICE_NAMESPACE => 'my-team',
        'deployment.environment'              => 'production',
    ]));

    $transport = (new OtlpHttpTransportFactory())->create(
        'http://localhost:4318/v1/logs',
        'application/x-protobuf'
    );

    $exporter = new LogsExporter($transport);

    $loggerProvider = LoggerProvider::builder()
        ->setResource($resource)
        ->addLogRecordProcessor(new BatchLogRecordProcessor($exporter))
        ->build();

    $handler = new OtelHandler($loggerProvider, Logger::DEBUG);

    $logger = new Logger('my-service');
    $logger->pushHandler($handler);
    $logger->pushHandler(new \Monolog\Handler\StreamHandler('php://stdout', Logger::DEBUG));

    return $logger;
}

Configure the OTLP exporter

The OtlpHttpTransportFactory in the snippet above connects to the OTel Collector on localhost:4318. If your Collector runs on a different host or port, update the URL accordingly.

Set resource attributes

Resource attributes are attached to every log record exported from this process. Two attributes drive how Bronto organises incoming logs:
OTel attributeBronto conceptDescription
service.nameDatasetGroups logs from one service
service.namespaceCollectionGroups related services or a team’s services
These are set via ResourceInfo::create in the setup above.

Complete example

index.php
<?php

require __DIR__ . '/vendor/autoload.php';
require __DIR__ . '/configure_logging.php';

$logger = configureOtelLogging();

$logger->info('Application started');
$logger->warning('Low disk space', ['disk_free_gb' => 2.1]);
$logger->error('Database connection failed', ['exception' => 'timeout']);
Existing Monolog log statements require no changes. The OtelHandler is added alongside any existing handlers (console, file, etc.) so both continue to work.

Verify log collection

After running your application, open the Search page in Bronto. Filter by the dataset name you set in service.name — your log records should appear within a few seconds. If no logs appear, check:
  • The OTel Collector is running and reachable at the configured endpoint.
  • The Collector’s pipeline includes a logs pipeline with an otlp receiver and the Bronto exporter — see Connect Open Telemetry to Bronto.
  • configureOtelLogging() is called before the first log statement.

Traces

Auto-instrumentation packages are available for Laravel, Symfony, Guzzle, PSR-18 HTTP clients, and more. Install the relevant open-telemetry/opentelemetry-auto-* package via Composer and register the instrumentation — no manual span code needed. See PHP instrumentation libraries for the full list.

Configure the tracer provider

No additional packages are needed — open-telemetry/sdk and open-telemetry/exporter-otlp already include tracing support.
configure_tracing.php
<?php

use OpenTelemetry\Contrib\Otlp\SpanExporter;
use OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;

function configureOtelTracing(ResourceInfo $resource): TracerProvider
{
    $transport = (new OtlpHttpTransportFactory())->create(
        'http://localhost:4318/v1/traces',
        'application/x-protobuf'
    );

    $spanExporter = new SpanExporter($transport);

    $tracerProvider = TracerProvider::builder()
        ->setResource($resource)
        ->addSpanProcessor(new BatchSpanProcessor($spanExporter))
        ->build();

    \OpenTelemetry\API\Globals::registerInitializer(function (Configurator $configurator) use ($tracerProvider) {
        $configurator->withTracerProvider($tracerProvider);
    });

    return $tracerProvider;
}
Pass the same $resource used for logging so both signals share service.name and service.namespace.

Creating spans

$tracer = $tracerProvider->getTracer('my-service');

$span = $tracer->spanBuilder('process-payment')->startSpan();
$scope = $span->activate();
try {
    $span->setAttribute('payment.amount', 99.99);
    $logger->info('Processing payment');  // trace_id and span_id injected automatically
} finally {
    $scope->detach();
    $span->end();
}

Direct export to Bronto

If you are not using an OTel Collector, export directly to Bronto by replacing the transport configurations with the Bronto OTLP endpoints and your API key:
// Logs
$logTransport = (new OtlpHttpTransportFactory())->create(
    'https://ingestion.eu.bronto.io/v1/logs', // or ingestion.us.bronto.io
    'application/x-protobuf',
    ['x-bronto-api-key' => '<YOUR_API_KEY>']
);

// Traces
$traceTransport = (new OtlpHttpTransportFactory())->create(
    'https://ingestion.eu.bronto.io/v1/traces', // or ingestion.us.bronto.io
    'application/x-protobuf',
    ['x-bronto-api-key' => '<YOUR_API_KEY>']
);
RegionLogs endpointTraces endpoint
EUhttps://ingestion.eu.bronto.io/v1/logshttps://ingestion.eu.bronto.io/v1/traces
UShttps://ingestion.us.bronto.io/v1/logshttps://ingestion.us.bronto.io/v1/traces
See API Keys for how to create a key with ingestion permissions. No other changes to the rest of the setup are required.