dartastic_opentelemetry 0.8.7

Dartastic.io's OpenTelemetry SDK for Dart

OpenTelemetry SDK for Dart

License OpenTelemetry Specification

Dartastic is an OpenTelemetry SDK to add standard observability to Dart applications. Dartastic can be used with any OTel backend, it's standards-compliant.

Flutter developers should use the Flutterific OTel SDK which builds on top of Dartastic OTel.

The Dartastic and Flutterrific OTel SDK has been proposed for Donation to the CNCF. We need YOU to grow the Dartastic community and make this SDK the standard for Flutter and Dart OTel. Please use it, submit issues, support us with stars and contribute PRs. We are looking for contributors and maintainers. Also, please support the development by subscribing at [Dartastic.io][https://dartastic.io] and gain early access to the Flutter SDK and the Wondrous Demo.

Dartastic.io provides an OpenTelemetry support, training, consulting and an Observability backend customized for Flutter apps, Dart backends, and any other service or process that produces OpenTelemetry data.

Features

  • 🚀 Friendly API: An easy to use, discoverable, immutable, typesafe API that feels familiar to Dart developers.
  • 📐 Standards Compliant: Complies with the OpenTelemetry specification so it's portable and future-proof.
  • 🌎 Ecosystem:
    • Dartastic.io is an OTel backend for Dart with a generous free tier, professional support and enterprise features.
    • Flutterrific OTel adds Dartastic OTel to Flutter apps with ease. Observe app routes, errors, web vitals and more with as few as two lines of code.
  • 💪🏻 Powerful:
    • Propagate OpenTelemetry Context across async gaps and Isolates.
    • Pick from a rich set of Samplers including On/Off, probability and rate-limiting.
    • Automatically capture platform resources on initialization.
    • No skimping - If it's optional in the spec, it's included in Dartastic.
    • A pluggable and extensible API and SDK enables implementation freedom.
  • 🧷 Typesafe Semantics: Ensure you're speaking the right language with a massive set of enums matching the OpenTelemetry Semantics Conventions.
  • 📊 Excellent Performance:
    • Low overhead
    • Batch processing
    • Performance test suite for proven benchmarks
  • 🐞 Well Tested: Good test coverage (>85%).
  • 📃 Quality Documentation: If it's not clearly documented, it's a bug. Extensive examples and best practices are provided Wonderous Dartastic demonstrates the Wonderous App instrumented with OpenTelemetry.
  • ✅ **Supported Telemetry Signals and Features **:
    • Tracing with span processors and samplers
    • Metrics collection and aggregation
    • Context propagation
    • Baggage management
    • Logging is not available yet

Dartastic OTel is suitable for Dart backends, CLIs or any Dart application.

opentelemetry_api is the API for the Dartastic OTel SDK. The opentelemetry_api exists as a standalone library to strictly adhere to the OpenTelemetry specification which separates API and the SDK. All OpenTelemetry API classes on in opentelemetry_api.

Flutterrific OTel adds Dartastic OTel to Flutter apps with ease. Sign Up at Dartastic.io for early access to this soon to be open source.

Dartastic.io is an OpenTelemetry backend based on Elastic with a generous free tier.

Dartastic and Flutterrific OTel are made with 💙 by Michael Bushe at Mindful Software, the Flutter experts with support from SEMplicity, Inc., the Elastic experts.

Getting started

Include this in your pubspec.yaml:

dependencies:
  dartastic_opentelemetry: ^0.8.6

The entrypoint to the SDK is the OTel class. OTel has static "factory" methods for all OTel API and SDK objects. OTel needs to be initialized first to point to an OpenTelemetry backend. Initialization does a lot of work under the hood including gathering a rich set of standard resources for any OS that Dart runs in. It prepares for the creation of the global default TracerProvider with the serviceName and a default Tracer, both created on first use.

Environment Variables

Dartastic OpenTelemetry supports standard OpenTelemetry environment variables as defined in the OpenTelemetry Specification.

These environment variables can be set to configure the SDK behavior without changing code. Signal-specific variables take precedence over general ones.

Service Configuration

VariableDescriptionExample
OTEL_SERVICE_NAMESets the service namemy-dart-app
OTEL_SERVICE_VERSIONSets the service version1.0.0
OTEL_RESOURCE_ATTRIBUTESAdditional resource attributes as comma-separated key=value pairsenvironment=production,region=us-west

OTLP Exporter Configuration

VariableDescriptionDefaultExample
OTEL_EXPORTER_OTLP_ENDPOINTThe OTLP endpoint URLhttp://localhost:4317 for gRPC, http://localhost:4318 for HTTPhttps://otel-collector:4317
OTEL_EXPORTER_OTLP_PROTOCOLThe protocol to usehttp/protobufgrpc, http/protobuf, http/json
OTEL_EXPORTER_OTLP_HEADERSAdditional headers as comma-separated key=value pairsNoneapi-key=secret,tenant=acme
OTEL_EXPORTER_OTLP_INSECUREWhether to use insecure connectionfalsetrue
OTEL_EXPORTER_OTLP_TIMEOUTExport timeout in milliseconds100005000
OTEL_EXPORTER_OTLP_COMPRESSIONCompression to useNonegzip

Signal-Specific Configuration

Traces

VariableDescriptionDefaultExample
OTEL_TRACES_EXPORTERTrace exporter to useotlpconsole, none
OTEL_EXPORTER_OTLP_TRACES_ENDPOINTTraces-specific endpointUses general endpointhttps://traces.example.com
OTEL_EXPORTER_OTLP_TRACES_PROTOCOLTraces-specific protocolUses general protocolgrpc
OTEL_EXPORTER_OTLP_TRACES_HEADERSTraces-specific headersUses general headerstrace-key=value
OTEL_EXPORTER_OTLP_TRACES_INSECURETraces-specific insecure settingUses general settingtrue
OTEL_EXPORTER_OTLP_TRACES_TIMEOUTTraces-specific timeoutUses general timeout30000
OTEL_EXPORTER_OTLP_TRACES_COMPRESSIONTraces-specific compressionUses general compressiongzip

Metrics

VariableDescriptionDefaultExample
OTEL_METRICS_EXPORTERMetrics exporter to useotlpconsole, none
OTEL_EXPORTER_OTLP_METRICS_ENDPOINTMetrics-specific endpointUses general endpointhttps://metrics.example.com
OTEL_EXPORTER_OTLP_METRICS_PROTOCOLMetrics-specific protocolUses general protocolhttp/protobuf
OTEL_EXPORTER_OTLP_METRICS_HEADERSMetrics-specific headersUses general headersmetric-key=value
OTEL_EXPORTER_OTLP_METRICS_INSECUREMetrics-specific insecure settingUses general settingfalse
OTEL_EXPORTER_OTLP_METRICS_TIMEOUTMetrics-specific timeoutUses general timeout60000
OTEL_EXPORTER_OTLP_METRICS_COMPRESSIONMetrics-specific compressionUses general compressiongzip

Logging Configuration

VariableDescriptionExample
OTEL_LOG_LEVELSDK internal log levelTRACE, DEBUG, INFO, WARN, ERROR, FATAL
OTEL_LOG_METRICSEnable metrics loggingtrue, 1, yes, on
OTEL_LOG_SPANSEnable spans loggingtrue, 1, yes, on
OTEL_LOG_EXPORTEnable export loggingtrue, 1, yes, on
OTEL_CONSOLE_EXPORTERAdd console exporter for debuggingtrue, 1, yes, on

Usage Example with Flutter

When running a Flutter app:

flutter run \
  --dart-define=OTEL_SERVICE_NAME=my-flutter-app \
  --dart-define=OTEL_SERVICE_VERSION=1.0.0 \
  --dart-define=OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector:4317 \
  --dart-define=OTEL_EXPORTER_OTLP_PROTOCOL=grpc \
  --dart-define=OTEL_EXPORTER_OTLP_HEADERS=api-key=your-api-key

Or when running a Dart application:

export OTEL_SERVICE_NAME=my-dart-service
export OTEL_SERVICE_VERSION=2.0.0
export OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector:4318
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_LOG_LEVEL=DEBUG

dart run bin/my_app.dart

Protocol Selection

The default protocol is http/protobuf (as per OpenTelemetry specification). The supported protocols are:

  • grpc - gRPC protocol (typically port 4317)
  • http/protobuf - HTTP with protobuf encoding (typically port 4318)
  • http/json - HTTP with JSON encoding (typically port 4318)

Minimal Code Example

import 'package:dartastic_opentelemetry/dartastic_opentelemetry.dart';

void main() {
  OTel.initialize(
      serviceName: 'powerful-backend-service',
      serviceVersion: '2.0',
      tracerName: 'data-microservice',
      tracerVersion: '1.1.11',
      //OTel standard tenant_id, required for Dartastic.io
      tenantId: 'valued-customer-id',
      //required for the Dartastic.io backend
      dartasticAPIKey: '123456',
      resourceAttributes: {
        // Always consult the OTel Semantic Conventions to find an existing
        // convention name for an attribute:
        // https://opentelemetry.io/docs/specs/semconv/
        //--dart-define environment=dev
        //See https://opentelemetry.io/docs/specs/semconv/resource/deployment-environment/
        DeploymentNames.deploymentEnvironmentName.key: String.fromEnvironment('environment'),
        //--dart-define pod-name=powerful-dart-pod
        //See https://opentelemetry.io/docs/specs/semconv/resource/#kubernetes
        DeploymentNames.k8sPodName.key: String.fromEnvironment('pod - name'),
      }
  );

  // Get the default tracer
  var tracer = OTel.tracer();

  // Create a new root span
  final rootSpan = tracer.startSpan(
    'root-operation',
    attributes: OTel.attributesFromMap({
      //SourceCode attributes are atypical, this is showing off the extensive semantics
      SourceCodeNames.codeFunctionName.key: 'main',
      // The spec limits attribute values to String, bool, int, double and lists thereof.
      'readme.magic.number': 42,
      'can.I.use.a.boolean': true,
      'a.list.of.ints': [42, 143],
      'a.list.of.doubles': [42.1, 143.4],
    }),
  );

  try {
    importantFunction();
    rootSpan.addEventNow('importantFunction completed', 
            // attributedFromMap can throw with bad types, OTel has typesafe attribute methods
            OTel.attributes([
              OTel.attributeString('event-foo', 'bar'),
              OTel.attributeBool('event-baz', true)
            ]));
  } catch (e, s) {
    span.recordException(e, stackTrace: s);
    span.setStatus(SpanStatusCode.Error, 'Error running importantFunction $e');
  } finally {
    // Ending a span sets the span status to SpanStatusCode.Ok, unless 
    // the span status has already been set, per the OpenTelemetry Specification
    // See https://opentelemetry.io/docs/specs/otel/trace/api/#set-status
    span.end();
  }
}

Since dartastic_opentelemetry exports all the classes of opentelemetry_api, refer to opentelemetry_api for documentation of API classes.

See the /example folder for more examples.

OpenTelemetry Metrics API

The Metrics API in OpenTelemetry provides a way to record measurements about your application. These measurements can be exported later as metrics, allowing you to monitor and analyze the performance and behavior of your application.

Concepts

  • MeterProvider: Entry point to the metrics API, responsible for creating Meters
  • Meter: Used to create instruments for recording measurements
  • Instrument: Used to record measurements
    • Synchronous instruments: record measurements at the moment of calling their APIs
    • Asynchronous instruments: collect measurements on demand via callbacks

Instrument Types

  • Counter: Synchronous, monotonic increasing counter (can only go up)
  • UpDownCounter: Synchronous, non-monotonic counter (can go up or down)
  • Histogram: Synchronous, aggregable measurements with statistical distributions
  • Gauge: Synchronous, non-additive value that represents current state
  • ObservableCounter: Asynchronous version of Counter
  • ObservableUpDownCounter: Asynchronous version of UpDownCounter
  • ObservableGauge: Asynchronous version of Gauge

Usage Pattern

Similar to the Tracing API, the metrics API follows a multi-layered factory pattern:

  1. API Layer: Defines interfaces and provides no-op implementations
  2. SDK Layer: Provides concrete implementations
  3. Flutter Layer: Adds UI-specific functionality

The API follows the pattern of using factory methods for creation rather than constructors:

// Get a meter from the meter provider
final meter = OTel.meterProvider().getMeter('component_name');

// Create a counter instrument
final counter = meter.createCounter('my_counter');

// Record measurements
counter.add(1, {'attribute_key': 'attribute_value'});

For asynchronous instruments:

// Create an observable counter
final observableCounter = meter.createObservableCounter(
  'my_observable_counter',
  () => [Measurement(10, {'attribute_key': 'attribute_value'})],
);

Understanding Metric Types and When to Use Them

Instrument TypeUse CaseExample
CounterCount things that only increaseRequest count, completed tasks
UpDownCounterCount things that can increase or decreaseActive requests, queue size
HistogramMeasure distributionsRequest durations, payload sizes
GaugeRecord current valueCPU usage, memory usage
ObservableCounterCount things that only increase, collected on demandTotal CPU time
ObservableUpDownCounterCount things that can increase or decrease, collected on demandMemory usage
ObservableGaugeRecord current value, collected on demandCurrent temperature

Integration with Dartastic/Flutterrific

This API implementation follows the same pattern as the tracing API, where the creation of objects is managed through factory methods. This allows for a clear separation between API and SDK, and ensures that the metrics functionality can be used in a no-op mode when the SDK is not initialized.

Commercial Support

Dartastic.io provides an OpenTelemetry Observability backend specifically built for Dart and Flutter applications. Features include:

  • Enhanced tracing with source code integration
  • Real-time user monitoring for Flutter apps
  • Advanced dashboard and visualization
  • Integration with native platforms
  • Generous free tier and enterprise support options

Roadmap

  • Enhanced metrics support
  • Support for Zipkin, Jaeger
  • Integration with common Dart libraries (Dio, etc.)
  • Context propagation through http, Android, iOS, WebViews

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 vendor-neutral implementation

License

Apache 2.0 - See the LICENSE file for details.

Commercial Support

Dartastic.io provides an OpenTelemetry support, training, consulting, enhanced private packages and an Observability backend customized 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:

  • Free, paid, and enterprise support
  • Packages with advanced features not available in the open source offering
  • Native code integration and Real-Time User Monitoring for Flutter apps
  • Multiple backends (Elastic, Grafana) customized for Flutter apps.

AI Usage

Practically all code in Dartastic was generated by using Claude Desktop with MCP on a local Mac repo. The spec is available on disk to Claude. Fortunately, with a good specification, LLMs generate better code. This project is a good fit for what AI can do in early 2025.

EVERY character is reviewed by a human. Tests may need improved quality.

Additional information