nucleardog/telemetry

Instrument your PHP application

v0.0.10 2024-03-29 11:36 UTC

This package is auto-updated.

Last update: 2024-04-29 15:51:28 UTC


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 automatically
           be 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 have
             the 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 name
  • APP_ENV: Used to report the environment it is running in
  • TELEMETRY_OPTIONS_IS_GCP: Uses alternative attribute labels that better align
                            with GCP's standards.
    
  • TELEMETRY_ENDPOINT_TYPE: One of null, 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 instrumentation
                                     and 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.