nucleardog / telemetry
Instrument your PHP application
Requires
- php: ^8.2
- nyholm/psr7: ^1.8
- open-telemetry/api: ^1.0
- open-telemetry/exporter-otlp: ^1.0
- open-telemetry/sdk: ^1.0
- psr/log: ^3.0
- symfony/http-client: ^7.0
Suggests
- ext-grpc: For more efficient communication with the OTLP collector
- illuminate/support: For Laravel integration
- open-telemetry/transport-grpc: For more efficient communication with the OTLP collector
README
OpenTelemetry for PHP with instrumentation for Laravel.
This library is meant to be a simple, batteries-included way to add telemetry to your application. This does not expose a lot of the OpenTelemetry functionality, does not intend to, and will not grow to. The intent of this library is to abstract away much of the complexity that comes from the flexibility by providing a more limited interface.
Usage
Installation
$ composer require nucleardog/telemetry
Base Library
Setup
Use the builder to build and configure the telemetry library:
<?php
use Nucleardog\Telemetry\Application;
use Nucleardog\Telemetry\TelemetryBuilder;
// Configure your application's information
$myApplication = new Application(
name: 'my-app',
// Only name is required. The rest of these are optional.
namespace: 'services',
environment: 'testing',
version: '0.0.1',
);
// Use the builder to configure and build the library
$builder = new TelemetryBuilder();
$builder->setApplication($myApplication);
// Output telemetry to the console
$builder->useConsole();
// Throw it away
//$builder->useNullEndpoint();
// Use the opentelemetry protocol over http
//$builder->useOtlpHttp('https://opentel-collector.svc:4318', 'my-service');
// Use the opentelemetry protocol over grpc; install the grpc extension for
// better performance.
//$builder->useOtlpGrpc('https://opentel-collector.svc:4317', 'my-service');
$telemetry = $builder->build();
// The builder can also be used "fluently"
// $telemetry = (new TelemetryBuilder())->setApplication($myApplication)->useConsole()->build();
Traces
You can use the traces interface to work with traces and contexts:
<?php
// Start a span
$telemetry->traces->enter('my-request');
// Start another span, nesting within the first
// This is providing additional attributes for this span.
$telemetry->traces->enter('nested', ['attribute1' => true, 'attribute2' => false]);
// Log an event with attributes
$telemetry->traces->event('An event', ['a' => 1, 'b' => 2, 'c' => false]);
// Mark this span as failed with the provided message.
$telemetry->traces->error('Something went wrong!');
// Mark this span as successful
$telemetry->traces->success();
// Attach an exception to this span
$telemetry->traces->exception(new \RuntimeException('Something exceptional'));
// Leave the span
$telemetry->traces->leave();
// Run the callback within a span
$someValue = $telemetry->traces->in('nested2', function($context) {
// Do something
// The callback is called in a try/catch/finally that will:
// - Catch any exception thrown, attach it to the active span, then rethrow it.
// - Ensure we leave() this context when we're done one way or another.
// Any value returned will be passed through.
return 1234;
}, ['a' => 1, 'b' => 2, 'c' => false]);
// You can also set context variables during a span directly on the context object.
$context = $telemetry->traces->enter('nested3');
$context['nested3_attribute'] = true;
$telemetry->traces->enter('nested3.1');
// You can also fetch the current span at any point
$context = $telemetry->traces->current();
$context['nested3.1_attribute'] = true;
// You should always try and pair up enter()/leave() calls, however if you need
// to ensure that _all_ traces are closed, you can call end().
$telemetry->traces->end();
// For distributed tracing, you can encode/decode the context to pass around
// and associate remote traces/etc.
$encoded = $telemetry->traces->encode();
// ['parent' => '...', 'state' => '...' | null ]
// When you are not in an active trace, you can then pass this in to associate
// your spans with the same trace, nested under the active span.
$telemetry->traces->setParent($encoded['parent'], $encoded['state'] /* optional */);
$telemetry->traces->enter('continuing trace');
Logs
The telemetry library provides a PSR-3 compatible logger that will push your log messages through OpenTelemetry, associating them with your active traces:
<?php
// Log things
$telemetry->logs->debug('A debug message');
$telemetry->logs->info('An info message');
$telemetry->logs->warning('A warning message');
$telemetry->logs->error('An error message');
// You can pass context as well
$telemetry->logs->debug('A thing happened', ['a' => 1, 'b' => 2, 'c' => false]);
Laravel
Auto-instrumentation
By default, the library will instrument a great deal of Laravel:
- Requests: Two middlewares are supplied and installed globally. One will read
a trace ID from incoming requests' `X-Trace` header and use them to associate our traces with the parent trace. The other automatically starts and ends a trace with each request, tracking some metadata (host, method, url, matched route, response status code, etc).
- Jobs: Any job dispatched while a span is active will automatically be nested
under the active span. All jobs processed by the workers will be run in their own span. Exceptions, failures, etc will be associated with the span.
- Processes: Any process run via Laravel's
Process::
facade will automaticallybe run within its own span, tracking the command run and the exit code.
- Exceptions: A global exception reporter is registered that will report any
uncaught exceptions by associating them with an active span, if available.
- Http Client: Any requests made through Laravel's
Http::
facade will havethe active trace and span added to an `X-Trace` header before the request is sent. The request will be executed in a span, and basic metadata (request url, response status code, failures) will be attached to the span.
- Logs: All log messages, regardless of channel and log level will be associated
with the active span, if available.
If you want to disable any of this instrumentation, you can adjust these via
the environment variables documented below or create a config/telemetry.php
file in your project:
<?php
return [
'instrument' => [
'jobs' => true,
'requests' => true,
'exceptions' => true,
'logs' => true,
'processes' => true,
'http_client' => true,
],
];
You can see which instrumentation is enabled at any time with artisan about
:
$ ./artisan about
[...]
Nucleardog\Telemetry .....................................................................................
exceptions ........................................................................................ active
http_client ....................................................................................... active
jobs .............................................................................................. active
logs .............................................................................................. active
processes ......................................................................................... active
requests .......................................................................................... active
Trace Facade
The package automatically registers a Trace::
facade exposing most of the
methods outlined above:
Trace::enter(string $name, ?array $attributes = null): Context
Trace::current(): Context
Trace::leave(): Traces
Trace::end(): void
Trace::in(string $name, \Closure $callback, ?array $attributes = null): mixed
Trace::encode(): array
Trace::setParent(string $parent, ?string $state = null): Traces
Trace::event(string $name, ?array $attributes = []): Context
Trace::exception(\Throwable $ex, ?string $message = null): Context
Trace::error(?string $message = null): Context
Trace::success(): Context
Trace::current(): Context
Configuration
The library exposes the following environment variables:
APP_NAME
: Used as your application's nameAPP_ENV
: Used to report the environment it is running inTELEMETRY_OPTIONS_IS_GCP
: Uses alternative attribute labels that better alignwith GCP's standards.
TELEMETRY_ENDPOINT_TYPE
: One ofnull
,console
,otlp-http
,otlp-grpc
TELEMETRY_ENDPOINT_URL
: URL of the collector when using the otlp- types.TELEMETRY_INSTRUMENT_JOBS
: Enable/disable job instrumentation.TELEMETRY_INSTRUMENT_REQUESTS
: Enable/disable request instrumentation.TELEMETRY_INSTRUMENT_EXCEPTIONS
: Enable/disable exception logging.TELEMETRY_INSTRUMENT_LOGS
: Enable/disable log capturing.TELEMETRY_INSTRUMENT_PROCESSES
: Enable/disable process instrumentation.TELEMETRY_INSTRUMENT_HTTP_CLIENT
: Enable/disable http client instrumentationand trace propagation.
Legal
Copyright 2024 Adam Pippin hello@adampippin.ca
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.