otel_logging 0.1.0-beta.1
otel_logging: ^0.1.0-beta.1 copied to clipboard
Bridge `package:logging` records into the OpenTelemetry logs SDK so trace_id / span_id correlation lights up automatically for any Dart app using the Dart team's standard logging package.
dartastic_opentelemetry_logging #
Bridges package:logging records into the
Dartastic OpenTelemetry SDK
so any Dart application using the de-facto-standard Dart logging package gets
trace/span correlation in its log records automatically.
Why #
package:logging is what every Dart server framework and most Flutter apps use
for structured application logs. Without a bridge, every consumer who wants
trace-id correlation in their backend has to write the same ~15 lines of
Logger.root.onRecord.listen(...) plumbing — easy to get the level mapping
subtly wrong. This package is that plumbing, written once.
The bridge is opt-in: the OTel SDK does not depend on package:logging.
Add this package only when you want the integration.
Usage #
import 'package:dartastic_opentelemetry/dartastic_opentelemetry.dart';
import 'package:dartastic_opentelemetry_logging/dartastic_opentelemetry_logging.dart';
import 'package:logging/logging.dart';
Future<void> main() async {
await OTel.initialize(serviceName: 'my-app');
// After OTel.initialize so the default LoggerProvider exists.
PackageLoggingBridge.install();
Logger.root.level = Level.ALL;
Logger('weather.api').info('serving forecast');
// Records emitted from inside an active span are auto-correlated.
await OTel.tracer().startActiveSpan('serve', (_) async {
Logger('handler').warning('upstream slow');
});
// Cancel the StreamSubscription before the program exits, otherwise
// the open subscription keeps the Dart isolate alive after main returns.
await PackageLoggingBridge.uninstall();
await OTel.shutdown();
}
Severity mapping #
package:logging Level.value is mapped to OTel Severity using the same
boundaries as the SDK's existing dart:developer bridge:
package:logging |
Level.value |
OTel Severity |
|---|---|---|
ALL (anything < 300) |
0+ | TRACE |
FINEST |
300 | TRACE2 |
FINER |
400 | TRACE2 |
FINE |
500 | DEBUG |
CONFIG |
700 | DEBUG2 |
INFO |
800 | INFO |
WARNING |
900 | WARN |
SEVERE |
1000 | ERROR |
SHOUT |
1200 | FATAL |
Attributes #
exception.type— set when the record has anerror(usesruntimeType.toString()).exception.message— set when the record has anerror(useserror.toString()).exception.stacktrace— set when the record has astackTrace.logging.zone—hashCodeof the originatingZone. Useful when correlating logs across isolates/zones; ignore otherwise.
The OTel logger name (instrumentation scope) defaults to the
Logger's name, falling back to package.logging for Logger.root
records.
Existing Logger.root.onRecord subscribers keep firing #
Installing the bridge is additive. If your app already prints log
records to stdout via a Logger.root.onRecord.listen(...) subscriber,
those continue to fire. That matters for Cloud Run / Cloud Functions
where the platform also collects stdout.
Lifecycle #
The bridge holds a StreamSubscription on Logger.root.onRecord. Like
any open subscription, an open subscription keeps the Dart isolate
alive past main(). Always:
await PackageLoggingBridge.uninstall();
await OTel.shutdown();
before letting main() return. Forgetting to uninstall is the same
class of bug as
issue #33 in the SDK
(short-lived CLIs hanging because a Timer/subscription was never
cancelled).
License #
Apache 2.0 — see LICENSE.