Skip to content

Dartastic.io's OpenTelemetry API for Dart implemented by the Dartastic SDK, dartastic_opentelemetry

License

Notifications You must be signed in to change notification settings

MindfulSoftwareLLC/opentelemetry_api

OpenTelemetry API for Dart

Pub Version License OpenTelemetry API Specification

A Dart implementation of the OpenTelemetry API that strictly adheres to the OpenTelemetry (OTel) specification. This package provides a vendor-neutral, implementation-agnostic API for telemetry instrumentation in Dart applications.

Overview

This OpenTelemetry API for Dart exists as a standalone library to strictly adhere to the OpenTelemetry specification which separates API and SDK concerns. The specification requires that the API can be dropped into an app without an SDK and it will work in a no-op fashion.

This API is rarely used without an SDK. The SDK for this API is implemented by dartastic_opentelemetry, the Dartastic OTel SDK. To instrument Dart apps, include the latest dartastic_opentelemetry and use its OTel class.

To instrument Flutter applications use the Flutterific OTel SDK, flutterrific_opentelemetry to gain almost automatic instrumentation for app routes, error catching and web vitals metrics and much more. Additional Flutterific OTel SDKs hook into popular Flutter libraries for state management, networking, logging, amongst others.

Dartastic.io provides and OpenTelemetry Observability backend for Flutter apps, Dart backends and any other service or process that produces OpenTelemetry. Dartastic.io is an observability background built on open standards, catering specifically to Flutter and Dart applications with the ability to show Dart source code lines and function calls from production errors and logs. Dartastic.io comes with a generous data parameters, various levels of free, paid and enterprise support and additional pro library features that are not available in the open source offering including telemetry that integrates with native code and Real-Time User Monitoring of Flutter apps, training and consulting.

This opentelemetry_api OTel API for Dart exists as a standalone library to strictly adhere to the OpenTelemetry specification which separates API and the SDK. The specification requires that the API can be dropped into an app without an SDK and it will work in a no-op fashion. You could include just opentelemetry_api in your pubspec.yaml top get a no-op implementation as required by the OTel specification, though this would be a rare use case. Typically, backend instrumenters will include dartastic_opentelemetry in their pubspec.yaml and this opentelemetry_api will be a transitive dependency. Flutter instrumentation developers will include flutterrific_opentelemetry.

Another direct use for this library is for developers who write instrumentation libraries.
This OpenTelemetry API is pluggable. You can create your own OTelFactory to implement your own SDK implementation. See the Dartastic OTel SDK's OTelSDKFactory for an example.

Features

  • βœ… Complete OpenTelemetry API implementation for Dart
  • βœ… Strict adherence to the OpenTelemetry specification
    • All MUST and SHOULD requirements are implemented
    • Most, if not all, MAY requirements are implemented
  • βœ… Support for all required signal types:
    • Tracing
    • Context propagation
    • Baggage
  • βœ… Fully typed API with strong Dart type safety
  • βœ… Cross-platform compatibility - works across all Dart environments (Servers, Mobile, Web, Desktop)
  • βœ… No-op implementation for safely including in any application
  • βœ… Pluggable API design - create your own SDK implementation using OTelFactory

Getting Started

Typically, you wouldn't use this library and will use Dartastic OTel dartastic_opentelemetry or flutterrific_opentelemetry instead to get a working OTel implementation in your Dart or Flutter application, respectively.

Installation

Add the package to your pubspec.yaml:

dependencies:
  opentelemetry_api: ^0.8.0

Then run:

dart pub get

Using with an SDK

This API is rarely used without an SDK. For a fully functional OpenTelemetry implementation, use one of the following:

  • Dart Backend Applications: Use the Dartastic OTel SDK.

    dependencies:
      dartastic_opentelemetry: ^1.0.0
  • Flutter Applications: Use the Flutterific OTel SDK.

    dependencies:
      flutterrific_opentelemetry: ^1.0.0

Direct API Usage (No-op Mode)

If you need a no-op OpenTelemetry implementation (unusual but compliant with the OTel spec):

dependencies:
  opentelemetry_api: ^0.8.0

Usage

The entrypoint for almost all object creation is the OTelAPI class. Again this would be rarely used, instead use the OTel class from dartastic_opentelemetry which has the same methods with addition methods for SDK objects like Resource and SpanProcessor.

All public constructors are private except the OTelAPIFactory. Use the OTelAPI to create all API objects except for Tracer and Span. The OTel specification requires that TracerProviders must provide a function for getting a Tracer and that Span's must only be created from a Tracer. Some immutable objects can also be created by copy with, copyWith and copyWithout methods on those objects such as Baggage Baggage copyWith(String key, String value, [String? metadata]) and Baggage copyWithout(String key).

In order to strictly comply with the limited types the OpenTelemetry specification allows for Attributes there's no generic OTelAPI.attribute<T> creation method and instead, to provide a typesafe API, there are 8 creation methods for String, bool, int, double and Lists of those types, i.e. OTelAPI.attributeString('foo', 'bar'), OTelAPI.attributeIntList('baz', [1, 2, 3]).

The OTelAPI has additional "factory"-like methods, i.e. baggageForMap(Map<String, String> keyValuePairs).

Usage Examples

Basic Tracing Example

import 'package:opentelemetry_api/opentelemetry_api.dart';

