Skip to content

Commit

Permalink
Merge branch 'main' into feat/add-ignore-routes
Browse files Browse the repository at this point in the history
* main:
  Add proxy support (#2192)
  Deserialize and serialize unknown fields (#2153)
  feat: add `ignoreTransactions` and ignoreErrors` #1391 (#2207)
  feat: add span level measurements #1855 (#2214)
  • Loading branch information
martinhaintz committed Aug 7, 2024
2 parents 668caaa + 33527b4 commit 15cf647
Show file tree
Hide file tree
Showing 77 changed files with 1,805 additions and 274 deletions.
40 changes: 39 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,44 @@
```dart
SentryNavigatorObserver(ignoreRoutes: ["/ignoreThisRoute"]),
```
- Add support for span level measurements. ([#2214](https://github.com/getsentry/sentry-dart/pull/2214))
- Add `ignoreTransactions` and `ignoreErrors` to options ([#2207](https://github.com/getsentry/sentry-dart/pull/2207))
```dart
await SentryFlutter.init(
(options) {
options.dsn = 'https://examplePublicKey@o0.ingest.sentry.io/0';
options.ignoreErrors = ["my-error", "^error-.*\$"];
options.ignoreTransactions = ["my-transaction", "^transaction-.*\$"];
...
},
appRunner: () => runApp(MyApp()),
);
```
- Add proxy support ([#2192](https://github.com/getsentry/sentry-dart/pull/2192))
- Configure a `SentryProxy` object and set it on `SentryFlutter.init`
```dart
import 'package:flutter/widgets.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
Future<void> main() async {
await SentryFlutter.init(
(options) {
options.dsn = 'https://example@sentry.io/add-your-dsn-here';
options.proxy = SentryProxy(
type: SenryProxyType.http,
host: 'localhost',
port: 8080,
);
},
// Init your App.
appRunner: () => runApp(MyApp()),
);
}
```

### Improvements

- Deserialize and serialize unknown fields ([#2153](https://github.com/getsentry/sentry-dart/pull/2153))

## 8.6.0

Expand Down Expand Up @@ -60,7 +98,7 @@ SentryFlutter.init((options) =>
- This allows viewing the correct dart formatted raw stacktrace in the Sentry UI
- Support `ignoredExceptionsForType` ([#2150](https://github.com/getsentry/sentry-dart/pull/2150))
- Filter out exception types by calling `SentryOptions.addExceptionFilterForType(Type exceptionType)`

### Fixes

- Disable sff & frame delay detection on web, linux and windows ([#2182](https://github.com/getsentry/sentry-dart/pull/2182))
Expand Down
2 changes: 2 additions & 0 deletions dart/lib/sentry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,5 @@ export 'src/sentry_span_operations.dart';
export 'src/utils.dart';
// spotlight debugging
export 'src/spotlight.dart';
// proxy
export 'src/protocol/sentry_proxy.dart';
16 changes: 16 additions & 0 deletions dart/lib/src/http_client/client_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:meta/meta.dart';
import 'package:http/http.dart';

import '../sentry_options.dart';

@internal
ClientProvider getClientProvider() {
return ClientProvider();
}

@internal
class ClientProvider {
Client getClient(SentryOptions options) {
return Client();
}
}
67 changes: 67 additions & 0 deletions dart/lib/src/http_client/io_client_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import 'dart:io';

import 'package:http/http.dart';
import 'package:http/io_client.dart';
import 'package:meta/meta.dart';

import '../protocol.dart';
import '../protocol/sentry_proxy.dart';
import '../sentry_options.dart';
import 'client_provider.dart';

@internal
ClientProvider getClientProvider() {
return IoClientProvider(
() {
return HttpClient();
},
(user, pass) {
return HttpClientBasicCredentials(user, pass);
},
);
}

@internal
class IoClientProvider implements ClientProvider {
final HttpClient Function() _httpClient;
final HttpClientCredentials Function(String, String) _httpClientCredentials;

IoClientProvider(this._httpClient, this._httpClientCredentials);

@override
Client getClient(SentryOptions options) {
final proxy = options.proxy;
if (proxy == null) {
return Client();
}
final pac = proxy.toPacString();
if (proxy.type == SentryProxyType.socks) {
options.logger(
SentryLevel.warning,
"Setting proxy '$pac' is not supported.",
);
return Client();
}
options.logger(
SentryLevel.info,
"Setting proxy '$pac'",
);
final httpClient = _httpClient();
httpClient.findProxy = (url) => pac;

final host = proxy.host;
final port = proxy.port;
final user = proxy.user;
final pass = proxy.pass;

if (host != null && port != null && user != null && pass != null) {
httpClient.addProxyCredentials(
host,
port,
'',
_httpClientCredentials(user, pass),
);
}
return IOClient(httpClient);
}
}
53 changes: 53 additions & 0 deletions dart/lib/src/protocol/access_aware_map.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import 'dart:collection';

import 'package:meta/meta.dart';

@internal
class AccessAwareMap<String, V> extends MapBase<String, V> {
AccessAwareMap(this._map);

final Map<String, V> _map;
final Set<String> _accessedKeysWithValues = {};

Set<String> get accessedKeysWithValues => _accessedKeysWithValues;

@override
V? operator [](Object? key) {
if (key is String && _map.containsKey(key)) {
_accessedKeysWithValues.add(key);
}
return _map[key];
}

@override
void operator []=(String key, V value) {
_map[key] = value;
}

@override
void clear() {
_map.clear();
_accessedKeysWithValues.clear();
}

@override
Iterable<String> get keys => _map.keys;

@override
V? remove(Object? key) {
return _map.remove(key);
}

Map<String, dynamic>? notAccessed() {
if (_accessedKeysWithValues.length == _map.length) {
return null;
}
Map<String, dynamic> unknown = _map.keys
.where((key) => !_accessedKeysWithValues.contains(key))
.fold<Map<String, dynamic>>({}, (map, key) {
map[key] = _map[key];
return map;
});
return unknown.isNotEmpty ? unknown : null;
}
}
13 changes: 11 additions & 2 deletions dart/lib/src/protocol/breadcrumb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:meta/meta.dart';

import '../utils.dart';
import '../protocol.dart';
import 'access_aware_map.dart';

/// Structured data to describe more information prior to the event captured.
/// See `Sentry.captureEvent()`.
Expand Down Expand Up @@ -30,6 +31,7 @@ class Breadcrumb {
this.data,
SentryLevel? level,
this.type,
this.unknown,
}) : timestamp = timestamp ?? getUtcDateTime(),
level = level ?? SentryLevel.info;

Expand Down Expand Up @@ -156,30 +158,36 @@ class Breadcrumb {
/// The value is submitted to Sentry with second precision.
final DateTime timestamp;

@internal
final Map<String, dynamic>? unknown;

/// Deserializes a [Breadcrumb] from JSON [Map].
factory Breadcrumb.fromJson(Map<String, dynamic> json) {
factory Breadcrumb.fromJson(Map<String, dynamic> jsonData) {
final json = AccessAwareMap(jsonData);

final levelName = json['level'];
final timestamp = json['timestamp'];

var data = json['data'];
if (data != null) {
data = Map<String, dynamic>.from(data as Map);
}

return Breadcrumb(
timestamp: timestamp != null ? DateTime.tryParse(timestamp) : null,
message: json['message'],
category: json['category'],
data: data,
level: levelName != null ? SentryLevel.fromName(levelName) : null,
type: json['type'],
unknown: json.notAccessed(),
);
}

/// Converts this breadcrumb to a map that can be serialized to JSON according
/// to the Sentry protocol.
Map<String, dynamic> toJson() {
return {
...?unknown,
'timestamp': formatDateAsIso8601WithMillisPrecision(timestamp),
if (message != null) 'message': message,
if (category != null) 'category': category,
Expand All @@ -204,5 +212,6 @@ class Breadcrumb {
level: level ?? this.level,
type: type ?? this.type,
timestamp: timestamp ?? this.timestamp,
unknown: unknown,
);
}
12 changes: 11 additions & 1 deletion dart/lib/src/protocol/debug_image.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:meta/meta.dart';

import 'access_aware_map.dart';

/// The list of debug images contains all dynamic libraries loaded into
/// the process and their memory addresses.
/// Instruction addresses in the Stack Trace are mapped into the list of debug
Expand Down Expand Up @@ -51,6 +53,9 @@ class DebugImage {
/// MachO CPU type identifier.
final int? cpuType;

@internal
final Map<String, dynamic>? unknown;

const DebugImage({
required this.type,
this.name,
Expand All @@ -65,10 +70,12 @@ class DebugImage {
this.codeId,
this.cpuType,
this.cpuSubtype,
this.unknown,
});

/// Deserializes a [DebugImage] from JSON [Map].
factory DebugImage.fromJson(Map<String, dynamic> json) {
factory DebugImage.fromJson(Map<String, dynamic> data) {
final json = AccessAwareMap(data);
return DebugImage(
type: json['type'],
name: json['name'],
Expand All @@ -83,12 +90,14 @@ class DebugImage {
codeId: json['code_id'],
cpuType: json['cpu_type'],
cpuSubtype: json['cpu_subtype'],
unknown: json.notAccessed(),
);
}

/// Produces a [Map] that can be serialized to JSON.
Map<String, dynamic> toJson() {
return {
...?unknown,
'type': type,
if (uuid != null) 'uuid': uuid,
if (debugId != null) 'debug_id': debugId,
Expand Down Expand Up @@ -134,5 +143,6 @@ class DebugImage {
codeId: codeId ?? this.codeId,
cpuType: cpuType ?? this.cpuType,
cpuSubtype: cpuSubtype ?? this.cpuSubtype,
unknown: unknown,
);
}
15 changes: 12 additions & 3 deletions dart/lib/src/protocol/debug_meta.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:meta/meta.dart';

import '../protocol.dart';
import 'access_aware_map.dart';

/// The debug meta interface carries debug information for processing errors and crash reports.
@immutable
Expand All @@ -16,10 +17,15 @@ class DebugMeta {
/// images in order to retrieve debug files for symbolication.
List<DebugImage> get images => List.unmodifiable(_images ?? const []);

DebugMeta({this.sdk, List<DebugImage>? images}) : _images = images;
DebugMeta({this.sdk, List<DebugImage>? images, this.unknown})
: _images = images;

@internal
final Map<String, dynamic>? unknown;

/// Deserializes a [DebugMeta] from JSON [Map].
factory DebugMeta.fromJson(Map<String, dynamic> json) {
factory DebugMeta.fromJson(Map<String, dynamic> data) {
final json = AccessAwareMap(data);
final sdkInfoJson = json['sdk_info'];
final debugImagesJson = json['images'] as List<dynamic>?;
return DebugMeta(
Expand All @@ -28,19 +34,21 @@ class DebugMeta {
?.map((debugImageJson) =>
DebugImage.fromJson(debugImageJson as Map<String, dynamic>))
.toList(),
unknown: json.notAccessed(),
);
}

/// Produces a [Map] that can be serialized to JSON.
Map<String, dynamic> toJson() {
final sdkInfo = sdk?.toJson();
return {
...?unknown,
if (sdkInfo?.isNotEmpty ?? false) 'sdk_info': sdkInfo,
if (_images?.isNotEmpty ?? false)
'images': _images!
.map((e) => e.toJson())
.where((element) => element.isNotEmpty)
.toList(growable: false)
.toList(growable: false),
};
}

Expand All @@ -51,5 +59,6 @@ class DebugMeta {
DebugMeta(
sdk: sdk ?? this.sdk,
images: images ?? _images,
unknown: unknown,
);
}
Loading

0 comments on commit 15cf647

Please sign in to comment.