diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b906efab3..960c3793b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Unreleased +### Breaking changes + +- Remove Metrics API ([#2571](https://github.com/getsentry/sentry-dart/pull/2571)) + - The Metrics product never reached maturity from beta and has officially ended in October 7th, 2024 + - Read [this post](https://sentry.zendesk.com/hc/en-us/articles/26369339769883-Metrics-Beta-Ended-on-October-7th) for more information + ### Features - Add `beforeCapture` for View Hierarchy ([#2523](https://github.com/getsentry/sentry-dart/pull/2523)) diff --git a/dart/lib/src/hub.dart b/dart/lib/src/hub.dart index 4e2ca289c3..ff8e639998 100644 --- a/dart/lib/src/hub.dart +++ b/dart/lib/src/hub.dart @@ -2,17 +2,14 @@ import 'dart:async'; import 'dart:collection'; import 'package:meta/meta.dart'; -import 'metrics/metric.dart'; -import 'metrics/metrics_aggregator.dart'; -import 'metrics/metrics_api.dart'; -import 'profiling.dart'; -import 'propagation_context.dart'; -import 'transport/data_category.dart'; import '../sentry.dart'; import 'client_reports/discard_reason.dart'; +import 'profiling.dart'; +import 'propagation_context.dart'; import 'sentry_tracer.dart'; import 'sentry_traces_sampler.dart'; +import 'transport/data_category.dart'; /// Configures the scope through the callback. typedef ScopeCallback = FutureOr Function(Scope); @@ -41,16 +38,6 @@ class Hub { late final _WeakMap _throwableToSpan; - late final MetricsApi _metricsApi; - - @internal - @Deprecated( - 'Metrics will be deprecated and removed in the next major release. Sentry will reject all metrics sent after October 7, 2024. Learn more: https://sentry.zendesk.com/hc/en-us/articles/26369339769883-Upcoming-API-Changes-to-Metrics') - MetricsApi get metricsApi => _metricsApi; - - @internal - MetricsAggregator? get metricsAggregator => _peek().client.metricsAggregator; - factory Hub(SentryOptions options) { _validateOptions(options); @@ -62,7 +49,6 @@ class Hub { _stack.add(_StackItem(_getClient(_options), Scope(_options))); _isEnabled = true; _throwableToSpan = _WeakMap(_options); - _metricsApi = MetricsApi(hub: this); } static void _validateOptions(SentryOptions options) { @@ -634,45 +620,6 @@ class Hub { return sentryId; } - @internal - Future captureMetrics( - Map> metricsBuckets) async { - var sentryId = SentryId.empty(); - - if (!_isEnabled) { - _options.logger( - SentryLevel.warning, - "Instance is disabled and this 'captureMetrics' call is a no-op.", - ); - } else if (!_options.enableMetrics) { - _options.logger( - SentryLevel.info, - "Metrics are disabled and this 'captureMetrics' call is a no-op.", - ); - } else if (metricsBuckets.isEmpty) { - _options.logger( - SentryLevel.info, - "Metrics are empty and this 'captureMetrics' call is a no-op.", - ); - } else { - final item = _peek(); - try { - sentryId = await item.client.captureMetrics(metricsBuckets); - } catch (exception, stackTrace) { - _options.logger( - SentryLevel.error, - 'Error while capturing metrics.', - exception: exception, - stackTrace: stackTrace, - ); - if (_options.automatedTestMode) { - rethrow; - } - } - } - return sentryId; - } - @internal void setSpanContext( dynamic throwable, diff --git a/dart/lib/src/hub_adapter.dart b/dart/lib/src/hub_adapter.dart index fa93aaf915..88b427e376 100644 --- a/dart/lib/src/hub_adapter.dart +++ b/dart/lib/src/hub_adapter.dart @@ -4,9 +4,6 @@ import 'package:meta/meta.dart'; import 'hint.dart'; import 'hub.dart'; -import 'metrics/metric.dart'; -import 'metrics/metrics_aggregator.dart'; -import 'metrics/metrics_api.dart'; import 'profiling.dart'; import 'protocol.dart'; import 'protocol/sentry_feedback.dart'; @@ -27,11 +24,6 @@ class HubAdapter implements Hub { @internal SentryOptions get options => Sentry.currentHub.options; - @override - @internal - // ignore: deprecated_member_use_from_same_package - MetricsApi get metricsApi => Sentry.currentHub.metricsApi; - factory HubAdapter() { return _instance; } @@ -193,14 +185,6 @@ class HubAdapter implements Hub { @override Scope get scope => Sentry.currentHub.scope; - @override - Future captureMetrics(Map> metricsBuckets) => - Sentry.currentHub.captureMetrics(metricsBuckets); - - @override - MetricsAggregator? get metricsAggregator => - Sentry.currentHub.metricsAggregator; - @override Future captureFeedback( SentryFeedback feedback, { diff --git a/dart/lib/src/metrics/local_metrics_aggregator.dart b/dart/lib/src/metrics/local_metrics_aggregator.dart deleted file mode 100644 index 92076ef807..0000000000 --- a/dart/lib/src/metrics/local_metrics_aggregator.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'dart:core'; -import 'package:meta/meta.dart'; -import '../protocol/metric_summary.dart'; -import 'metric.dart'; - -@internal -class LocalMetricsAggregator { - // format: > - final Map> _buckets = {}; - - void add(final Metric metric, final num value) { - final bucket = - _buckets.putIfAbsent(metric.getSpanAggregationKey(), () => {}); - - bucket.update(metric.getCompositeKey(), (m) => m..add(value), - ifAbsent: () => Metric.fromType( - type: MetricType.gauge, - key: metric.key, - value: value, - unit: metric.unit, - tags: metric.tags) as GaugeMetric); - } - - Map> getSummaries() { - final Map> summaries = {}; - for (final entry in _buckets.entries) { - final String exportKey = entry.key; - - final metricSummaries = entry.value.values - .map((gauge) => MetricSummary.fromGauge(gauge)) - .toList(); - - summaries[exportKey] = metricSummaries; - } - return summaries; - } -} diff --git a/dart/lib/src/metrics/metric.dart b/dart/lib/src/metrics/metric.dart deleted file mode 100644 index fdea81cbf4..0000000000 --- a/dart/lib/src/metrics/metric.dart +++ /dev/null @@ -1,291 +0,0 @@ -import 'dart:math'; - -import 'package:meta/meta.dart'; - -import '../../sentry.dart'; - -final RegExp unitRegex = RegExp('[^\\w]+'); -final RegExp nameRegex = RegExp('[^\\w-.]+'); -final RegExp tagKeyRegex = RegExp('[^\\w-./]+'); - -/// Base class for metrics. -/// Each metric is identified by a [key]. Its [type] describes its behaviour. -/// A [unit] (defaults to [SentryMeasurementUnit.none]) describes the values -/// being tracked. Optional [tags] can be added. The [timestamp] is the time -/// when the metric was emitted. -@internal -abstract class Metric { - final MetricType type; - final String key; - final SentryMeasurementUnit unit; - final Map tags; - - Metric({ - required this.type, - required this.key, - required this.unit, - required this.tags, - }); - - factory Metric.fromType({ - required final MetricType type, - required final String key, - required final num value, - required final SentryMeasurementUnit unit, - required final Map tags, - }) { - switch (type) { - case MetricType.counter: - return CounterMetric._(value: value, key: key, unit: unit, tags: tags); - case MetricType.gauge: - return GaugeMetric._(value: value, key: key, unit: unit, tags: tags); - case MetricType.set: - return SetMetric._(value: value, key: key, unit: unit, tags: tags); - case MetricType.distribution: - return DistributionMetric._( - value: value, key: key, unit: unit, tags: tags); - } - } - - /// Add a value to the metric. - add(num value); - - /// Return the weight of the current metric. - int getWeight(); - - /// Serialize the value into a list of Objects to be converted into a String. - Iterable _serializeValue(); - - /// Encodes the metric in the statsd format - /// See github.com/statsd/statsd#usage and - /// getsentry.github.io/relay/relay_metrics/index.html - /// for more details about the format. - /// - /// Example format: key@none:1|c|#myTag:myValue|T1710844170 - /// key@unit:value1:value2|type|#tagKey1:tagValue1,tagKey2:tagValue2,|TbucketKey - /// - /// [bucketKey] is the key of the metric bucket that will be sent to Sentry, - /// and it's appended at the end of the encoded metric. - String encodeToStatsd(int bucketKey) { - final buffer = StringBuffer(); - buffer.write(_sanitizeName(key)); - buffer.write("@"); - - final sanitizeUnitName = _sanitizeUnit(unit.name); - buffer.write(sanitizeUnitName); - - for (final value in _serializeValue()) { - buffer.write(":"); - buffer.write(value.toString()); - } - - buffer.write("|"); - buffer.write(type.statsdType); - - if (tags.isNotEmpty) { - buffer.write("|#"); - final serializedTags = tags.entries - .map((tag) => - '${_sanitizeTagKey(tag.key)}:${_sanitizeTagValue(tag.value)}') - .join(','); - buffer.write(serializedTags); - } - - buffer.write("|T"); - buffer.write(bucketKey); - - return buffer.toString(); - } - - /// Return a key created by [key], [type], [unit] and [tags]. - /// This key should be used to retrieve the metric to update in aggregation. - String getCompositeKey() { - final String serializedTags = tags.entries.map((e) { - // We escape the ',' from the key and the value, as we will join the tags - // with a ',' to create the composite key. - String escapedKey = e.key.replaceAll(',', '\\,'); - String escapedValue = e.value.replaceAll(',', '\\,'); - return '$escapedKey=$escapedValue'; - }).join(','); - - return ('${type.statsdType}_${key}_${unit.name}_$serializedTags'); - } - - /// Return a key created by [key], [type] and [unit]. - /// This key should be used to aggregate the metric locally in a span. - String getSpanAggregationKey() => '${type.statsdType}:$key@${unit.name}'; - - /// Remove forbidden characters from the metric key and tag key. - String _sanitizeName(String input) => input.replaceAll(nameRegex, '_'); - - /// Remove forbidden characters from the tag value. - String _sanitizeTagKey(String input) => input.replaceAll(tagKeyRegex, ''); - - /// Remove forbidden characters from the metric unit. - String _sanitizeUnit(String input) => input.replaceAll(unitRegex, ''); - - String _sanitizeTagValue(String input) { - // see https://develop.sentry.dev/sdk/metrics/#tag-values-replacement-map - // Line feed -> \n - // Carriage return -> \r - // Tab -> \t - // Backslash -> \\ - // Pipe -> \\u{7c} - // Comma -> \\u{2c} - final buffer = StringBuffer(); - for (int i = 0; i < input.length; i++) { - final ch = input[i]; - if (ch == '\n') { - buffer.write("\\n"); - } else if (ch == '\r') { - buffer.write("\\r"); - } else if (ch == '\t') { - buffer.write("\\t"); - } else if (ch == '\\') { - buffer.write("\\\\"); - } else if (ch == '|') { - buffer.write("\\u{7c}"); - } else if (ch == ',') { - buffer.write("\\u{2c}"); - } else { - buffer.write(ch); - } - } - return buffer.toString(); - } -} - -/// Metric [MetricType.counter] that tracks a value that can only be incremented. -@internal -class CounterMetric extends Metric { - num value; - - CounterMetric._({ - required this.value, - required super.key, - required super.unit, - required super.tags, - }) : super(type: MetricType.counter); - - @override - add(num value) => this.value += value; - - @override - Iterable _serializeValue() => [value]; - - @override - int getWeight() => 1; -} - -/// Metric [MetricType.gauge] that tracks a value that can go up and down. -@internal -class GaugeMetric extends Metric { - num _last; - num _minimum; - num _maximum; - num _sum; - int _count; - - GaugeMetric._({ - required num value, - required super.key, - required super.unit, - required super.tags, - }) : _last = value, - _minimum = value, - _maximum = value, - _sum = value, - _count = 1, - super(type: MetricType.gauge); - - @override - add(num value) { - _last = value; - _minimum = min(_minimum, value); - _maximum = max(_maximum, value); - _sum += value; - _count++; - } - - @override - Iterable _serializeValue() => - [_last, _minimum, _maximum, _sum, _count]; - - @override - int getWeight() => 5; - - @visibleForTesting - num get last => _last; - num get minimum => _minimum; - num get maximum => _maximum; - num get sum => _sum; - int get count => _count; -} - -/// Metric [MetricType.set] that tracks a set of values on which you can perform -/// aggregations such as count_unique. -@internal -class SetMetric extends Metric { - final Set _values = {}; - - SetMetric._( - {required num value, - required super.key, - required super.unit, - required super.tags}) - : super(type: MetricType.set) { - add(value); - } - - @override - add(num value) => _values.add(value.toInt()); - - @override - Iterable _serializeValue() => _values; - - @override - int getWeight() => _values.length; - - @visibleForTesting - Set get values => _values; -} - -/// Metric [MetricType.distribution] that tracks a list of values. -@internal -class DistributionMetric extends Metric { - final List _values = []; - - DistributionMetric._( - {required num value, - required super.key, - required super.unit, - required super.tags}) - : super(type: MetricType.distribution) { - add(value); - } - - @override - add(num value) => _values.add(value); - - @override - Iterable _serializeValue() => _values; - - @override - int getWeight() => _values.length; - - @visibleForTesting - List get values => _values; -} - -/// The metric type and its associated statsd encoded value. -@internal -enum MetricType { - counter('c'), - gauge('g'), - distribution('d'), - set('s'); - - final String statsdType; - - const MetricType(this.statsdType); -} diff --git a/dart/lib/src/metrics/metrics_aggregator.dart b/dart/lib/src/metrics/metrics_aggregator.dart deleted file mode 100644 index ef763eae35..0000000000 --- a/dart/lib/src/metrics/metrics_aggregator.dart +++ /dev/null @@ -1,207 +0,0 @@ -import 'dart:async'; -import 'dart:collection'; -import 'dart:math'; - -import 'package:meta/meta.dart'; - -import '../../sentry.dart'; -import 'local_metrics_aggregator.dart'; -import 'metric.dart'; - -/// Class that aggregates all metrics into time buckets and sends them. -@internal -class MetricsAggregator { - static final _defaultFlushShiftMs = - (Random().nextDouble() * (_rollupInSeconds * 1000)).toInt(); - static const _defaultFlushInterval = Duration(seconds: 5); - static const _defaultMaxWeight = 100000; - static const int _rollupInSeconds = 10; - - final Duration _flushInterval; - final int _flushShiftMs; - final SentryOptions _options; - final Hub _hub; - final int _maxWeight; - int _totalWeight = 0; - bool _isClosed = false; - Completer? _flushCompleter; - Timer? _flushTimer; - - /// The key for this map is the timestamp of the bucket, rounded down to the - /// nearest RollupInSeconds. So it aggregates all the metrics over a certain - /// time period. The Value is a map of the metrics, each of which has a key - /// that uniquely identifies it within the time period. - /// The [SplayTreeMap] is used so that bucket keys are ordered. - final SplayTreeMap> _buckets = SplayTreeMap(); - - MetricsAggregator({ - required SentryOptions options, - Hub? hub, - @visibleForTesting Duration? flushInterval, - @visibleForTesting int? flushShiftMs, - @visibleForTesting int? maxWeight, - }) : _options = options, - _hub = hub ?? HubAdapter(), - _flushInterval = flushInterval ?? _defaultFlushInterval, - _flushShiftMs = flushShiftMs ?? _defaultFlushShiftMs, - _maxWeight = maxWeight ?? _defaultMaxWeight; - - /// Creates or update an existing Counter metric with [value]. - /// The metric to update is identified using [key], [unit] and [tags]. - /// The [timestamp] represents when the metric was emitted. - void emit( - MetricType metricType, - String key, - num value, - SentryMeasurementUnit unit, - Map tags, { - LocalMetricsAggregator? localMetricsAggregator, - }) { - if (_isClosed) { - return; - } - - // run before metric callback if set - if (_options.beforeMetricCallback != null) { - try { - final shouldEmit = _options.beforeMetricCallback!(key, tags: tags); - if (!shouldEmit) { - _options.logger( - SentryLevel.info, - 'Metric was dropped by beforeMetric', - ); - return; - } - } catch (exception, stackTrace) { - _options.logger( - SentryLevel.error, - 'The BeforeMetric callback threw an exception', - exception: exception, - stackTrace: stackTrace, - ); - if (_options.automatedTestMode) { - rethrow; - } - } - } - - final bucketKey = _getBucketKey(_options.clock()); - final bucket = _buckets.putIfAbsent(bucketKey, () => {}); - final metric = Metric.fromType( - type: metricType, key: key, value: value, unit: unit, tags: tags); - - final oldWeight = bucket[metric.getCompositeKey()]?.getWeight() ?? 0; - final addedWeight = metric.getWeight(); - _totalWeight += addedWeight - oldWeight; - - // Update the existing metric in the bucket. - // If absent, add the newly created metric to the bucket. - bucket.update( - metric.getCompositeKey(), - (m) => m..add(value), - ifAbsent: () => metric, - ); - - // For sets, we only record that a value has been added to the set but not which one. - // See develop docs: https://develop.sentry.dev/sdk/metrics/#sets - final localAggregator = - localMetricsAggregator ?? (_hub.getSpan()?.localMetricsAggregator); - localAggregator?.add( - metric, metricType == MetricType.set ? addedWeight : value); - - // Schedule the metrics flushing. - _scheduleFlush(); - } - - void _scheduleFlush() { - if (!_isClosed && _buckets.isNotEmpty) { - if (_isOverWeight()) { - _flushTimer?.cancel(); - _flush(false); - return; - } - if (_flushTimer?.isActive != true) { - _flushCompleter = Completer(); - _flushTimer = Timer(_flushInterval, () => _flush(false)); - } - } - } - - bool _isOverWeight() => _totalWeight >= _maxWeight; - - int getBucketWeight(final Map bucket) { - int weight = 0; - for (final metric in bucket.values) { - weight += metric.getWeight(); - } - return weight; - } - - /// Flush the metrics, then schedule next flush again. - void _flush(bool force) async { - if (!force && _isOverWeight()) { - _options.logger(SentryLevel.info, - "Metrics: total weight exceeded, flushing all buckets"); - force = true; - } - - final flushableBucketKeys = _getFlushableBucketKeys(force); - if (flushableBucketKeys.isEmpty) { - _options.logger(SentryLevel.debug, 'Metrics: nothing to flush'); - } else { - final Map> bucketsToFlush = {}; - - for (final flushableBucketKey in flushableBucketKeys) { - final bucket = _buckets.remove(flushableBucketKey); - if (bucket != null && bucket.isNotEmpty) { - _totalWeight -= getBucketWeight(bucket); - bucketsToFlush[flushableBucketKey] = bucket.values; - } - } - await _hub.captureMetrics(bucketsToFlush); - } - - // Notify flush completed and reschedule flushing - _flushTimer?.cancel(); - _flushTimer = null; - flushCompleter?.complete(null); - _flushCompleter = null; - _scheduleFlush(); - } - - /// Return a list of bucket keys to flush. - List _getFlushableBucketKeys(bool force) { - if (force) { - return buckets.keys.toList(); - } - // Flushable buckets are all buckets with timestamp lower than the current - // one (so now - rollupInSeconds), minus a random duration (flushShiftMs). - final maxTimestampToFlush = _options.clock().subtract(Duration( - seconds: _rollupInSeconds, - milliseconds: _flushShiftMs, - )); - final maxKeyToFlush = _getBucketKey(maxTimestampToFlush); - - // takeWhile works because we use a SplayTreeMap and keys are ordered. - // toList() is needed because takeWhile is lazy and we want to remove items - // from the buckets with these keys. - return _buckets.keys.takeWhile((value) => value <= maxKeyToFlush).toList(); - } - - /// The timestamp of the bucket, rounded down to the nearest RollupInSeconds. - int _getBucketKey(DateTime timestamp) { - final seconds = timestamp.millisecondsSinceEpoch ~/ 1000; - return (seconds ~/ _rollupInSeconds) * _rollupInSeconds; - } - - @visibleForTesting - SplayTreeMap> get buckets => _buckets; - - @visibleForTesting - Completer? get flushCompleter => _flushCompleter; - - void close() { - _flush(true); - _isClosed = true; - } -} diff --git a/dart/lib/src/metrics/metrics_api.dart b/dart/lib/src/metrics/metrics_api.dart deleted file mode 100644 index 9f9e8305f2..0000000000 --- a/dart/lib/src/metrics/metrics_api.dart +++ /dev/null @@ -1,186 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import '../../sentry.dart'; -import '../utils/crc32_utils.dart'; -import 'metric.dart'; - -/// Public APIs to emit Sentry metrics. -class MetricsApi { - MetricsApi({Hub? hub}) : _hub = hub ?? HubAdapter(); - - final Hub _hub; - - /// Emits a Counter metric, identified by [key], increasing it by [value]. - /// Counters track a value that can only be incremented. - /// You can set the [unit] and the optional [tags] to associate to the metric. - void increment(final String key, - {final double value = 1.0, - final SentryMeasurementUnit? unit, - final Map? tags}) { - _hub.metricsAggregator?.emit( - MetricType.counter, - key, - value, - unit ?? SentryMeasurementUnit.none, - _enrichWithDefaultTags(tags), - ); - } - - /// Emits a Gauge metric, identified by [key], adding [value] to it. - /// Gauges track a value that can go up and down. - /// You can set the [unit] and the optional [tags] to associate to the metric. - void gauge(final String key, - {required final double value, - final SentryMeasurementUnit? unit, - final Map? tags}) { - _hub.metricsAggregator?.emit( - MetricType.gauge, - key, - value, - unit ?? SentryMeasurementUnit.none, - _enrichWithDefaultTags(tags), - ); - } - - /// Emits a Distribution metric, identified by [key], adding [value] to it. - /// Distributions track a list of values. - /// You can set the [unit] and the optional [tags] to associate to the metric. - void distribution(final String key, - {required final double value, - final SentryMeasurementUnit? unit, - final Map? tags}) { - _hub.metricsAggregator?.emit( - MetricType.distribution, - key, - value, - unit ?? SentryMeasurementUnit.none, - _enrichWithDefaultTags(tags), - ); - } - - /// Emits a Set metric, identified by [key], adding [value] or the CRC32 - /// checksum of [stringValue] to it. - /// Providing both [value] and [stringValue] adds both values to the metric. - /// Sets track a set of values to perform aggregations such as count_unique. - /// You can set the [unit] and the optional [tags] to associate to the metric. - void set(final String key, - {final int? value, - final String? stringValue, - final SentryMeasurementUnit? unit, - final Map? tags}) { - if (value != null) { - _hub.metricsAggregator?.emit( - MetricType.set, - key, - value, - unit ?? SentryMeasurementUnit.none, - _enrichWithDefaultTags(tags), - ); - } - if (stringValue != null && stringValue.isNotEmpty) { - final intValue = Crc32Utils.getCrc32(utf8.encode(stringValue)); - - _hub.metricsAggregator?.emit( - MetricType.set, - key, - intValue, - unit ?? SentryMeasurementUnit.none, - _enrichWithDefaultTags(tags), - ); - } - if (value == null && (stringValue == null || stringValue.isEmpty)) { - _hub.options.logger( - SentryLevel.info, 'No value provided. No metric will be emitted.'); - } - } - - /// Enrich user tags adding default tags - /// - /// Currently adds release, environment and transaction. - Map _enrichWithDefaultTags(Map? userTags) { - // We create another map, in case the userTags is unmodifiable. - final Map tags = Map.from(userTags ?? {}); - if (!_hub.options.enableDefaultTagsForMetrics) { - return tags; - } - // Enrich tags with default values (without overwriting user values) - _putIfAbsentIfNotNull(tags, 'release', _hub.options.release); - _putIfAbsentIfNotNull(tags, 'environment', _hub.options.environment); - _putIfAbsentIfNotNull(tags, 'transaction', _hub.scope.transaction); - return tags; - } - - /// Call [map.putIfAbsent] with [key] and [value] if [value] is not null. - _putIfAbsentIfNotNull(Map map, K key, V? value) { - if (value != null) { - map.putIfAbsent(key, () => value); - } - } - - /// Emits a Distribution metric, identified by [key], with the time it takes - /// to run [function]. - /// You can set the [unit] and the optional [tags] to associate to the metric. - void timing(final String key, - {required FutureOr Function() function, - final DurationSentryMeasurementUnit unit = - DurationSentryMeasurementUnit.second, - final Map? tags}) async { - // Start a span for the metric - final span = _hub.getSpan()?.startChild('metric.timing', description: key); - // Set the user tags to the span as well - if (span != null && tags != null) { - for (final entry in tags.entries) { - span.setTag(entry.key, entry.value); - } - } - final before = _hub.options.clock(); - try { - if (function is Future Function()) { - await function(); - } else { - function(); - } - } finally { - final after = _hub.options.clock(); - Duration duration = after.difference(before); - // If we have a span, we use its duration as value for the emitted metric - if (span != null) { - await span.finish(); - duration = - span.endTimestamp?.difference(span.startTimestamp) ?? duration; - } - final value = _convertMicrosTo(unit, duration.inMicroseconds); - - _hub.metricsAggregator?.emit( - MetricType.distribution, - key, - value, - unit, - _enrichWithDefaultTags(tags), - localMetricsAggregator: span?.localMetricsAggregator, - ); - } - } - - double _convertMicrosTo( - final DurationSentryMeasurementUnit unit, final int micros) { - switch (unit) { - case DurationSentryMeasurementUnit.nanoSecond: - return micros * 1000; - case DurationSentryMeasurementUnit.microSecond: - return micros.toDouble(); - case DurationSentryMeasurementUnit.milliSecond: - return micros / 1000.0; - case DurationSentryMeasurementUnit.second: - return micros / 1000000.0; - case DurationSentryMeasurementUnit.minute: - return micros / 60000000.0; - case DurationSentryMeasurementUnit.hour: - return micros / 3600000000.0; - case DurationSentryMeasurementUnit.day: - return micros / 86400000000.0; - case DurationSentryMeasurementUnit.week: - return micros / 86400000000.0 / 7.0; - } - } -} diff --git a/dart/lib/src/noop_hub.dart b/dart/lib/src/noop_hub.dart index 10f34a6d42..d07e3c9609 100644 --- a/dart/lib/src/noop_hub.dart +++ b/dart/lib/src/noop_hub.dart @@ -4,9 +4,6 @@ import 'package:meta/meta.dart'; import 'hint.dart'; import 'hub.dart'; -import 'metrics/metric.dart'; -import 'metrics/metrics_aggregator.dart'; -import 'metrics/metrics_api.dart'; import 'profiling.dart'; import 'protocol.dart'; import 'protocol/sentry_feedback.dart'; @@ -17,24 +14,16 @@ import 'sentry_user_feedback.dart'; import 'tracing.dart'; class NoOpHub implements Hub { - NoOpHub._() { - _metricsApi = MetricsApi(hub: this); - } + NoOpHub._(); static final NoOpHub _instance = NoOpHub._(); final _options = SentryOptions.empty(); - late final MetricsApi _metricsApi; - @override @internal SentryOptions get options => _options; - @override - @internal - MetricsApi get metricsApi => _metricsApi; - factory NoOpHub() { return _instance; } @@ -152,14 +141,4 @@ class NoOpHub implements Hub { @override Scope get scope => Scope(_options); - - @override - @internal - Future captureMetrics( - Map> metricsBuckets) async => - SentryId.empty(); - - @override - @internal - MetricsAggregator? get metricsAggregator => null; } diff --git a/dart/lib/src/noop_sentry_client.dart b/dart/lib/src/noop_sentry_client.dart index f2854f4f7e..7aa9aabe73 100644 --- a/dart/lib/src/noop_sentry_client.dart +++ b/dart/lib/src/noop_sentry_client.dart @@ -1,10 +1,6 @@ import 'dart:async'; -import 'package:meta/meta.dart'; - import 'hint.dart'; -import 'metrics/metric.dart'; -import 'metrics/metrics_aggregator.dart'; import 'protocol.dart'; import 'protocol/sentry_feedback.dart'; import 'scope.dart'; @@ -70,16 +66,6 @@ class NoOpSentryClient implements SentryClient { }) async => SentryId.empty(); - @override - @internal - Future captureMetrics( - Map> metricsBuckets) async => - SentryId.empty(); - - @override - @internal - MetricsAggregator? get metricsAggregator => null; - @override Future captureFeedback(SentryFeedback feedback, {Scope? scope, Hint? hint}) async => diff --git a/dart/lib/src/noop_sentry_span.dart b/dart/lib/src/noop_sentry_span.dart index 45d72b94c9..2156aeb678 100644 --- a/dart/lib/src/noop_sentry_span.dart +++ b/dart/lib/src/noop_sentry_span.dart @@ -1,4 +1,3 @@ -import 'metrics/local_metrics_aggregator.dart'; import 'protocol.dart'; import 'tracing.dart'; import 'utils.dart'; @@ -96,7 +95,4 @@ class NoOpSentrySpan extends ISentrySpan { @override void scheduleFinish() {} - - @override - LocalMetricsAggregator? get localMetricsAggregator => null; } diff --git a/dart/lib/src/protocol.dart b/dart/lib/src/protocol.dart index 6d89823721..e8bfb8d460 100644 --- a/dart/lib/src/protocol.dart +++ b/dart/lib/src/protocol.dart @@ -1,44 +1,41 @@ -export 'protocol/sentry_app.dart'; export 'protocol/breadcrumb.dart'; -export 'protocol/sentry_browser.dart'; export 'protocol/contexts.dart'; export 'protocol/debug_image.dart'; export 'protocol/debug_meta.dart'; -export 'protocol/sentry_device.dart'; export 'protocol/dsn.dart'; -export 'protocol/sentry_gpu.dart'; +export 'protocol/max_body_size.dart'; export 'protocol/mechanism.dart'; -export 'protocol/metric_summary.dart'; -export 'protocol/sentry_message.dart'; -export 'protocol/sentry_operating_system.dart'; -export 'protocol/sentry_request.dart'; -export 'protocol/sentry_response.dart'; export 'protocol/sdk_info.dart'; export 'protocol/sdk_version.dart'; +export 'protocol/sentry_app.dart'; +export 'protocol/sentry_baggage_header.dart'; +export 'protocol/sentry_browser.dart'; +export 'protocol/sentry_culture.dart'; +export 'protocol/sentry_device.dart'; export 'protocol/sentry_event.dart'; export 'protocol/sentry_exception.dart'; +export 'protocol/sentry_geo.dart'; +export 'protocol/sentry_gpu.dart'; export 'protocol/sentry_id.dart'; export 'protocol/sentry_level.dart'; +export 'protocol/sentry_message.dart'; +export 'protocol/sentry_operating_system.dart'; export 'protocol/sentry_package.dart'; +export 'protocol/sentry_request.dart'; +export 'protocol/sentry_response.dart'; export 'protocol/sentry_runtime.dart'; +export 'protocol/sentry_span.dart'; export 'protocol/sentry_stack_frame.dart'; export 'protocol/sentry_stack_trace.dart'; -export 'protocol/sentry_user.dart'; -export 'protocol/sentry_geo.dart'; -export 'protocol/max_body_size.dart'; -export 'protocol/sentry_culture.dart'; export 'protocol/sentry_thread.dart'; -export 'sentry_event_like.dart'; -// tracing -export 'protocol/span_status.dart'; -export 'protocol/span_id.dart'; -export 'protocol/sentry_transaction.dart'; export 'protocol/sentry_trace_context.dart'; -export 'protocol/sentry_span.dart'; export 'protocol/sentry_trace_header.dart'; -export 'protocol/sentry_transaction_name_source.dart'; -export 'protocol/sentry_baggage_header.dart'; +export 'protocol/sentry_transaction.dart'; export 'protocol/sentry_transaction_info.dart'; -// view hierarchy +export 'protocol/sentry_transaction_name_source.dart'; +export 'protocol/sentry_user.dart'; export 'protocol/sentry_view_hierarchy.dart'; export 'protocol/sentry_view_hierarchy_element.dart'; +export 'protocol/span_id.dart'; +export 'protocol/span_status.dart'; +export 'sentry_event_like.dart'; diff --git a/dart/lib/src/protocol/metric_summary.dart b/dart/lib/src/protocol/metric_summary.dart deleted file mode 100644 index f5354bfdf7..0000000000 --- a/dart/lib/src/protocol/metric_summary.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:meta/meta.dart'; - -import '../metrics/metric.dart'; -import 'access_aware_map.dart'; - -class MetricSummary { - final num min; - final num max; - final num sum; - final int count; - final Map? tags; - - @internal - final Map? unknown; - - MetricSummary.fromGauge(GaugeMetric gauge, {this.unknown}) - : min = gauge.minimum, - max = gauge.maximum, - sum = gauge.sum, - count = gauge.count, - tags = gauge.tags; - - const MetricSummary( - {required this.min, - required this.max, - required this.sum, - required this.count, - required this.tags, - this.unknown}); - - /// Deserializes a [MetricSummary] from JSON [Map]. - factory MetricSummary.fromJson(Map data) { - final json = AccessAwareMap(data); - return MetricSummary( - min: json['min'], - max: json['max'], - count: json['count'], - sum: json['sum'], - tags: json['tags']?.cast(), - unknown: json.notAccessed(), - ); - } - - /// Produces a [Map] that can be serialized to JSON. - Map toJson() { - return { - ...?unknown, - 'min': min, - 'max': max, - 'count': count, - 'sum': sum, - if (tags?.isNotEmpty ?? false) 'tags': tags, - }; - } -} diff --git a/dart/lib/src/protocol/sentry_span.dart b/dart/lib/src/protocol/sentry_span.dart index 00f6ec8f5a..52d1b949a8 100644 --- a/dart/lib/src/protocol/sentry_span.dart +++ b/dart/lib/src/protocol/sentry_span.dart @@ -3,8 +3,6 @@ import 'dart:async'; import 'package:meta/meta.dart'; import '../../sentry.dart'; -import '../metrics/local_metrics_aggregator.dart'; - import '../sentry_tracer.dart'; typedef OnFinishedCallback = Future Function({DateTime? endTimestamp}); @@ -12,7 +10,6 @@ typedef OnFinishedCallback = Future Function({DateTime? endTimestamp}); class SentrySpan extends ISentrySpan { final SentrySpanContext _context; DateTime? _endTimestamp; - Map>? _metricSummaries; late final DateTime _startTimestamp; final Hub _hub; @@ -31,7 +28,6 @@ class SentrySpan extends ISentrySpan { SpanStatus? _status; final Map _tags = {}; OnFinishedCallback? _finishedCallback; - late final LocalMetricsAggregator? _localMetricsAggregator; @override final SentryTracesSamplingDecision? samplingDecision; @@ -48,9 +44,6 @@ class SentrySpan extends ISentrySpan { _startTimestamp = startTimestamp?.toUtc() ?? _hub.options.clock(); _finishedCallback = finishedCallback; _origin = _context.origin; - _localMetricsAggregator = _hub.options.enableSpanLocalMetricAggregation - ? LocalMetricsAggregator() - : null; _isRootSpan = isRootSpan; } @@ -90,7 +83,6 @@ class SentrySpan extends ISentrySpan { if (_throwable != null) { _hub.setSpanContext(_throwable, this, _tracer.name); } - _metricSummaries = _localMetricsAggregator?.getSummaries(); await _finishedCallback?.call(endTimestamp: _endTimestamp); return super.finish(status: status, endTimestamp: _endTimestamp); } @@ -180,9 +172,6 @@ class SentrySpan extends ISentrySpan { @override set origin(String? origin) => _origin = origin; - @override - LocalMetricsAggregator? get localMetricsAggregator => _localMetricsAggregator; - Map toJson() { final json = _context.toJson(); json['start_timestamp'] = @@ -204,15 +193,6 @@ class SentrySpan extends ISentrySpan { json['origin'] = _origin; } - final metricSummariesMap = _metricSummaries?.entries ?? Iterable.empty(); - if (metricSummariesMap.isNotEmpty) { - final map = {}; - for (final entry in metricSummariesMap) { - final summary = entry.value.map((e) => e.toJson()); - map[entry.key] = summary.toList(growable: false); - } - json['_metrics_summary'] = map; - } return json; } diff --git a/dart/lib/src/protocol/sentry_transaction.dart b/dart/lib/src/protocol/sentry_transaction.dart index 8ab9fefa45..0525aa7251 100644 --- a/dart/lib/src/protocol/sentry_transaction.dart +++ b/dart/lib/src/protocol/sentry_transaction.dart @@ -1,9 +1,9 @@ import 'package:meta/meta.dart'; import '../protocol.dart'; +import '../sentry_measurement.dart'; import '../sentry_tracer.dart'; import '../utils.dart'; -import '../sentry_measurement.dart'; @immutable class SentryTransaction extends SentryEvent { @@ -13,7 +13,6 @@ class SentryTransaction extends SentryEvent { @internal final SentryTracer tracer; late final Map measurements; - late final Map>? metricSummaries; late final SentryTransactionInfo? transactionInfo; SentryTransaction( @@ -38,7 +37,6 @@ class SentryTransaction extends SentryEvent { super.request, String? type, Map? measurements, - Map>? metricSummaries, SentryTransactionInfo? transactionInfo, }) : super( timestamp: timestamp ?? tracer.endTimestamp, @@ -54,8 +52,6 @@ class SentryTransaction extends SentryEvent { final spanContext = tracer.context; spans = tracer.children; this.measurements = measurements ?? {}; - this.metricSummaries = - metricSummaries ?? tracer.localMetricsAggregator?.getSummaries(); final data = extra ?? tracer.data; contexts.trace = spanContext.toTraceContext( @@ -91,16 +87,6 @@ class SentryTransaction extends SentryEvent { json['transaction_info'] = transactionInfo.toJson(); } - final metricSummariesMap = metricSummaries?.entries ?? Iterable.empty(); - if (metricSummariesMap.isNotEmpty) { - final map = {}; - for (final entry in metricSummariesMap) { - final summary = entry.value.map((e) => e.toJson()); - map[entry.key] = summary.toList(growable: false); - } - json['_metrics_summary'] = map; - } - return json; } @@ -139,7 +125,6 @@ class SentryTransaction extends SentryEvent { List? threads, String? type, Map? measurements, - Map>? metricSummaries, SentryTransactionInfo? transactionInfo, }) => SentryTransaction( @@ -165,9 +150,6 @@ class SentryTransaction extends SentryEvent { type: type ?? this.type, measurements: (measurements != null ? Map.from(measurements) : null) ?? this.measurements, - metricSummaries: - (metricSummaries != null ? Map.from(metricSummaries) : null) ?? - this.metricSummaries, transactionInfo: transactionInfo ?? this.transactionInfo, ); } diff --git a/dart/lib/src/sentry.dart b/dart/lib/src/sentry.dart index 310c3cecae..91c511ebfd 100644 --- a/dart/lib/src/sentry.dart +++ b/dart/lib/src/sentry.dart @@ -3,28 +3,27 @@ import 'dart:async'; import 'package:meta/meta.dart'; import 'dart_exception_type_identifier.dart'; -import 'load_dart_debug_images_integration.dart'; -import 'metrics/metrics_api.dart'; -import 'protocol/sentry_feedback.dart'; -import 'run_zoned_guarded_integration.dart'; -import 'event_processor/enricher/enricher_event_processor.dart'; import 'environment/environment_variables.dart'; import 'event_processor/deduplication_event_processor.dart'; -import 'hint.dart'; +import 'event_processor/enricher/enricher_event_processor.dart'; import 'event_processor/exception/exception_event_processor.dart'; +import 'hint.dart'; import 'hub.dart'; import 'hub_adapter.dart'; import 'integration.dart'; +import 'load_dart_debug_images_integration.dart'; import 'noop_hub.dart'; import 'noop_isolate_error_integration.dart' if (dart.library.io) 'isolate_error_integration.dart'; import 'protocol.dart'; +import 'protocol/sentry_feedback.dart'; +import 'run_zoned_guarded_integration.dart'; +import 'sentry_attachment/sentry_attachment.dart'; import 'sentry_client.dart'; import 'sentry_options.dart'; import 'sentry_run_zoned_guarded.dart'; import 'sentry_user_feedback.dart'; import 'tracing.dart'; -import 'sentry_attachment/sentry_attachment.dart'; import 'transport/data_category.dart'; import 'transport/task_queue.dart'; @@ -359,11 +358,6 @@ class Sentry { /// Gets the current active transaction or span bound to the scope. static ISentrySpan? getSpan() => _hub.getSpan(); - /// Gets access to the metrics API for the current hub. - @Deprecated( - 'Metrics will be deprecated and removed in the next major release. Sentry will reject all metrics sent after October 7, 2024. Learn more: https://sentry.zendesk.com/hc/en-us/articles/26369339769883-Upcoming-API-Changes-to-Metrics') - static MetricsApi metrics() => _hub.metricsApi; - @internal static Hub get currentHub => _hub; diff --git a/dart/lib/src/sentry_client.dart b/dart/lib/src/sentry_client.dart index f5a893b45a..9c89ecb414 100644 --- a/dart/lib/src/sentry_client.dart +++ b/dart/lib/src/sentry_client.dart @@ -2,14 +2,11 @@ import 'dart:async'; import 'dart:math'; import 'package:meta/meta.dart'; -import 'type_check_hint.dart'; import 'client_reports/client_report_recorder.dart'; import 'client_reports/discard_reason.dart'; import 'event_processor.dart'; import 'hint.dart'; -import 'metrics/metric.dart'; -import 'metrics/metrics_aggregator.dart'; import 'protocol.dart'; import 'protocol/sentry_feedback.dart'; import 'scope.dart'; @@ -27,6 +24,7 @@ import 'transport/http_transport.dart'; import 'transport/noop_transport.dart'; import 'transport/rate_limiter.dart'; import 'transport/spotlight_http_transport.dart'; +import 'type_check_hint.dart'; import 'utils/isolate_utils.dart'; import 'utils/regex_utils.dart'; import 'utils/stacktrace_utils.dart'; @@ -43,8 +41,6 @@ class SentryClient { final Random? _random; - late final MetricsAggregator? _metricsAggregator; - static final _emptySentryId = Future.value(SentryId.empty()); SentryExceptionFactory get _exceptionFactory => _options.exceptionFactory; @@ -82,13 +78,7 @@ class SentryClient { /// Instantiates a client using [SentryOptions] SentryClient._(this._options) - : _random = _options.sampleRate == null ? null : Random(), - _metricsAggregator = _options.enableMetrics - ? MetricsAggregator(options: _options) - : null; - - @internal - MetricsAggregator? get metricsAggregator => _metricsAggregator; + : _random = _options.sampleRate == null ? null : Random(); /// Reports an [event] to Sentry.io. Future captureEvent( @@ -482,20 +472,7 @@ class SentryClient { ); } - /// Reports the [metricsBuckets] to Sentry.io. - Future captureMetrics( - Map> metricsBuckets) async { - final envelope = SentryEnvelope.fromMetrics( - metricsBuckets, - _options.sdk, - dsn: _options.dsn, - ); - final id = await _options.transport.send(envelope); - return id ?? SentryId.empty(); - } - void close() { - _metricsAggregator?.close(); _options.httpClient.close(); } diff --git a/dart/lib/src/sentry_envelope.dart b/dart/lib/src/sentry_envelope.dart index 50a2b84e41..5d83797143 100644 --- a/dart/lib/src/sentry_envelope.dart +++ b/dart/lib/src/sentry_envelope.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'client_reports/client_report.dart'; -import 'metrics/metric.dart'; import 'protocol.dart'; import 'sentry_attachment/sentry_attachment.dart'; import 'sentry_envelope_header.dart'; @@ -100,22 +99,6 @@ class SentryEnvelope { ); } - /// Create a [SentryEnvelope] containing one [SentryEnvelopeItem] which holds the [Metric] data. - factory SentryEnvelope.fromMetrics( - Map> metricsBuckets, - SdkVersion sdkVersion, { - String? dsn, - }) { - return SentryEnvelope( - SentryEnvelopeHeader( - SentryId.newId(), - sdkVersion, - dsn: dsn, - ), - [SentryEnvelopeItem.fromMetrics(metricsBuckets)], - ); - } - /// Stream binary data representation of `Envelope` file encoded. Stream> envelopeStream(SentryOptions options) async* { yield utf8JsonEncoder.convert(header.toJson()); diff --git a/dart/lib/src/sentry_envelope_item.dart b/dart/lib/src/sentry_envelope_item.dart index a671730fb6..03164ba2a8 100644 --- a/dart/lib/src/sentry_envelope_item.dart +++ b/dart/lib/src/sentry_envelope_item.dart @@ -1,8 +1,6 @@ import 'dart:async'; -import 'dart:convert'; import 'client_reports/client_report.dart'; -import 'metrics/metric.dart'; import 'protocol.dart'; import 'sentry_attachment/sentry_attachment.dart'; import 'sentry_envelope_item_header.dart'; @@ -82,30 +80,6 @@ class SentryEnvelopeItem { ); } - /// Creates a [SentryEnvelopeItem] which holds several [Metric] data. - factory SentryEnvelopeItem.fromMetrics(Map> buckets) { - final dataFactory = () { - final statsd = StringBuffer(); - // Encode all metrics of a bucket in statsd format, using the bucket key, - // which is the timestamp of the bucket. - for (final bucket in buckets.entries) { - final encodedMetrics = - bucket.value.map((metric) => metric.encodeToStatsd(bucket.key)); - statsd.write(encodedMetrics.join('\n')); - } - return utf8.encode(statsd.toString()); - }; - final header = SentryEnvelopeItemHeader( - SentryItemType.statsd, - contentType: 'application/octet-stream', - ); - return SentryEnvelopeItem( - header, - dataFactory, - originalObject: buckets, - ); - } - /// Header with info about type and length of data in bytes. final SentryEnvelopeItemHeader header; diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index fa30ca8117..90df95261e 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -451,48 +451,6 @@ class SentryOptions { 'Use either tracesSampleRate or tracesSampler instead. This will be removed in v9') bool? enableTracing; - /// Enables sending developer metrics to Sentry. - /// More on https://develop.sentry.dev/delightful-developer-metrics/. - /// Example: - /// ```dart - /// Sentry.metrics.counter('myMetric'); - /// ``` - @experimental - bool enableMetrics = false; - - @experimental - bool _enableDefaultTagsForMetrics = true; - - /// Enables enriching metrics with default tags. Requires [enableMetrics]. - /// More on https://develop.sentry.dev/delightful-developer-metrics/sending-metrics-sdk/#automatic-tags-extraction - /// Currently adds release, environment and transaction name. - @experimental - bool get enableDefaultTagsForMetrics => - enableMetrics && _enableDefaultTagsForMetrics; - - /// Enables enriching metrics with default tags. Requires [enableMetrics]. - /// More on https://develop.sentry.dev/delightful-developer-metrics/sending-metrics-sdk/#automatic-tags-extraction - /// Currently adds release, environment and transaction name. - @experimental - set enableDefaultTagsForMetrics(final bool enableDefaultTagsForMetrics) => - _enableDefaultTagsForMetrics = enableDefaultTagsForMetrics; - - @experimental - bool _enableSpanLocalMetricAggregation = true; - - /// Enables span metrics aggregation. Requires [enableMetrics]. - /// More on https://develop.sentry.dev/sdk/metrics/#span-aggregation - @experimental - bool get enableSpanLocalMetricAggregation => - enableMetrics && _enableSpanLocalMetricAggregation; - - /// Enables span metrics aggregation. Requires [enableMetrics]. - /// More on https://develop.sentry.dev/sdk/metrics/#span-aggregation - @experimental - set enableSpanLocalMetricAggregation( - final bool enableSpanLocalMetricAggregation) => - _enableSpanLocalMetricAggregation = enableSpanLocalMetricAggregation; - /// Only for internal use. Changed SDK behaviour when set to true: /// - Rethrow exceptions that occur in user provided closures @internal diff --git a/dart/lib/src/sentry_span_interface.dart b/dart/lib/src/sentry_span_interface.dart index 979822c2ac..f6c36c49e7 100644 --- a/dart/lib/src/sentry_span_interface.dart +++ b/dart/lib/src/sentry_span_interface.dart @@ -1,6 +1,5 @@ import 'package:meta/meta.dart'; -import 'metrics/local_metrics_aggregator.dart'; import 'protocol.dart'; import 'tracing.dart'; @@ -47,9 +46,6 @@ abstract class ISentrySpan { /// See https://develop.sentry.dev/sdk/performance/trace-origin set origin(String? origin); - @internal - LocalMetricsAggregator? get localMetricsAggregator; - /// Returns the end timestamp if finished DateTime? get endTimestamp; diff --git a/dart/lib/src/sentry_tracer.dart b/dart/lib/src/sentry_tracer.dart index 0f53d26e38..05a1fd87d0 100644 --- a/dart/lib/src/sentry_tracer.dart +++ b/dart/lib/src/sentry_tracer.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'package:meta/meta.dart'; import '../sentry.dart'; -import 'metrics/local_metrics_aggregator.dart'; import 'profiling.dart'; import 'sentry_tracer_finish_status.dart'; import 'utils/sample_rate_format.dart'; @@ -426,8 +425,4 @@ class SentryTracer extends ISentrySpan { }); } } - - @override - LocalMetricsAggregator? get localMetricsAggregator => - _rootSpan.localMetricsAggregator; } diff --git a/dart/test/hub_test.dart b/dart/test/hub_test.dart index 12eaf8d227..6dbf6f1288 100644 --- a/dart/test/hub_test.dart +++ b/dart/test/hub_test.dart @@ -100,21 +100,6 @@ void main() { expect(fixture.client.captureMessageCalls.first.scope, isNotNull); }); - test('should capture metrics', () async { - final hub = fixture.getSut(); - await hub.captureMetrics(fakeMetrics); - - expect(fixture.client.captureMetricsCalls.length, 1); - expect( - fixture.client.captureMetricsCalls.first.values, - [ - [fakeMetric], - [fakeMetric, fakeMetric2], - [fakeMetric, fakeMetric3, fakeMetric4], - ], - ); - }); - test('should save the lastEventId', () async { final hub = fixture.getSut(); final event = SentryEvent(); @@ -767,44 +752,6 @@ void main() { expect(spanCount, 4); }); }); - - group('Metrics', () { - late Fixture fixture; - - setUp(() { - fixture = Fixture(); - }); - - test('should not capture metrics if enableMetric is false', () async { - final hub = fixture.getSut(enableMetrics: false, debug: true); - await hub.captureMetrics(fakeMetrics); - - expect(fixture.client.captureMetricsCalls, isEmpty); - expect(fixture.loggedMessage, - 'Metrics are disabled and this \'captureMetrics\' call is a no-op.'); - }); - - test('should not capture metrics if hub is closed', () async { - final hub = fixture.getSut(debug: true); - await hub.close(); - - expect(hub.isEnabled, false); - await hub.captureMetrics(fakeMetrics); - expect(fixture.loggedMessage, - 'Instance is disabled and this \'captureMetrics\' call is a no-op.'); - - expect(fixture.client.captureMetricsCalls, isEmpty); - }); - - test('should not capture metrics if metrics are empty', () async { - final hub = fixture.getSut(debug: true); - await hub.captureMetrics({}); - expect(fixture.loggedMessage, - 'Metrics are empty and this \'captureMetrics\' call is a no-op.'); - - expect(fixture.client.captureMetricsCalls, isEmpty); - }); - }); } class Fixture { @@ -823,13 +770,11 @@ class Fixture { double? tracesSampleRate = 1.0, TracesSamplerCallback? tracesSampler, bool? sampled = true, - bool enableMetrics = true, bool debug = false, }) { options.tracesSampleRate = tracesSampleRate; options.tracesSampler = tracesSampler; options.debug = debug; - options.enableMetrics = enableMetrics; options.logger = mockLogger; // Enable logging in DiagnosticsLogger final hub = Hub(options); diff --git a/dart/test/mocks.dart b/dart/test/mocks.dart index 679b9f73cd..a658ce0fd8 100644 --- a/dart/test/mocks.dart +++ b/dart/test/mocks.dart @@ -1,6 +1,5 @@ import 'package:mockito/annotations.dart'; import 'package:sentry/sentry.dart'; -import 'package:sentry/src/metrics/metric.dart'; import 'package:sentry/src/profiling.dart'; import 'package:sentry/src/transport/rate_limiter.dart'; @@ -98,37 +97,6 @@ final fakeEvent = SentryEvent( ), ); -final fakeMetric = Metric.fromType( - type: MetricType.counter, - value: 4, - key: 'key', - unit: DurationSentryMeasurementUnit.hour, - tags: {'tag1': 'value1', 'tag2': 'value2'}); -final fakeMetric2 = Metric.fromType( - type: MetricType.counter, - value: 2, - key: 'key', - unit: SentryMeasurementUnit.none, - tags: {'tag1': 'value1', 'tag2': 'value2'}); -final fakeMetric3 = Metric.fromType( - type: MetricType.counter, - value: 2, - key: 'key', - unit: SentryMeasurementUnit.none, - tags: {'tag1': 'value1'}); -final fakeMetric4 = Metric.fromType( - type: MetricType.counter, - value: 2, - key: 'key2', - unit: SentryMeasurementUnit.none, - tags: {'tag1': 'value1'}); - -final Map> fakeMetrics = { - 10: [fakeMetric], - 20: [fakeMetric, fakeMetric2], - 30: [fakeMetric, fakeMetric3, fakeMetric4], -}; - /// Always returns null and thus drops all events class DropAllEventProcessor implements EventProcessor { @override diff --git a/dart/test/mocks/mock_hub.dart b/dart/test/mocks/mock_hub.dart index dcd305e821..62db6c13a4 100644 --- a/dart/test/mocks/mock_hub.dart +++ b/dart/test/mocks/mock_hub.dart @@ -1,7 +1,5 @@ import 'package:meta/meta.dart'; import 'package:sentry/sentry.dart'; -import 'package:sentry/src/metrics/metric.dart'; -import 'package:sentry/src/metrics/metrics_aggregator.dart'; import '../test_utils.dart'; import 'mock_sentry_client.dart'; @@ -17,23 +15,17 @@ class MockHub with NoSuchMethodProvider implements Hub { // ignore: deprecated_member_use_from_same_package List userFeedbackCalls = []; List captureTransactionCalls = []; - List captureMetricsCalls = []; int closeCalls = 0; bool _isEnabled = true; int spanContextCals = 0; int getSpanCalls = 0; final _options = defaultTestOptions(); - late final MetricsAggregator _metricsAggregator = - MetricsAggregator(options: _options, hub: this); @override @internal SentryOptions get options => _options; - @override - MetricsAggregator? get metricsAggregator => _metricsAggregator; - /// Useful for tests. void reset() { captureEventCalls = []; @@ -45,7 +37,6 @@ class MockHub with NoSuchMethodProvider implements Hub { _isEnabled = true; spanContextCals = 0; captureTransactionCalls = []; - captureMetricsCalls = []; getSpanCalls = 0; } @@ -127,13 +118,6 @@ class MockHub with NoSuchMethodProvider implements Hub { return transaction.eventId; } - @override - Future captureMetrics( - Map> metricsBuckets) async { - captureMetricsCalls.add(CaptureMetricsCall(metricsBuckets)); - return SentryId.newId(); - } - @override // ignore: deprecated_member_use_from_same_package Future captureUserFeedback(SentryUserFeedback userFeedback) async { diff --git a/dart/test/mocks/mock_sentry_client.dart b/dart/test/mocks/mock_sentry_client.dart index c0e4ba9ffe..7a79b31f7c 100644 --- a/dart/test/mocks/mock_sentry_client.dart +++ b/dart/test/mocks/mock_sentry_client.dart @@ -1,5 +1,4 @@ import 'package:sentry/sentry.dart'; -import 'package:sentry/src/metrics/metric.dart'; import 'no_such_method_provider.dart'; @@ -13,7 +12,6 @@ class MockSentryClient with NoSuchMethodProvider implements SentryClient { // ignore: deprecated_member_use_from_same_package List userFeedbackCalls = []; List captureFeedbackCalls = []; - List>> captureMetricsCalls = []; int closeCalls = 0; @override @@ -94,12 +92,6 @@ class MockSentryClient with NoSuchMethodProvider implements SentryClient { return SentryId.newId(); } - @override - Future captureMetrics(Map> metrics) async { - captureMetricsCalls.add(metrics); - return SentryId.newId(); - } - @override void close() { closeCalls = closeCalls + 1; @@ -187,9 +179,3 @@ class CaptureTransactionCall { CaptureTransactionCall(this.transaction, this.traceContext); } - -class CaptureMetricsCall { - final Map> metricsBuckets; - - CaptureMetricsCall(this.metricsBuckets); -} diff --git a/dart/test/protocol/rate_limiter_test.dart b/dart/test/protocol/rate_limiter_test.dart index 96d91ea685..c90c689e01 100644 --- a/dart/test/protocol/rate_limiter_test.dart +++ b/dart/test/protocol/rate_limiter_test.dart @@ -1,12 +1,11 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:sentry/src/client_reports/discard_reason.dart'; +import 'package:sentry/src/sentry_envelope_header.dart'; +import 'package:sentry/src/sentry_tracer.dart'; import 'package:sentry/src/transport/data_category.dart'; -import 'package:test/test.dart'; - import 'package:sentry/src/transport/rate_limiter.dart'; -import 'package:sentry/src/sentry_tracer.dart'; -import 'package:sentry/src/sentry_envelope_header.dart'; +import 'package:test/test.dart'; import '../mocks/mock_client_report_recorder.dart'; import '../mocks/mock_hub.dart'; @@ -248,27 +247,6 @@ void main() { expect(spanDiscardedEvent!.quantity, 3); }); - test('dropping of metrics recorded', () { - final rateLimiter = fixture.getSut(); - - final metricsItem = SentryEnvelopeItem.fromMetrics({}); - final eventEnvelope = SentryEnvelope( - SentryEnvelopeHeader.newEventId(), - [metricsItem], - ); - - rateLimiter.updateRetryAfterLimits( - '1:metric_bucket:key, 5:metric_bucket:organization', null, 1); - - final result = rateLimiter.filter(eventEnvelope); - expect(result, isNull); - - expect(fixture.mockRecorder.discardedEvents.first.category, - DataCategory.metricBucket); - expect(fixture.mockRecorder.discardedEvents.first.reason, - DiscardReason.rateLimitBackoff); - }); - group('apply rateLimit', () { test('error', () { final rateLimiter = fixture.getSut(); @@ -303,63 +281,6 @@ void main() { final result = rateLimiter.filter(envelope); expect(result, isNull); }); - - test('metrics', () { - final rateLimiter = fixture.getSut(); - fixture.dateTimeToReturn = 0; - - final metricsItem = SentryEnvelopeItem.fromMetrics({}); - final envelope = SentryEnvelope( - SentryEnvelopeHeader.newEventId(), - [metricsItem], - ); - - rateLimiter.updateRetryAfterLimits( - '1:metric_bucket:key, 5:metric_bucket:organization', null, 1); - - final result = rateLimiter.filter(envelope); - expect(result, isNull); - }); - - test('metrics with empty namespaces', () { - final rateLimiter = fixture.getSut(); - fixture.dateTimeToReturn = 0; - - final eventItem = SentryEnvelopeItem.fromEvent(SentryEvent()); - final metricsItem = SentryEnvelopeItem.fromMetrics({}); - final envelope = SentryEnvelope( - SentryEnvelopeHeader.newEventId(), - [eventItem, metricsItem], - ); - - rateLimiter.updateRetryAfterLimits( - '10:metric_bucket:key:quota_exceeded:', null, 1); - - final result = rateLimiter.filter(envelope); - expect(result, isNotNull); - expect(result!.items.length, 1); - expect(result.items.first.header.type, 'event'); - }); - - test('metrics with custom namespace', () { - final rateLimiter = fixture.getSut(); - fixture.dateTimeToReturn = 0; - - final eventItem = SentryEnvelopeItem.fromEvent(SentryEvent()); - final metricsItem = SentryEnvelopeItem.fromMetrics({}); - final envelope = SentryEnvelope( - SentryEnvelopeHeader.newEventId(), - [eventItem, metricsItem], - ); - - rateLimiter.updateRetryAfterLimits( - '10:metric_bucket:key:quota_exceeded:custom', null, 1); - - final result = rateLimiter.filter(envelope); - expect(result, isNotNull); - expect(result!.items.length, 1); - expect(result.items.first.header.type, 'event'); - }); }); } diff --git a/dart/test/sentry_client_test.dart b/dart/test/sentry_client_test.dart index 889e7fa88c..170dc9d36a 100644 --- a/dart/test/sentry_client_test.dart +++ b/dart/test/sentry_client_test.dart @@ -6,7 +6,6 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:sentry/src/client_reports/discard_reason.dart'; import 'package:sentry/src/client_reports/noop_client_report_recorder.dart'; -import 'package:sentry/src/metrics/metric.dart'; import 'package:sentry/src/sentry_item_type.dart'; import 'package:sentry/src/sentry_stack_trace_factory.dart'; import 'package:sentry/src/sentry_tracer.dart'; @@ -2158,42 +2157,6 @@ void main() { await client.captureEvent(fakeEvent, stackTrace: StackTrace.current); }); }); - - group('Capture metrics', () { - late Fixture fixture; - - setUp(() { - fixture = Fixture(); - }); - - test('metricsAggregator is set if metrics are enabled', () async { - final client = fixture.getSut(enableMetrics: true); - expect(client.metricsAggregator, isNotNull); - }); - - test('metricsAggregator is null if metrics are disabled', () async { - final client = fixture.getSut(enableMetrics: false); - expect(client.metricsAggregator, isNull); - }); - - test('captureMetrics send statsd envelope', () async { - final client = fixture.getSut(); - await client.captureMetrics(fakeMetrics); - - final capturedStatsd = (fixture.transport).statsdItems.first; - expect(capturedStatsd, isNotNull); - }); - - test('close closes metricsAggregator', () async { - final client = fixture.getSut(); - client.close(); - expect(client.metricsAggregator, isNotNull); - client.metricsAggregator! - .emit(MetricType.counter, 'key', 1, SentryMeasurementUnit.none, {}); - // metricsAggregator is closed, so no metrics should be recorded - expect(client.metricsAggregator!.buckets, isEmpty); - }); - }); } Future eventFromEnvelope(SentryEnvelope envelope) async { @@ -2294,7 +2257,6 @@ class Fixture { bool sendDefaultPii = false, bool attachStacktrace = true, bool attachThreads = false, - bool enableMetrics = true, double? sampleRate, BeforeSendCallback? beforeSend, BeforeSendTransactionCallback? beforeSendTransaction, @@ -2306,7 +2268,6 @@ class Fixture { }) { options.tracesSampleRate = 1.0; options.sendDefaultPii = sendDefaultPii; - options.enableMetrics = enableMetrics; options.attachStacktrace = attachStacktrace; options.attachThreads = attachThreads; options.sampleRate = sampleRate; diff --git a/dart/test/sentry_envelope_item_test.dart b/dart/test/sentry_envelope_item_test.dart index 1af2756f9a..aac20a7fb5 100644 --- a/dart/test/sentry_envelope_item_test.dart +++ b/dart/test/sentry_envelope_item_test.dart @@ -4,13 +4,11 @@ import 'package:sentry/sentry.dart'; import 'package:sentry/src/client_reports/client_report.dart'; import 'package:sentry/src/client_reports/discard_reason.dart'; import 'package:sentry/src/client_reports/discarded_event.dart'; -import 'package:sentry/src/metrics/metric.dart'; import 'package:sentry/src/sentry_item_type.dart'; import 'package:sentry/src/sentry_tracer.dart'; import 'package:sentry/src/transport/data_category.dart'; import 'package:test/test.dart'; -import 'mocks.dart'; import 'mocks/mock_hub.dart'; void main() { @@ -118,22 +116,5 @@ void main() { expect(sut.header.type, SentryItemType.userFeedback); expect(actualData, expectedData); }); - - test('fromMetrics', () async { - final sut = SentryEnvelopeItem.fromMetrics(fakeMetrics); - - final StringBuffer statsd = StringBuffer(); - for (MapEntry> bucket in fakeMetrics.entries) { - final Iterable encodedMetrics = - bucket.value.map((metric) => metric.encodeToStatsd(bucket.key)); - statsd.write(encodedMetrics.join('\n')); - } - final expectedData = utf8.encode(statsd.toString()); - final actualData = await sut.dataFactory(); - - expect(sut.header.contentType, 'application/octet-stream'); - expect(sut.header.type, SentryItemType.statsd); - expect(actualData, expectedData); - }); }); } diff --git a/dart/test/sentry_envelope_test.dart b/dart/test/sentry_envelope_test.dart index e79d8c1668..e8087527e7 100644 --- a/dart/test/sentry_envelope_test.dart +++ b/dart/test/sentry_envelope_test.dart @@ -165,28 +165,6 @@ void main() { expect(actualItem, expectedItem); }); - test('fromMetrics', () async { - final sdkVersion = - SdkVersion(name: 'fixture-name', version: 'fixture-version'); - final sut = SentryEnvelope.fromMetrics( - fakeMetrics, - sdkVersion, - dsn: fakeDsn, - ); - - final expectedEnvelopeItem = SentryEnvelopeItem.fromMetrics(fakeMetrics); - - expect(sut.header.sdkVersion, sdkVersion); - expect(sut.header.dsn, fakeDsn); - expect(sut.items[0].header.contentType, - expectedEnvelopeItem.header.contentType); - expect(sut.items[0].header.type, expectedEnvelopeItem.header.type); - - final actualItem = await sut.items[0].dataFactory(); - final expectedItem = await expectedEnvelopeItem.dataFactory(); - expect(actualItem, expectedItem); - }); - test('max attachment size', () async { final attachment = SentryAttachment.fromLoader( loader: () => Uint8List.fromList([1, 2, 3, 4]), diff --git a/dart/test/sentry_options_test.dart b/dart/test/sentry_options_test.dart index 8cf1f409a5..958594b818 100644 --- a/dart/test/sentry_options_test.dart +++ b/dart/test/sentry_options_test.dart @@ -136,63 +136,12 @@ void main() { expect(options.spotlight.enabled, false); }); - test('metrics are disabled by default', () { - final options = defaultTestOptions(); - - expect(options.enableMetrics, false); - }); - test('enableExceptionTypeIdentification is enabled by default', () { final options = defaultTestOptions(); expect(options.enableExceptionTypeIdentification, true); }); - test('default tags for metrics are enabled by default', () { - final options = defaultTestOptions(); - options.enableMetrics = true; - - expect(options.enableDefaultTagsForMetrics, true); - }); - - test('default tags for metrics are disabled if metrics are disabled', () { - final options = defaultTestOptions(); - options.enableMetrics = false; - - expect(options.enableDefaultTagsForMetrics, false); - }); - - test('default tags for metrics are enabled if metrics are enabled, too', () { - final options = defaultTestOptions(); - options.enableMetrics = true; - options.enableDefaultTagsForMetrics = true; - - expect(options.enableDefaultTagsForMetrics, true); - }); - - test('span local metric aggregation is enabled by default', () { - final options = defaultTestOptions(); - options.enableMetrics = true; - - expect(options.enableSpanLocalMetricAggregation, true); - }); - - test('span local metric aggregation is disabled if metrics are disabled', () { - final options = defaultTestOptions(); - options.enableMetrics = false; - - expect(options.enableSpanLocalMetricAggregation, false); - }); - - test('span local metric aggregation is enabled if metrics are enabled, too', - () { - final options = defaultTestOptions(); - options.enableMetrics = true; - options.enableSpanLocalMetricAggregation = true; - - expect(options.enableSpanLocalMetricAggregation, true); - }); - test('enablePureDartSymbolication is enabled by default', () { final options = defaultTestOptions(); diff --git a/dart/test/sentry_span_test.dart b/dart/test/sentry_span_test.dart index d063cf787e..9e77f0ba81 100644 --- a/dart/test/sentry_span_test.dart +++ b/dart/test/sentry_span_test.dart @@ -2,7 +2,6 @@ import 'package:sentry/sentry.dart'; import 'package:sentry/src/sentry_tracer.dart'; import 'package:test/test.dart'; -import 'mocks.dart'; import 'mocks/mock_hub.dart'; void main() { @@ -126,14 +125,11 @@ void main() { }); test('span serializes', () async { - fixture.hub.options.enableMetrics = true; - fixture.hub.options.enableSpanLocalMetricAggregation = true; final sut = fixture.getSut(); sut.setTag('test', 'test'); sut.setData('test', 'test'); sut.origin = 'manual'; - sut.localMetricsAggregator?.add(fakeMetric, 0); await sut.finish(status: SpanStatus.aborted()); @@ -145,26 +141,6 @@ void main() { expect(map['tags']['test'], 'test'); expect(map['status'], 'aborted'); expect(map['origin'], 'manual'); - expect(map['_metrics_summary'], isNotNull); - }); - - test('adding a metric after span finish does not serialize', () async { - fixture.hub.options.enableMetrics = true; - fixture.hub.options.enableSpanLocalMetricAggregation = true; - final sut = fixture.getSut(); - await sut.finish(status: SpanStatus.aborted()); - sut.localMetricsAggregator?.add(fakeMetric, 0); - - expect(sut.toJson()['_metrics_summary'], isNull); - }); - - test('adding a metric when option is disabled does not serialize', () async { - fixture.hub.options.enableMetrics = false; - final sut = fixture.getSut(); - sut.localMetricsAggregator?.add(fakeMetric, 0); - await sut.finish(status: SpanStatus.aborted()); - - expect(sut.toJson()['_metrics_summary'], isNull); }); test('finished returns false if not yet', () { @@ -296,21 +272,6 @@ void main() { expect(sut.origin, 'manual'); }); - test('localMetricsAggregator is set when option is enabled', () async { - fixture.hub.options.enableMetrics = true; - fixture.hub.options.enableSpanLocalMetricAggregation = true; - final sut = fixture.getSut(); - expect(fixture.hub.options.enableSpanLocalMetricAggregation, true); - expect(sut.localMetricsAggregator, isNotNull); - }); - - test('localMetricsAggregator is null when option is disabled', () async { - fixture.hub.options.enableSpanLocalMetricAggregation = false; - final sut = fixture.getSut(); - expect(fixture.hub.options.enableSpanLocalMetricAggregation, false); - expect(sut.localMetricsAggregator, null); - }); - test('setMeasurement sets a measurement', () async { final sut = fixture.getSut(); sut.setMeasurement("test", 1); diff --git a/dart/test/sentry_tracer_test.dart b/dart/test/sentry_tracer_test.dart index 9bc6410725..667e43b159 100644 --- a/dart/test/sentry_tracer_test.dart +++ b/dart/test/sentry_tracer_test.dart @@ -453,21 +453,6 @@ void main() { expect(sut.measurements.isEmpty, true); }); - test('localMetricsAggregator is set when option is enabled', () async { - fixture.hub.options.enableMetrics = true; - fixture.hub.options.enableSpanLocalMetricAggregation = true; - final sut = fixture.getSut(); - expect(fixture.hub.options.enableSpanLocalMetricAggregation, true); - expect(sut.localMetricsAggregator, isNotNull); - }); - - test('localMetricsAggregator is null when option is disabled', () async { - fixture.hub.options.enableMetrics = false; - final sut = fixture.getSut(); - expect(fixture.hub.options.enableSpanLocalMetricAggregation, false); - expect(sut.localMetricsAggregator, null); - }); - test('setMeasurement sets a measurement', () async { final sut = fixture.getSut(); sut.setMeasurement("test", 1); diff --git a/dart/test/sentry_transaction_test.dart b/dart/test/sentry_transaction_test.dart index 4448506c3f..14245aed5a 100644 --- a/dart/test/sentry_transaction_test.dart +++ b/dart/test/sentry_transaction_test.dart @@ -2,7 +2,6 @@ import 'package:sentry/sentry.dart'; import 'package:sentry/src/sentry_tracer.dart'; import 'package:test/test.dart'; -import 'mocks.dart'; import 'mocks/mock_hub.dart'; import 'test_utils.dart'; @@ -23,11 +22,7 @@ void main() { } test('toJson serializes', () async { - fixture.options.enableSpanLocalMetricAggregation = true; - fixture.options.enableMetrics = true; - final tracer = _createTracer(hub: fixture.hub); - tracer.localMetricsAggregator?.add(fakeMetric, 0); final child = tracer.startChild('child'); await child.finish(); @@ -40,7 +35,6 @@ void main() { expect(map['start_timestamp'], isNotNull); expect(map['spans'], isNotNull); expect(map['transaction_info']['source'], 'component'); - expect(map['_metrics_summary'], isNotNull); }); test('returns finished if it is', () async { @@ -98,37 +92,6 @@ void main() { expect(sut.sampled, false); }); - - test('add a metric to localAggregator adds it to metricSummary', () async { - fixture.options.enableSpanLocalMetricAggregation = true; - fixture.options.enableMetrics = true; - - final tracer = _createTracer(hub: fixture.hub) - ..localMetricsAggregator?.add(fakeMetric, 0); - await tracer.finish(); - - final sut = fixture.getSut(tracer); - expect(sut.metricSummaries, isNotEmpty); - }); - - test('add metric after creation does not add it to metricSummary', () async { - fixture.options.enableSpanLocalMetricAggregation = true; - fixture.options.enableMetrics = true; - - final tracer = _createTracer(hub: fixture.hub); - await tracer.finish(); - final sut = fixture.getSut(tracer); - tracer.localMetricsAggregator?.add(fakeMetric, 0); - - expect(sut.metricSummaries, isEmpty); - }); - - test('metricSummary is null by default', () async { - final tracer = _createTracer(); - await tracer.finish(); - final sut = fixture.getSut(tracer); - expect(sut.metricSummaries, null); - }); } class Fixture { diff --git a/flutter/example/lib/main.dart b/flutter/example/lib/main.dart index edcd383ebd..d67aec2adc 100644 --- a/flutter/example/lib/main.dart +++ b/flutter/example/lib/main.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:math'; import 'package:dio/dio.dart'; import 'package:feedback/feedback.dart' as feedback; @@ -82,7 +81,6 @@ Future setupSentry( options.debug = kDebugMode; options.spotlight = Spotlight(enabled: true); options.enableTimeToFullDisplayTracing = true; - options.enableMetrics = true; options.enableSentryJs = true; options.maxRequestBodySize = MaxRequestBodySize.always; @@ -531,41 +529,6 @@ class MainScaffold extends StatelessWidget { 'Demonstrates the logging integration. log.info() will create an info event send it to Sentry.', buttonTitle: 'Logging', ), - TooltipButton( - onPressed: () async { - final span = Sentry.getSpan() ?? - Sentry.startTransaction( - 'testMetrics', 'span summary example', - bindToScope: true); - // ignore: deprecated_member_use - Sentry.metrics().increment('increment key', - unit: DurationSentryMeasurementUnit.day); - // ignore: deprecated_member_use - Sentry.metrics().distribution('distribution key', - value: Random().nextDouble() * 10); - // ignore: deprecated_member_use - Sentry.metrics().set('set int key', - value: Random().nextInt(100), - tags: {'myTag': 'myValue', 'myTag2': 'myValue2'}); - // ignore: deprecated_member_use - Sentry.metrics().set('set string key', - stringValue: 'Random n ${Random().nextInt(100)}'); - // ignore: deprecated_member_use - Sentry.metrics() - .gauge('gauge key', value: Random().nextDouble() * 10); - // ignore: deprecated_member_use - Sentry.metrics().timing( - 'timing key', - function: () async => await Future.delayed( - Duration(milliseconds: Random().nextInt(100)), - () => span.finish()), - unit: DurationSentryMeasurementUnit.milliSecond, - ); - }, - text: - 'Demonstrates the metrics. It creates several metrics and send them to Sentry.', - buttonTitle: 'Metrics', - ), if (UniversalPlatform.isIOS || UniversalPlatform.isMacOS) const CocoaExample(), if (UniversalPlatform.isAndroid) const AndroidExample(), diff --git a/flutter/test/mocks.mocks.dart b/flutter/test/mocks.mocks.dart index 58db67e65b..9d0e625e79 100644 --- a/flutter/test/mocks.mocks.dart +++ b/flutter/test/mocks.mocks.dart @@ -4,33 +4,31 @@ // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i11; -import 'dart:developer' as _i24; -import 'dart:typed_data' as _i19; +import 'dart:developer' as _i22; +import 'dart:typed_data' as _i17; import 'dart:ui' as _i6; import 'package:flutter/foundation.dart' as _i8; import 'package:flutter/gestures.dart' as _i7; import 'package:flutter/rendering.dart' as _i10; -import 'package:flutter/scheduler.dart' as _i23; +import 'package:flutter/scheduler.dart' as _i21; import 'package:flutter/services.dart' as _i4; import 'package:flutter/src/widgets/binding.dart' as _i5; import 'package:flutter/widgets.dart' as _i9; import 'package:flutter_test/flutter_test.dart' as _i12; import 'package:mockito/mockito.dart' as _i1; -import 'package:mockito/src/dummies.dart' as _i15; -import 'package:sentry/src/metrics/metric.dart' as _i17; -import 'package:sentry/src/metrics/metrics_api.dart' as _i13; -import 'package:sentry/src/profiling.dart' as _i16; +import 'package:mockito/src/dummies.dart' as _i14; +import 'package:sentry/src/profiling.dart' as _i15; import 'package:sentry/src/sentry_tracer.dart' as _i3; import 'package:sentry_flutter/sentry_flutter.dart' as _i2; import 'package:sentry_flutter/src/frames_tracking/sentry_delayed_frames_tracker.dart' - as _i22; -import 'package:sentry_flutter/src/native/native_frames.dart' as _i20; -import 'package:sentry_flutter/src/native/sentry_native_binding.dart' as _i18; -import 'package:sentry_flutter/src/replay/replay_config.dart' as _i21; -import 'package:sentry_flutter/src/web/sentry_js_binding.dart' as _i25; + as _i20; +import 'package:sentry_flutter/src/native/native_frames.dart' as _i18; +import 'package:sentry_flutter/src/native/sentry_native_binding.dart' as _i16; +import 'package:sentry_flutter/src/replay/replay_config.dart' as _i19; +import 'package:sentry_flutter/src/web/sentry_js_binding.dart' as _i23; -import 'mocks.dart' as _i14; +import 'mocks.dart' as _i13; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -492,8 +490,8 @@ class _FakeSentryOptions_40 extends _i1.SmartFake implements _i2.SentryOptions { ); } -class _FakeMetricsApi_41 extends _i1.SmartFake implements _i13.MetricsApi { - _FakeMetricsApi_41( +class _FakeScope_41 extends _i1.SmartFake implements _i2.Scope { + _FakeScope_41( Object parent, Invocation parentInvocation, ) : super( @@ -502,18 +500,8 @@ class _FakeMetricsApi_41 extends _i1.SmartFake implements _i13.MetricsApi { ); } -class _FakeScope_42 extends _i1.SmartFake implements _i2.Scope { - _FakeScope_42( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeHub_43 extends _i1.SmartFake implements _i2.Hub { - _FakeHub_43( +class _FakeHub_42 extends _i1.SmartFake implements _i2.Hub { + _FakeHub_42( Object parent, Invocation parentInvocation, ) : super( @@ -525,7 +513,7 @@ class _FakeHub_43 extends _i1.SmartFake implements _i2.Hub { /// A class which mocks [Callbacks]. /// /// See the documentation for Mockito's code generation for more information. -class MockCallbacks extends _i1.Mock implements _i14.Callbacks { +class MockCallbacks extends _i1.Mock implements _i13.Callbacks { MockCallbacks() { _i1.throwOnMissingStub(this); } @@ -574,7 +562,7 @@ class MockSentryTracer extends _i1.Mock implements _i3.SentryTracer { @override String get name => (super.noSuchMethod( Invocation.getter(#name), - returnValue: _i15.dummyValue( + returnValue: _i14.dummyValue( this, Invocation.getter(#name), ), @@ -608,7 +596,7 @@ class MockSentryTracer extends _i1.Mock implements _i3.SentryTracer { ); @override - set profiler(_i16.SentryProfiler? _profiler) => super.noSuchMethod( + set profiler(_i15.SentryProfiler? _profiler) => super.noSuchMethod( Invocation.setter( #profiler, _profiler, @@ -617,7 +605,7 @@ class MockSentryTracer extends _i1.Mock implements _i3.SentryTracer { ); @override - set profileInfo(_i16.SentryProfileInfo? _profileInfo) => super.noSuchMethod( + set profileInfo(_i15.SentryProfileInfo? _profileInfo) => super.noSuchMethod( Invocation.setter( #profileInfo, _profileInfo, @@ -959,16 +947,6 @@ class MockSentryTransaction extends _i1.Mock implements _i2.SentryTransaction { returnValueForMissingStub: null, ); - @override - set metricSummaries(Map>? _metricSummaries) => - super.noSuchMethod( - Invocation.setter( - #metricSummaries, - _metricSummaries, - ), - returnValueForMissingStub: null, - ); - @override set transactionInfo(_i2.SentryTransactionInfo? _transactionInfo) => super.noSuchMethod( @@ -1047,7 +1025,6 @@ class MockSentryTransaction extends _i1.Mock implements _i2.SentryTransaction { List<_i2.SentryThread>? threads, String? type, Map? measurements, - Map>? metricSummaries, _i2.SentryTransactionInfo? transactionInfo, }) => (super.noSuchMethod( @@ -1082,7 +1059,6 @@ class MockSentryTransaction extends _i1.Mock implements _i2.SentryTransaction { #threads: threads, #type: type, #measurements: measurements, - #metricSummaries: metricSummaries, #transactionInfo: transactionInfo, }, ), @@ -1119,7 +1095,6 @@ class MockSentryTransaction extends _i1.Mock implements _i2.SentryTransaction { #threads: threads, #type: type, #measurements: measurements, - #metricSummaries: metricSummaries, #transactionInfo: transactionInfo, }, ), @@ -1545,23 +1520,6 @@ class MockSentryClient extends _i1.Mock implements _i2.SentryClient { )), ) as _i11.Future<_i2.SentryId>); - @override - _i11.Future<_i2.SentryId> captureMetrics( - Map>? metricsBuckets) => - (super.noSuchMethod( - Invocation.method( - #captureMetrics, - [metricsBuckets], - ), - returnValue: _i11.Future<_i2.SentryId>.value(_FakeSentryId_5( - this, - Invocation.method( - #captureMetrics, - [metricsBuckets], - ), - )), - ) as _i11.Future<_i2.SentryId>); - @override void close() => super.noSuchMethod( Invocation.method( @@ -1583,7 +1541,7 @@ class MockMethodChannel extends _i1.Mock implements _i4.MethodChannel { @override String get name => (super.noSuchMethod( Invocation.getter(#name), - returnValue: _i15.dummyValue( + returnValue: _i14.dummyValue( this, Invocation.getter(#name), ), @@ -1671,7 +1629,7 @@ class MockMethodChannel extends _i1.Mock implements _i4.MethodChannel { /// /// See the documentation for Mockito's code generation for more information. class MockSentryNativeBinding extends _i1.Mock - implements _i18.SentryNativeBinding { + implements _i16.SentryNativeBinding { MockSentryNativeBinding() { _i1.throwOnMissingStub(this); } @@ -1703,7 +1661,7 @@ class MockSentryNativeBinding extends _i1.Mock @override _i11.FutureOr captureEnvelope( - _i19.Uint8List? envelopeData, + _i17.Uint8List? envelopeData, bool? containsUnhandledException, ) => (super.noSuchMethod(Invocation.method( @@ -1722,11 +1680,11 @@ class MockSentryNativeBinding extends _i1.Mock )) as _i11.FutureOr); @override - _i11.FutureOr<_i20.NativeFrames?> endNativeFrames(_i2.SentryId? id) => + _i11.FutureOr<_i18.NativeFrames?> endNativeFrames(_i2.SentryId? id) => (super.noSuchMethod(Invocation.method( #endNativeFrames, [id], - )) as _i11.FutureOr<_i20.NativeFrames?>); + )) as _i11.FutureOr<_i18.NativeFrames?>); @override _i11.FutureOr addBreadcrumb(_i2.Breadcrumb? breadcrumb) => @@ -1833,7 +1791,7 @@ class MockSentryNativeBinding extends _i1.Mock )) as _i11.FutureOr?>); @override - _i11.FutureOr setReplayConfig(_i21.ReplayConfig? config) => + _i11.FutureOr setReplayConfig(_i19.ReplayConfig? config) => (super.noSuchMethod(Invocation.method( #setReplayConfig, [config], @@ -1860,16 +1818,16 @@ class MockSentryNativeBinding extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockSentryDelayedFramesTracker extends _i1.Mock - implements _i22.SentryDelayedFramesTracker { + implements _i20.SentryDelayedFramesTracker { MockSentryDelayedFramesTracker() { _i1.throwOnMissingStub(this); } @override - List<_i22.SentryFrameTiming> get delayedFrames => (super.noSuchMethod( + List<_i20.SentryFrameTiming> get delayedFrames => (super.noSuchMethod( Invocation.getter(#delayedFrames), - returnValue: <_i22.SentryFrameTiming>[], - ) as List<_i22.SentryFrameTiming>); + returnValue: <_i20.SentryFrameTiming>[], + ) as List<_i20.SentryFrameTiming>); @override bool get isTrackingActive => (super.noSuchMethod( @@ -1896,7 +1854,7 @@ class MockSentryDelayedFramesTracker extends _i1.Mock ); @override - List<_i22.SentryFrameTiming> getFramesIntersecting({ + List<_i20.SentryFrameTiming> getFramesIntersecting({ required DateTime? startTimestamp, required DateTime? endTimestamp, }) => @@ -1909,8 +1867,8 @@ class MockSentryDelayedFramesTracker extends _i1.Mock #endTimestamp: endTimestamp, }, ), - returnValue: <_i22.SentryFrameTiming>[], - ) as List<_i22.SentryFrameTiming>); + returnValue: <_i20.SentryFrameTiming>[], + ) as List<_i20.SentryFrameTiming>); @override void addFrame( @@ -1939,7 +1897,7 @@ class MockSentryDelayedFramesTracker extends _i1.Mock ); @override - _i22.SpanFrameMetrics? getFrameMetrics({ + _i20.SpanFrameMetrics? getFrameMetrics({ required DateTime? spanStartTimestamp, required DateTime? spanEndTimestamp, }) => @@ -1950,7 +1908,7 @@ class MockSentryDelayedFramesTracker extends _i1.Mock #spanStartTimestamp: spanStartTimestamp, #spanEndTimestamp: spanEndTimestamp, }, - )) as _i22.SpanFrameMetrics?); + )) as _i20.SpanFrameMetrics?); @override void clear() => super.noSuchMethod( @@ -2089,17 +2047,17 @@ class MockWidgetsFlutterBinding extends _i1.Mock ) as _i7.SamplingClock); @override - _i23.SchedulingStrategy get schedulingStrategy => (super.noSuchMethod( + _i21.SchedulingStrategy get schedulingStrategy => (super.noSuchMethod( Invocation.getter(#schedulingStrategy), returnValue: ({ required int priority, - required _i23.SchedulerBinding scheduler, + required _i21.SchedulerBinding scheduler, }) => false, - ) as _i23.SchedulingStrategy); + ) as _i21.SchedulingStrategy); @override - set schedulingStrategy(_i23.SchedulingStrategy? _schedulingStrategy) => + set schedulingStrategy(_i21.SchedulingStrategy? _schedulingStrategy) => super.noSuchMethod( Invocation.setter( #schedulingStrategy, @@ -2127,10 +2085,10 @@ class MockWidgetsFlutterBinding extends _i1.Mock ) as bool); @override - _i23.SchedulerPhase get schedulerPhase => (super.noSuchMethod( + _i21.SchedulerPhase get schedulerPhase => (super.noSuchMethod( Invocation.getter(#schedulerPhase), - returnValue: _i23.SchedulerPhase.idle, - ) as _i23.SchedulerPhase); + returnValue: _i21.SchedulerPhase.idle, + ) as _i21.SchedulerPhase); @override bool get framesEnabled => (super.noSuchMethod( @@ -2703,10 +2661,10 @@ class MockWidgetsFlutterBinding extends _i1.Mock @override _i11.Future scheduleTask( - _i23.TaskCallback? task, - _i23.Priority? priority, { + _i21.TaskCallback? task, + _i21.Priority? priority, { String? debugLabel, - _i24.Flow? flow, + _i22.Flow? flow, }) => (super.noSuchMethod( Invocation.method( @@ -2720,8 +2678,8 @@ class MockWidgetsFlutterBinding extends _i1.Mock #flow: flow, }, ), - returnValue: _i15.ifNotNull( - _i15.dummyValueOrNull( + returnValue: _i14.ifNotNull( + _i14.dummyValueOrNull( this, Invocation.method( #scheduleTask, @@ -2764,7 +2722,7 @@ class MockWidgetsFlutterBinding extends _i1.Mock @override int scheduleFrameCallback( - _i23.FrameCallback? callback, { + _i21.FrameCallback? callback, { bool? rescheduling = false, }) => (super.noSuchMethod( @@ -2814,7 +2772,7 @@ class MockWidgetsFlutterBinding extends _i1.Mock ) as bool); @override - void addPersistentFrameCallback(_i23.FrameCallback? callback) => + void addPersistentFrameCallback(_i21.FrameCallback? callback) => super.noSuchMethod( Invocation.method( #addPersistentFrameCallback, @@ -2825,7 +2783,7 @@ class MockWidgetsFlutterBinding extends _i1.Mock @override void addPostFrameCallback( - _i23.FrameCallback? callback, { + _i21.FrameCallback? callback, { String? debugLabel = r'callback', }) => super.noSuchMethod( @@ -2901,12 +2859,12 @@ class MockWidgetsFlutterBinding extends _i1.Mock ); @override - _i23.PerformanceModeRequestHandle? requestPerformanceMode( + _i21.PerformanceModeRequestHandle? requestPerformanceMode( _i6.DartPerformanceMode? mode) => (super.noSuchMethod(Invocation.method( #requestPerformanceMode, [mode], - )) as _i23.PerformanceModeRequestHandle?); + )) as _i21.PerformanceModeRequestHandle?); @override void handleDrawFrame() => super.noSuchMethod( @@ -3473,7 +3431,7 @@ class MockWidgetsFlutterBinding extends _i1.Mock /// A class which mocks [SentryJsBinding]. /// /// See the documentation for Mockito's code generation for more information. -class MockSentryJsBinding extends _i1.Mock implements _i25.SentryJsBinding { +class MockSentryJsBinding extends _i1.Mock implements _i23.SentryJsBinding { MockSentryJsBinding() { _i1.throwOnMissingStub(this); } @@ -3523,15 +3481,6 @@ class MockHub extends _i1.Mock implements _i2.Hub { ), ) as _i2.SentryOptions); - @override - _i13.MetricsApi get metricsApi => (super.noSuchMethod( - Invocation.getter(#metricsApi), - returnValue: _FakeMetricsApi_41( - this, - Invocation.getter(#metricsApi), - ), - ) as _i13.MetricsApi); - @override bool get isEnabled => (super.noSuchMethod( Invocation.getter(#isEnabled), @@ -3550,14 +3499,14 @@ class MockHub extends _i1.Mock implements _i2.Hub { @override _i2.Scope get scope => (super.noSuchMethod( Invocation.getter(#scope), - returnValue: _FakeScope_42( + returnValue: _FakeScope_41( this, Invocation.getter(#scope), ), ) as _i2.Scope); @override - set profilerFactory(_i16.SentryProfilerFactory? value) => super.noSuchMethod( + set profilerFactory(_i15.SentryProfilerFactory? value) => super.noSuchMethod( Invocation.setter( #profilerFactory, value, @@ -3733,7 +3682,7 @@ class MockHub extends _i1.Mock implements _i2.Hub { #clone, [], ), - returnValue: _FakeHub_43( + returnValue: _FakeHub_42( this, Invocation.method( #clone, @@ -3790,7 +3739,7 @@ class MockHub extends _i1.Mock implements _i2.Hub { #customSamplingContext: customSamplingContext, }, ), - returnValue: _i14.startTransactionShim( + returnValue: _i13.startTransactionShim( name, operation, description: description, @@ -3868,23 +3817,6 @@ class MockHub extends _i1.Mock implements _i2.Hub { )), ) as _i11.Future<_i2.SentryId>); - @override - _i11.Future<_i2.SentryId> captureMetrics( - Map>? metricsBuckets) => - (super.noSuchMethod( - Invocation.method( - #captureMetrics, - [metricsBuckets], - ), - returnValue: _i11.Future<_i2.SentryId>.value(_FakeSentryId_5( - this, - Invocation.method( - #captureMetrics, - [metricsBuckets], - ), - )), - ) as _i11.Future<_i2.SentryId>); - @override void setSpanContext( dynamic throwable,