void main() {
  // Create a tracer
  final tracer = OTelAPI.tracerProvider().getTracer('example-service');
  
  // Create and use a span
  Span rootSpan = tracer.startSpan('main-operation');
  try {
    // Your business logic here
    rootSpan.setBoolAttribute('operation.success', true);
    
    // Create a child span for a sub-operation
    Span childSpan = tracer.startSpan('sub-operation');
    try {
      // Sub-operation logic
      childSpan.setIntAttribute('operation.value', 42);
    } finally {
      childSpan.end();
    }
  } catch (e, stackTrace) {
    // Record the error
    rootSpan
      ..setStatus(SpanStatusCode.error, e.toString())
      ..recordException(e, stackTrace: stackTrace);
    rethrow;
  } finally {
    rootSpan.setStatus(SpanStatusCode.Ok);
    // Always end the span
    rootSpan.end();
  }
}

Using Context and Baggage

import 'package:opentelemetry_api/opentelemetry_api.dart';

void main() {
  // Create baggage with user info
  Baggage baggage = OTelAPI.baggageForMap({
    'userId': 'user-123',
    'tenant': 'example-tenant'
  });

  // Create a context with this baggage
  Context context = OTelAPI.context(baggage: baggage);
  
  // Make this the current context
  Context.current = context;
  
  // Later, retrieve baggage from current context
  Baggage currentBaggage = Baggage.fromContext(Context.current);
  String? userId = currentBaggage.getEntry('userId')?.value;
}

Working with Attributes

import 'package:opentelemetry_api/opentelemetry_api.dart';

void main() {
  // Using the typesafe API methods
  Attributes attributes = OTelAPI.attributes([
    OTelAPI.attributeString('service.name', 'payment-processor'),
    OTelAPI.attributeInt('retry.count', 3),
    OTelAPI.attributeDouble('request.duration', 0.125),
    OTelAPI.attributeBool('request.success', true),
    OTelAPI.attributeStringList('tags', ['payment', 'critical']),
  ]);
  
  // Using Map extension
  Attributes fromMap = <String, Object>{
    'http.method': 'GET',
    'http.url': 'https://api.example.com/users',
    'http.status_code': 200,
    'environment': 'production',
    'user.roles': ['admin', 'operator'],
  }.toAttributes();
  
  // Example from original README
  Attributes equalToTheAbove = Attributes.of({
    'example_string_key': 'foo',
    'example_double_key': 42.1,
    'example_bool_list_key': [true, false, true],
    'example_int_list_key': [42, 43, 44],
  });
}

See the /example folder for more complete examples.

API Overview

Main API Components

  • OTelAPI - The main entry point for creating API objects
  • Tracer - Creates spans for tracing operations
  • Span - Represents a unit of work or operation
  • Context - Carries execution metadata across API boundaries
  • Baggage - Provides a mechanism to propagate key-value pairs alongside a context
  • Attributes - Represent keyvalue pairs with a known set of value types

Important OTelAPI Methods

The entrypoint for almost all object creation is the OTelAPI class. In real applications, you would typically use the OTel class from an SDK implementation.

// Get the tracer provider
TracerProvider provider = OTelAPI.tracerProvider();

// Create context
Context context = OTelAPI.context(baggage: baggage, spanContext: spanContext);

// Create attributes
Attribute attr1 = OTelAPI.attributeString('key', 'value');
Attribute attr2 = OTelAPI.attributeInt('count', 42);
Attributes attributes = OTelAPI.attributes([attr1, attr2]);

// Create baggage
Baggage baggage = OTelAPI.baggageForMap({'userId': 'user-123'});

Usage Patterns

All public constructors are private except the OTelAPIFactory. Use the OTelAPI to create all API objects except for Tracer and Span. The OTel specification requires that TracerProviders must provide a function for getting a Tracer and that Span's must only be created from a Tracer. Some immutable objects can also be created by copy with, copyWith and copyWithout methods on those objects such as Baggage Baggage copyWith(String key, String value, [String? metadata]) and Baggage copyWithout(String key).

In order to strictly comply with the limited types the OpenTelemetry specification allows for Attributes there's no generic OTelAPI.attribute<T> creation method and instead, to provide a typesafe API, there are 8 creation methods for String, bool, int, double and Lists of those types, i.e. OTelAPI.attributeString('foo', 'bar'), OTelAPI.attributeIntList('baz', [1, 2, 3]).

CNCF Contribution and Alignment

This project aims to align with Cloud Native Computing Foundation (CNCF) best practices:

  • Interoperability - Works with the broader OpenTelemetry ecosystem
  • Specification compliance - Strictly follows the OpenTelemetry specification
  • Vendor neutrality - Provides a foundation for any OpenTelemetry SDK implementation

Commercial Support

Dartastic.io provides an OpenTelemetry Observability backend for Flutter apps, Dart backends, and any other service or process that produces OpenTelemetry data. Dartastic.io is built on open standards, specifically catering to Flutter and Dart applications with the ability to show Dart source code lines and function calls from production errors and logs.

Dartastic.io offers:

  • A generous free tier
  • Various levels of free, paid, and enterprise support
  • Advanced features not available in the open source offering
  • Native code integration and Real-Time User Monitoring for Flutter apps

For Instrumentation Library Developers

This API can be used directly by those writing instrumentation libraries. By coding against this API rather than a specific SDK implementation, your instrumentation will work with any compliant OpenTelemetry SDK.

To create your own SDK implementation, implement the OTelFactory interface. See the Dartastic OTel SDK's OTelSDKFactory for an example.

Additional Resources

License

Apache 2.0 - See the LICENSE file for details.

Acknowledgements

This Dart API, the Dartastic SDK, and Flutterific OTel are made with πŸ’™ by Michael Bushe at Mindful Software.

About

Dartastic.io's OpenTelemetry API for Dart implemented by the Dartastic SDK, dartastic_opentelemetry

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages