Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
7e7a385
feat(telemetry): Introduce TelemetryItem interface and implement tele…
buenaflor Dec 15, 2025
72639df
feat(telemetry): Enhance telemetry processing with buffer registratio…
buenaflor Dec 16, 2025
d14838a
refactor(tests): Remove unused initialization tests from telemetry pr…
buenaflor Dec 16, 2025
02b1d34
feat(telemetry): Integrate telemetry processing into SentryOptions
buenaflor Dec 16, 2025
f80d9ba
refactor(telemetry): Simplify telemetry buffer handling in DefaultTel…
buenaflor Dec 16, 2025
388409c
feat(telemetry): Implement in-memory telemetry buffer for span and lo…
buenaflor Dec 16, 2025
ca184fc
fix(span): Ensure child span inherits traceId from parent correctly
buenaflor Dec 16, 2025
534aee1
fix(noop_span): Correct segmentSpan implementation to return the curr…
buenaflor Dec 16, 2025
cba8450
Merge branch 'feat/span-first' into feat/buffer/pr-1-telemetry-item-i…
buenaflor Dec 16, 2025
59927dc
Formatting
buenaflor Dec 16, 2025
ed407b1
feat(telemetry): Enhance DefaultTelemetryProcessor with customizable …
buenaflor Dec 17, 2025
b4dc2a1
refactor(span): Update SimpleSpan to use configurable clock for times…
buenaflor Dec 17, 2025
01c771b
refactor(telemetry): Simplify DefaultTelemetryProcessor by removing b…
buenaflor Dec 17, 2025
b868f54
refactor(telemetry): Remove unused telemetry item import from NoOpSpan
buenaflor Dec 17, 2025
874c684
refactor(telemetry): Replace TelemetryItem with SentryEncodable inter…
buenaflor Dec 17, 2025
eedfd0b
docs(telemetry): Add documentation for SentryEncodable and TelemetryB…
buenaflor Dec 17, 2025
13955bd
refactor(span): Improve traceId inheritance logic in SimpleSpan const…
buenaflor Dec 17, 2025
b522089
fix(span): Ensure endTimestamp is stored in UTC format in SimpleSpan
buenaflor Dec 17, 2025
8ea876a
feat(telemetry): Prevent NoOpSpan and UnsetSpan from being added to t…
buenaflor Dec 17, 2025
d54ae8b
docs(telemetry): Enhance documentation for TelemetryProcessor methods
buenaflor Dec 17, 2025
9434be4
docs(telemetry): Remove outdated flush method documentation in Defaul…
buenaflor Dec 17, 2025
cc9815b
docs(telemetry): Remove outdated constructor documentation in Default…
buenaflor Dec 17, 2025
bcde33e
refactor(telemetry): Remove SentryEncodable interface and simplify re…
buenaflor Dec 17, 2025
ed1ce35
refactor(telemetry): Rename BufferedItem to EncodedItem and update re…
buenaflor Dec 17, 2025
a12ff23
refactor(span): Simplify traceId assignment in SimpleSpan constructor
buenaflor Dec 17, 2025
4d50af0
refactor(telemetry): Integrate telemetry processing into SentryClient
buenaflor Dec 17, 2025
43a8d5a
refactor(telemetry): Implement JsonEncodable interface for telemetry …
buenaflor Dec 17, 2025
fe868cb
Merge branch 'feat/span-first' into feat/buffer/pr-1-telemetry-item-i…
buenaflor Dec 17, 2025
a072baa
refactor(telemetry): Update telemetry buffer implementation and enhan…
buenaflor Dec 17, 2025
1fb4a80
refactor(telemetry): Rename flush methods to clear for clarity
buenaflor Dec 17, 2025
28ff74c
refactor(telemetry): Rename flush method to clear in MockTelemetryBuffer
buenaflor Dec 17, 2025
3a1904d
refactor(telemetry): Update futures type in telemetry processor
buenaflor Dec 17, 2025
ff13cc4
refactor(telemetry): Rename asyncFlush to asyncClear in MockTelemetry…
buenaflor Dec 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/dart/lib/src/protocol/noop_span.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,10 @@ class NoOpSpan implements Span {

@override
Map<String, dynamic> toJson() => {};

@override
Span get segmentSpan => this;

@override
SentryId get traceId => SentryId.empty();
}
4 changes: 3 additions & 1 deletion packages/dart/lib/src/protocol/sentry_log.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import '../telemetry_processing/json_encodable.dart';
import 'sentry_attribute.dart';
import 'sentry_id.dart';
import 'sentry_log_level.dart';

class SentryLog {
class SentryLog implements JsonEncodable {
DateTime timestamp;
SentryId traceId;
SentryLogLevel level;
Expand All @@ -21,6 +22,7 @@ class SentryLog {
this.severityNumber,
}) : traceId = traceId ?? SentryId.empty();

@override
Map<String, dynamic> toJson() {
return {
'timestamp': timestamp.toIso8601String(),
Expand Down
38 changes: 34 additions & 4 deletions packages/dart/lib/src/protocol/simple_span.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ class SimpleSpan implements Span {
@override
final Span? parentSpan;
final Map<String, SentryAttribute> _attributes = {};
late final DateTime _startTimestamp;
late final Span _segmentSpan;
late final SentryId _traceId;

String _name;
SpanV2Status _status = SpanV2Status.ok;
Expand All @@ -18,7 +21,16 @@ class SimpleSpan implements Span {
Hub? hub,
}) : _spanId = SpanId.newId(),
_hub = hub ?? HubAdapter(),
_name = name;
_name = name {
_segmentSpan = parentSpan?.segmentSpan ?? this;
_startTimestamp = _hub.options.clock();
_traceId = parentSpan != null
? parentSpan!.traceId
: _hub.scope.propagationContext.traceId;
}

@override
SentryId get traceId => _traceId;

@override
SpanId get spanId => _spanId;
Expand All @@ -44,6 +56,9 @@ class SimpleSpan implements Span {
@override
bool get isFinished => _isFinished;

@override
Span get segmentSpan => _segmentSpan;

@override
void setAttribute(String key, SentryAttribute value) {
_attributes[key] = value;
Expand All @@ -59,14 +74,29 @@ class SimpleSpan implements Span {
if (_isFinished) {
return;
}
_endTimestamp = (endTimestamp ?? DateTime.now()).toUtc();
_endTimestamp = (endTimestamp?.toUtc() ?? _hub.options.clock());
_isFinished = true;
_hub.captureSpan(this);
}

@override
Map<String, dynamic> toJson() {
// TODO: implement toJson
throw UnimplementedError();
double toUnixSeconds(DateTime timestamp) =>
timestamp.microsecondsSinceEpoch / 1000000;

return {
'trace_id': _traceId.toString(),
'span_id': _spanId.toString(),
'is_segment': parentSpan == null,
'name': _name,
'status': _status.name,
'end_timestamp':
_endTimestamp == null ? null : toUnixSeconds(_endTimestamp!),
'start_timestamp': toUnixSeconds(_startTimestamp),
if (parentSpan != null) 'parent_span_id': parentSpan?.spanId.toString(),
if (_attributes.isNotEmpty)
'attributes':
_attributes.map((key, value) => MapEntry(key, value.toJson())),
};
}
}
10 changes: 9 additions & 1 deletion packages/dart/lib/src/protocol/span.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import 'package:meta/meta.dart';

import '../../sentry.dart';
import '../telemetry_processing/json_encodable.dart';

// Span specs: https://develop.sentry.dev/sdk/telemetry/spans/span-api/

/// Represents a basic telemetry span.
abstract class Span {
abstract class Span implements JsonEncodable {
@internal
const Span();

/// Gets the id of the trace this span belongs to.
SentryId get traceId;

/// Gets the id of the span.
SpanId get spanId;

Expand Down Expand Up @@ -51,9 +55,13 @@ abstract class Span {
/// Overrides if the attributes already exist.
void setAttributes(Map<String, SentryAttribute> attributes);

@internal
Span get segmentSpan;

@internal
bool get isFinished;

@internal
@override
Map<String, dynamic> toJson();
}
52 changes: 22 additions & 30 deletions packages/dart/lib/src/protocol/unset_span.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,59 +8,51 @@ import '../../sentry.dart';
class UnsetSpan extends Span {
const UnsetSpan();

static Never _throw() =>
throw UnimplementedError('$UnsetSpan APIs should not be used');

@override
SpanId get spanId => _throw();

@override
String get name => _throw();

@override
SpanId get spanId =>
throw UnimplementedError('$UnsetSpan apis should not be used');
set name(String name) => _throw();

@override
String get name =>
throw UnimplementedError('$UnsetSpan apis should not be used');
SpanV2Status get status => _throw();

@override
set name(String name) =>
throw UnimplementedError('$UnsetSpan apis should not be used');
set status(SpanV2Status status) => _throw();

@override
SpanV2Status get status =>
throw UnimplementedError('$UnsetSpan apis should not be used');
Span? get parentSpan => _throw();

@override
set status(SpanV2Status status) =>
throw UnimplementedError('$UnsetSpan apis should not be used');
DateTime? get endTimestamp => _throw();

@override
Span? get parentSpan =>
throw UnimplementedError('$UnsetSpan apis should not be used');
Map<String, SentryAttribute> get attributes => _throw();

@override
DateTime? get endTimestamp =>
throw UnimplementedError('$UnsetSpan apis should not be used');
bool get isFinished => _throw();

@override
Map<String, SentryAttribute> get attributes =>
throw UnimplementedError('$UnsetSpan apis should not be used');
void setAttribute(String key, SentryAttribute value) => _throw();

@override
bool get isFinished =>
throw UnimplementedError('$UnsetSpan apis should not be used');
void setAttributes(Map<String, SentryAttribute> attributes) => _throw();

@override
void setAttribute(String key, SentryAttribute value) {
throw UnimplementedError('$UnsetSpan apis should not be used');
}
void end({DateTime? endTimestamp}) => _throw();

@override
void setAttributes(Map<String, SentryAttribute> attributes) {
throw UnimplementedError('$UnsetSpan apis should not be used');
}
Map<String, dynamic> toJson() => _throw();

@override
void end({DateTime? endTimestamp}) {
throw UnimplementedError('$UnsetSpan apis should not be used');
}
Span get segmentSpan => _throw();

@override
Map<String, dynamic> toJson() {
throw UnimplementedError('$UnsetSpan apis should not be used');
}
SentryId get traceId => _throw();
}
7 changes: 7 additions & 0 deletions packages/dart/lib/src/sentry_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import 'sentry_exception_factory.dart';
import 'sentry_options.dart';
import 'sentry_stack_trace_factory.dart';
import 'sentry_trace_context_header.dart';
import 'telemetry_processing/telemetry_buffer.dart';
import 'telemetry_processing/telemetry_processor.dart';
import 'transport/client_report_transport.dart';
import 'transport/data_category.dart';
import 'transport/http_transport.dart';
Expand Down Expand Up @@ -78,6 +80,10 @@ class SentryClient {
if (options.enableLogs) {
options.logBatcher = SentryLogBatcher(options);
}
options.telemetryProcessor = DefaultTelemetryProcessor(options.log,
logBuffer: InMemoryTelemetryBuffer(),
spanBuffer: InMemoryTelemetryBuffer());
// TODO(next-pr): remove log batcher
return SentryClient._(options);
}

Expand Down Expand Up @@ -588,6 +594,7 @@ class SentryClient {
}

FutureOr<void> close() {
// TODO(next-pr): replace with telemetry processor
final flush = _options.logBatcher.flush();
if (flush is Future<void>) {
return flush.then((_) => _options.httpClient.close());
Expand Down
4 changes: 4 additions & 0 deletions packages/dart/lib/src/sentry_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'noop_client.dart';
import 'platform/platform.dart';
import 'sentry_exception_factory.dart';
import 'sentry_stack_trace_factory.dart';
import 'telemetry_processing/telemetry_processor.dart';
import 'transport/noop_transport.dart';
import 'version.dart';
import 'sentry_log_batcher.dart';
Expand Down Expand Up @@ -543,6 +544,9 @@ class SentryOptions {
@internal
SentryLogBatcher logBatcher = NoopLogBatcher();

@internal
TelemetryProcessor telemetryProcessor = NoOpTelemetryProcessor();

SentryOptions({String? dsn, Platform? platform, RuntimeChecker? checker}) {
this.dsn = dsn;
if (platform != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
abstract interface class JsonEncodable {
Map<String, dynamic> toJson();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import 'dart:async';

import '../../sentry.dart';
import 'json_encodable.dart';

/// A buffer that batches telemetry items for efficient transmission to Sentry.
///
/// Collects items of type [T] and sends them in batches rather than
/// individually, reducing network overhead.
abstract class TelemetryBuffer<T> {
/// Adds an item to the buffer.
void add(T item);

/// When executed immediately sends all buffered items to Sentry and clears the buffer.
FutureOr<void> clear();
}

/// Pairs an item with its encoded bytes for size tracking and transmission.
class BufferedItem<T> {
final T item;
final List<int> encoded;

BufferedItem(this.item, this.encoded);
}

/// In-memory buffer with time and size-based flushing.
class InMemoryTelemetryBuffer<T extends JsonEncodable>
extends TelemetryBuffer<T> {
InMemoryTelemetryBuffer();

@override
void add(T item) {
final encoded = utf8JsonEncoder.convert(item.toJson());
final _ = BufferedItem(item, encoded);
// TODO(next-pr): finish this impl
}

@override
FutureOr<void> clear() {
// TODO(next-pr): finish this impl
}
}
Loading
Loading