From 55fa42adf7be4c447df39dc9759896dd20c3b133 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 13:23:31 +0200 Subject: [PATCH 01/43] Add `unknown` map to `Breadcrumb` --- dart/lib/src/protocol/breadcrumb.dart | 26 ++++++++++++++++++++++++- dart/test/protocol/breadcrumb_test.dart | 21 +++++++++++++------- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/dart/lib/src/protocol/breadcrumb.dart b/dart/lib/src/protocol/breadcrumb.dart index f7eea55358..6f10163886 100644 --- a/dart/lib/src/protocol/breadcrumb.dart +++ b/dart/lib/src/protocol/breadcrumb.dart @@ -30,6 +30,7 @@ class Breadcrumb { this.data, SentryLevel? level, this.type, + this.unknown, }) : timestamp = timestamp ?? getUtcDateTime(), level = level ?? SentryLevel.info; @@ -156,8 +157,20 @@ class Breadcrumb { /// The value is submitted to Sentry with second precision. final DateTime timestamp; + @internal + final Map? unknown; + /// Deserializes a [Breadcrumb] from JSON [Map]. factory Breadcrumb.fromJson(Map json) { + final knownKeys = { + 'level', + 'timestamp', + 'data', + 'message', + 'category', + 'type', + }; + final levelName = json['level']; final timestamp = json['timestamp']; @@ -166,6 +179,13 @@ class Breadcrumb { data = Map.from(data as Map); } + final unknown = json.keys + .where((key) => !knownKeys.contains(key)) + .fold>({}, (map, key) { + map[key] = json[key]; + return map; + }); + return Breadcrumb( timestamp: timestamp != null ? DateTime.tryParse(timestamp) : null, message: json['message'], @@ -173,13 +193,14 @@ class Breadcrumb { data: data, level: levelName != null ? SentryLevel.fromName(levelName) : null, type: json['type'], + unknown: unknown.isNotEmpty ? unknown : null, ); } /// Converts this breadcrumb to a map that can be serialized to JSON according /// to the Sentry protocol. Map toJson() { - return { + final json = { 'timestamp': formatDateAsIso8601WithMillisPrecision(timestamp), if (message != null) 'message': message, if (category != null) 'category': category, @@ -187,6 +208,8 @@ class Breadcrumb { if (level != null) 'level': level!.name, if (type != null) 'type': type, }; + json.addAll(unknown ?? {}); + return json; } Breadcrumb copyWith({ @@ -204,5 +227,6 @@ class Breadcrumb { level: level ?? this.level, type: type ?? this.type, timestamp: timestamp ?? this.timestamp, + unknown: unknown, ); } diff --git a/dart/test/protocol/breadcrumb_test.dart b/dart/test/protocol/breadcrumb_test.dart index ddd4008d98..422c71d1e9 100644 --- a/dart/test/protocol/breadcrumb_test.dart +++ b/dart/test/protocol/breadcrumb_test.dart @@ -5,14 +5,20 @@ import 'package:test/test.dart'; void main() { final timestamp = DateTime.now(); + final Map unknown = { + 'unknown-string': 'foo', + 'unknown-bool': true, + 'unknown-num': 9001, + }; + final breadcrumb = Breadcrumb( - message: 'message', - timestamp: timestamp, - data: {'key': 'value'}, - level: SentryLevel.warning, - category: 'category', - type: 'type', - ); + message: 'message', + timestamp: timestamp, + data: {'key': 'value'}, + level: SentryLevel.warning, + category: 'category', + type: 'type', + unknown: unknown); final breadcrumbJson = { 'timestamp': formatDateAsIso8601WithMillisPrecision(timestamp), @@ -22,6 +28,7 @@ void main() { 'level': 'warning', 'type': 'type', }; + breadcrumbJson.addAll(unknown); group('json', () { test('toJson', () { From e2277628f017ccf94c5a59092d1cdfb9c7be37ec Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 13:36:35 +0200 Subject: [PATCH 02/43] move unknown reading to helper function --- dart/lib/src/protocol/breadcrumb.dart | 27 +++++++++------------------ dart/lib/src/protocol/unknown.dart | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 18 deletions(-) create mode 100644 dart/lib/src/protocol/unknown.dart diff --git a/dart/lib/src/protocol/breadcrumb.dart b/dart/lib/src/protocol/breadcrumb.dart index 6f10163886..dd6868fd85 100644 --- a/dart/lib/src/protocol/breadcrumb.dart +++ b/dart/lib/src/protocol/breadcrumb.dart @@ -2,6 +2,7 @@ import 'package:meta/meta.dart'; import '../utils.dart'; import '../protocol.dart'; +import 'unknown.dart'; /// Structured data to describe more information prior to the event captured. /// See `Sentry.captureEvent()`. @@ -162,15 +163,6 @@ class Breadcrumb { /// Deserializes a [Breadcrumb] from JSON [Map]. factory Breadcrumb.fromJson(Map json) { - final knownKeys = { - 'level', - 'timestamp', - 'data', - 'message', - 'category', - 'type', - }; - final levelName = json['level']; final timestamp = json['timestamp']; @@ -178,14 +170,6 @@ class Breadcrumb { if (data != null) { data = Map.from(data as Map); } - - final unknown = json.keys - .where((key) => !knownKeys.contains(key)) - .fold>({}, (map, key) { - map[key] = json[key]; - return map; - }); - return Breadcrumb( timestamp: timestamp != null ? DateTime.tryParse(timestamp) : null, message: json['message'], @@ -193,7 +177,14 @@ class Breadcrumb { data: data, level: levelName != null ? SentryLevel.fromName(levelName) : null, type: json['type'], - unknown: unknown.isNotEmpty ? unknown : null, + unknown: unknownFrom(json, { + 'level', + 'timestamp', + 'data', + 'message', + 'category', + 'type', + }), ); } diff --git a/dart/lib/src/protocol/unknown.dart b/dart/lib/src/protocol/unknown.dart new file mode 100644 index 0000000000..1900e58d94 --- /dev/null +++ b/dart/lib/src/protocol/unknown.dart @@ -0,0 +1,15 @@ +import 'package:meta/meta.dart'; + +@internal +Map? unknownFrom( + Map json, + Set knownKeys, +) { + Map unknown = json.keys + .where((key) => !knownKeys.contains(key)) + .fold>({}, (map, key) { + map[key] = json[key]; + return map; + }); + return unknown.isNotEmpty ? unknown : null; +} From bb7feb638f7d3e8ccc3c8d8303a16046cb8c54a7 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 13:39:44 +0200 Subject: [PATCH 03/43] Move unknown test data to mocks.dart --- dart/test/mocks.dart | 6 ++++++ dart/test/protocol/breadcrumb_test.dart | 25 +++++++++++-------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/dart/test/mocks.dart b/dart/test/mocks.dart index 7c960c8a07..3df2dce865 100644 --- a/dart/test/mocks.dart +++ b/dart/test/mocks.dart @@ -184,6 +184,12 @@ class MockRateLimiter implements RateLimiter { } } +final Map testUnknown = { + 'unknown-string': 'foo', + 'unknown-bool': true, + 'unknown-num': 9001, +}; + @GenerateMocks([ SentryProfilerFactory, SentryProfiler, diff --git a/dart/test/protocol/breadcrumb_test.dart b/dart/test/protocol/breadcrumb_test.dart index 422c71d1e9..ddda79df6e 100644 --- a/dart/test/protocol/breadcrumb_test.dart +++ b/dart/test/protocol/breadcrumb_test.dart @@ -2,23 +2,20 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final timestamp = DateTime.now(); - final Map unknown = { - 'unknown-string': 'foo', - 'unknown-bool': true, - 'unknown-num': 9001, - }; - final breadcrumb = Breadcrumb( - message: 'message', - timestamp: timestamp, - data: {'key': 'value'}, - level: SentryLevel.warning, - category: 'category', - type: 'type', - unknown: unknown); + message: 'message', + timestamp: timestamp, + data: {'key': 'value'}, + level: SentryLevel.warning, + category: 'category', + type: 'type', + unknown: testUnknown, + ); final breadcrumbJson = { 'timestamp': formatDateAsIso8601WithMillisPrecision(timestamp), @@ -28,7 +25,7 @@ void main() { 'level': 'warning', 'type': 'type', }; - breadcrumbJson.addAll(unknown); + breadcrumbJson.addAll(testUnknown); group('json', () { test('toJson', () { From 35bff66639dc712b21670eb91ebe5c0904e90d5c Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 13:53:59 +0200 Subject: [PATCH 04/43] Add `unknown` map to `DebugImage` --- dart/lib/src/protocol/debug_image.dart | 26 +++++++++++++++++++++++- dart/test/protocol/debug_image_test.dart | 4 ++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/protocol/debug_image.dart b/dart/lib/src/protocol/debug_image.dart index df45a12fed..64862ea157 100644 --- a/dart/lib/src/protocol/debug_image.dart +++ b/dart/lib/src/protocol/debug_image.dart @@ -1,5 +1,7 @@ import 'package:meta/meta.dart'; +import 'unknown.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 @@ -51,6 +53,9 @@ class DebugImage { /// MachO CPU type identifier. final int? cpuType; + @internal + final Map? unknown; + const DebugImage({ required this.type, this.name, @@ -65,6 +70,7 @@ class DebugImage { this.codeId, this.cpuType, this.cpuSubtype, + this.unknown, }); /// Deserializes a [DebugImage] from JSON [Map]. @@ -83,12 +89,27 @@ class DebugImage { codeId: json['code_id'], cpuType: json['cpu_type'], cpuSubtype: json['cpu_subtype'], + unknown: unknownFrom(json, { + 'type', + 'name', + 'image_addr', + 'image_vmaddr', + 'debug_id', + 'debug_file', + 'image_size', + 'uuid', + 'code_file', + 'arch', + 'code_id', + 'cpu_type', + 'cpu_subtype', + }), ); } /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { 'type': type, if (uuid != null) 'uuid': uuid, if (debugId != null) 'debug_id': debugId, @@ -103,6 +124,8 @@ class DebugImage { if (cpuType != null) 'cpu_type': cpuType, if (cpuSubtype != null) 'cpu_subtype': cpuSubtype, }; + json.addAll(unknown ?? {}); + return json; } DebugImage copyWith({ @@ -134,5 +157,6 @@ class DebugImage { codeId: codeId ?? this.codeId, cpuType: cpuType ?? this.cpuType, cpuSubtype: cpuSubtype ?? this.cpuSubtype, + unknown: unknown, ); } diff --git a/dart/test/protocol/debug_image_test.dart b/dart/test/protocol/debug_image_test.dart index d06dad4b5e..5f3de134e1 100644 --- a/dart/test/protocol/debug_image_test.dart +++ b/dart/test/protocol/debug_image_test.dart @@ -2,6 +2,8 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final debugImage = DebugImage( type: 'type', @@ -13,6 +15,7 @@ void main() { codeFile: 'codeFile', arch: 'arch', codeId: 'codeId', + unknown: testUnknown, ); final debugImageJson = { @@ -26,6 +29,7 @@ void main() { 'arch': 'arch', 'code_id': 'codeId', }; + debugImageJson.addAll(testUnknown); group('json', () { test('toJson', () { From 6b6ebf7cb503bf891963a8f7481ee0bc55b91348 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 14:21:56 +0200 Subject: [PATCH 05/43] Add `unknown` map to `DebugMeta` --- dart/lib/src/protocol/debug_meta.dart | 13 +++++++++++-- dart/test/protocol/debug_meta_test.dart | 4 ++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/dart/lib/src/protocol/debug_meta.dart b/dart/lib/src/protocol/debug_meta.dart index 205b2cc13e..908be86c48 100644 --- a/dart/lib/src/protocol/debug_meta.dart +++ b/dart/lib/src/protocol/debug_meta.dart @@ -1,6 +1,7 @@ import 'package:meta/meta.dart'; import '../protocol.dart'; +import 'unknown.dart'; /// The debug meta interface carries debug information for processing errors and crash reports. @immutable @@ -16,7 +17,11 @@ class DebugMeta { /// images in order to retrieve debug files for symbolication. List get images => List.unmodifiable(_images ?? const []); - DebugMeta({this.sdk, List? images}) : _images = images; + DebugMeta({this.sdk, List? images, this.unknown}) + : _images = images; + + @internal + final Map? unknown; /// Deserializes a [DebugMeta] from JSON [Map]. factory DebugMeta.fromJson(Map json) { @@ -28,13 +33,14 @@ class DebugMeta { ?.map((debugImageJson) => DebugImage.fromJson(debugImageJson as Map)) .toList(), + unknown: unknownFrom(json, {'sdk_info', 'images'}), ); } /// Produces a [Map] that can be serialized to JSON. Map toJson() { final sdkInfo = sdk?.toJson(); - return { + final json = { if (sdkInfo?.isNotEmpty ?? false) 'sdk_info': sdkInfo, if (_images?.isNotEmpty ?? false) 'images': _images! @@ -42,6 +48,8 @@ class DebugMeta { .where((element) => element.isNotEmpty) .toList(growable: false) }; + json.addAll(unknown ?? {}); + return json; } DebugMeta copyWith({ @@ -51,5 +59,6 @@ class DebugMeta { DebugMeta( sdk: sdk ?? this.sdk, images: images ?? _images, + unknown: unknown, ); } diff --git a/dart/test/protocol/debug_meta_test.dart b/dart/test/protocol/debug_meta_test.dart index 21caf02747..4b5624f4a9 100644 --- a/dart/test/protocol/debug_meta_test.dart +++ b/dart/test/protocol/debug_meta_test.dart @@ -2,12 +2,15 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final debugMeta = DebugMeta( sdk: SdkInfo( sdkName: 'sdkName', ), images: [DebugImage(type: 'macho', uuid: 'uuid')], + unknown: testUnknown, ); final debugMetaJson = { @@ -16,6 +19,7 @@ void main() { {'uuid': 'uuid', 'type': 'macho'} ] }; + debugMetaJson.addAll(testUnknown); group('json', () { test('toJson', () { From c071d1095fab836f638a1a2d060a51e375d03dc0 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 14:33:02 +0200 Subject: [PATCH 06/43] Add `unknown` map to `Mechanism` --- dart/lib/src/protocol/mechanism.dart | 24 +++++++++++++++++++++++- dart/test/protocol/mechanism_test.dart | 4 ++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/protocol/mechanism.dart b/dart/lib/src/protocol/mechanism.dart index 22a6356800..5cc5018fa1 100644 --- a/dart/lib/src/protocol/mechanism.dart +++ b/dart/lib/src/protocol/mechanism.dart @@ -1,5 +1,7 @@ import 'package:meta/meta.dart'; +import 'unknown.dart'; + /// Sentry Exception Mechanism /// The exception mechanism is an optional field residing /// in the Exception Interface. It carries additional information about @@ -76,6 +78,9 @@ class Mechanism { /// (the last to be listed in the exception values). final int? parentId; + @internal + final Map? unknown; + Mechanism({ required this.type, this.description, @@ -88,6 +93,7 @@ class Mechanism { this.source, this.exceptionId, this.parentId, + this.unknown, }) : _meta = meta != null ? Map.from(meta) : null, _data = data != null ? Map.from(data) : null; @@ -116,6 +122,7 @@ class Mechanism { source: source ?? this.source, exceptionId: exceptionId ?? this.exceptionId, parentId: parentId ?? this.parentId, + unknown: unknown, ); /// Deserializes a [Mechanism] from JSON [Map]. @@ -142,12 +149,25 @@ class Mechanism { source: json['source'], exceptionId: json['exception_id'], parentId: json['parent_id'], + unknown: unknownFrom(json, { + 'data', + 'meta', + 'type', + 'description', + 'help_link', + 'handled', + 'synthetic', + 'is_exception_group', + 'source', + 'exception_id', + 'parent_id', + }), ); } /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { 'type': type, if (description != null) 'description': description, if (helpLink != null) 'help_link': helpLink, @@ -160,5 +180,7 @@ class Mechanism { if (exceptionId != null) 'exception_id': exceptionId, if (parentId != null) 'parent_id': parentId, }; + json.addAll(unknown ?? {}); + return json; } } diff --git a/dart/test/protocol/mechanism_test.dart b/dart/test/protocol/mechanism_test.dart index 857a0529a9..d9bdc3a7cf 100644 --- a/dart/test/protocol/mechanism_test.dart +++ b/dart/test/protocol/mechanism_test.dart @@ -2,6 +2,8 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final mechanism = Mechanism( type: 'type', @@ -15,6 +17,7 @@ void main() { exceptionId: 0, parentId: 0, source: 'source', + unknown: testUnknown, ); final mechanismJson = { @@ -30,6 +33,7 @@ void main() { 'exception_id': 0, 'parent_id': 0, }; + mechanismJson.addAll(testUnknown); group('json', () { test('toJson', () { From d07dbd4d8364199c57a94dd9a0098f2f048a639b Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 14:36:28 +0200 Subject: [PATCH 07/43] Add `unknown` map to `MetricSummary` --- dart/lib/src/protocol/metric_summary.dart | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/dart/lib/src/protocol/metric_summary.dart b/dart/lib/src/protocol/metric_summary.dart index b0c617fb30..9396ad1fe7 100644 --- a/dart/lib/src/protocol/metric_summary.dart +++ b/dart/lib/src/protocol/metric_summary.dart @@ -1,4 +1,7 @@ +import 'package:meta/meta.dart'; + import '../metrics/metric.dart'; +import 'unknown.dart'; class MetricSummary { final num min; @@ -7,7 +10,10 @@ class MetricSummary { final int count; final Map? tags; - MetricSummary.fromGauge(GaugeMetric gauge) + @internal + final Map? unknown; + + MetricSummary.fromGauge(GaugeMetric gauge, {this.unknown}) : min = gauge.minimum, max = gauge.maximum, sum = gauge.sum, @@ -19,7 +25,8 @@ class MetricSummary { required this.max, required this.sum, required this.count, - required this.tags}); + required this.tags, + this.unknown}); /// Deserializes a [MetricSummary] from JSON [Map]. factory MetricSummary.fromJson(Map data) => MetricSummary( @@ -28,16 +35,25 @@ class MetricSummary { count: data['count'], sum: data['sum'], tags: data['tags']?.cast(), + unknown: unknownFrom(data, { + 'min', + 'max', + 'count', + 'sum', + 'tags', + }), ); /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { 'min': min, 'max': max, 'count': count, 'sum': sum, if (tags?.isNotEmpty ?? false) 'tags': tags, }; + json.addAll(unknown ?? {}); + return json; } } From 7f87af99fa5e407afdd004ed4d42073a5d293413 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 14:39:57 +0200 Subject: [PATCH 08/43] Add `unknown` map to `SdkInfo ` --- dart/lib/src/protocol/sdk_info.dart | 17 ++++++++++++++++- dart/test/protocol/sdk_info_test.dart | 4 ++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/protocol/sdk_info.dart b/dart/lib/src/protocol/sdk_info.dart index cf0b7d0f41..dd69217bbf 100644 --- a/dart/lib/src/protocol/sdk_info.dart +++ b/dart/lib/src/protocol/sdk_info.dart @@ -1,5 +1,7 @@ import 'package:meta/meta.dart'; +import 'unknown.dart'; + /// An object describing the system SDK. @immutable class SdkInfo { @@ -8,11 +10,15 @@ class SdkInfo { final int? versionMinor; final int? versionPatchlevel; + @internal + final Map? unknown; + const SdkInfo({ this.sdkName, this.versionMajor, this.versionMinor, this.versionPatchlevel, + this.unknown, }); /// Deserializes a [SdkInfo] from JSON [Map]. @@ -22,17 +28,25 @@ class SdkInfo { versionMajor: json['version_major'], versionMinor: json['version_minor'], versionPatchlevel: json['version_patchlevel'], + unknown: unknownFrom(json, { + 'sdk_name', + 'version_major', + 'version_minor', + 'version_patchlevel', + }), ); } /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { if (sdkName != null) 'sdk_name': sdkName, if (versionMajor != null) 'version_major': versionMajor, if (versionMinor != null) 'version_minor': versionMinor, if (versionPatchlevel != null) 'version_patchlevel': versionPatchlevel, }; + json.addAll(unknown ?? {}); + return json; } SdkInfo copyWith({ @@ -46,5 +60,6 @@ class SdkInfo { versionMajor: versionMajor ?? this.versionMajor, versionMinor: versionMinor ?? this.versionMinor, versionPatchlevel: versionPatchlevel ?? this.versionPatchlevel, + unknown: unknown, ); } diff --git a/dart/test/protocol/sdk_info_test.dart b/dart/test/protocol/sdk_info_test.dart index 50e3c3fdcd..822b5e59d0 100644 --- a/dart/test/protocol/sdk_info_test.dart +++ b/dart/test/protocol/sdk_info_test.dart @@ -2,12 +2,15 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final sdkInfo = SdkInfo( sdkName: 'sdkName', versionMajor: 1, versionMinor: 2, versionPatchlevel: 3, + unknown: testUnknown, ); final sdkInfoJson = { @@ -16,6 +19,7 @@ void main() { 'version_minor': 2, 'version_patchlevel': 3, }; + sdkInfoJson.addAll(testUnknown); group('json', () { test('toJson', () { From 0cd7479a813f3eecc941e33368ef201f8af86649 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 15:16:04 +0200 Subject: [PATCH 09/43] Add `unknown` map to `SdkVersion` --- dart/lib/src/protocol/sdk_version.dart | 29 +++++++++++++++++------- dart/test/protocol/sdk_version_test.dart | 7 ++++++ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/dart/lib/src/protocol/sdk_version.dart b/dart/lib/src/protocol/sdk_version.dart index e4b686a402..6154225ac9 100644 --- a/dart/lib/src/protocol/sdk_version.dart +++ b/dart/lib/src/protocol/sdk_version.dart @@ -1,6 +1,7 @@ import 'package:meta/meta.dart'; import 'sentry_package.dart'; +import 'unknown.dart'; /// Describes the SDK that is submitting events to Sentry. /// @@ -40,6 +41,7 @@ class SdkVersion { required this.version, List? integrations, List? packages, + this.unknown, }) : // List.from prevents from having immutable lists _integrations = List.from(integrations ?? []), @@ -61,29 +63,39 @@ class SdkVersion { /// An immutable list of packages that compose this SDK. List get packages => List.unmodifiable(_packages); + @internal + final Map? unknown; + /// Deserializes a [SdkVersion] from JSON [Map]. factory SdkVersion.fromJson(Map json) { final packagesJson = json['packages'] as List?; final integrationsJson = json['integrations'] as List?; return SdkVersion( - name: json['name'], - version: json['version'], - packages: packagesJson - ?.map((e) => SentryPackage.fromJson(e as Map)) - .toList(), - integrations: integrationsJson?.map((e) => e as String).toList(), - ); + name: json['name'], + version: json['version'], + packages: packagesJson + ?.map((e) => SentryPackage.fromJson(e as Map)) + .toList(), + integrations: integrationsJson?.map((e) => e as String).toList(), + unknown: unknownFrom(json, { + 'name', + 'version' + 'packages', + 'integrations', + })); } /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final Map json = { 'name': name, 'version': version, if (packages.isNotEmpty) 'packages': packages.map((p) => p.toJson()).toList(growable: false), if (integrations.isNotEmpty) 'integrations': integrations, }; + json.addAll(unknown ?? {}); + return json; } /// Adds a package @@ -117,5 +129,6 @@ class SdkVersion { version: version ?? this.version, integrations: integrations ?? _integrations, packages: packages ?? _packages, + unknown: unknown, ); } diff --git a/dart/test/protocol/sdk_version_test.dart b/dart/test/protocol/sdk_version_test.dart index 92f799712c..b2e85a73c4 100644 --- a/dart/test/protocol/sdk_version_test.dart +++ b/dart/test/protocol/sdk_version_test.dart @@ -2,6 +2,8 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { group('json', () { final fixture = Fixture(); @@ -95,10 +97,15 @@ class Fixture { ], }; + Fixture() { + sdkVersionJson.addAll(testUnknown); + } + SdkVersion getSut() => SdkVersion( name: 'name', version: 'version', integrations: ['test'], packages: [SentryPackage('name', 'version')], + unknown: testUnknown, ); } From 7c1ba853dfa259f3d91c2a4b7bb1ab46a89b40f8 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 15:30:18 +0200 Subject: [PATCH 10/43] Add `unknown` map to `SentryApp` --- dart/lib/src/protocol/sentry_app.dart | 52 ++++++++++++++++++------- dart/test/protocol/sentry_app_test.dart | 4 ++ 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/dart/lib/src/protocol/sentry_app.dart b/dart/lib/src/protocol/sentry_app.dart index 24501ce540..d302a63623 100644 --- a/dart/lib/src/protocol/sentry_app.dart +++ b/dart/lib/src/protocol/sentry_app.dart @@ -1,5 +1,7 @@ import 'package:meta/meta.dart'; +import 'unknown.dart'; + /// App context describes the application. /// /// As opposed to the runtime, this is the actual application that was @@ -20,6 +22,7 @@ class SentryApp { this.inForeground, this.viewNames, this.textScale, + this.unknown, }); /// Human readable application name, as it appears on the platform. @@ -56,29 +59,44 @@ class SentryApp { /// The current text scale. Only available on Flutter. final double? textScale; + @internal + final Map? unknown; + /// Deserializes a [SentryApp] from JSON [Map]. factory SentryApp.fromJson(Map data) { final viewNamesJson = data['view_names'] as List?; return SentryApp( - name: data['app_name'], - version: data['app_version'], - identifier: data['app_identifier'], - build: data['app_build'], - buildType: data['build_type'], - startTime: data['app_start_time'] != null - ? DateTime.tryParse(data['app_start_time']) - : null, - deviceAppHash: data['device_app_hash'], - appMemory: data['app_memory'], - inForeground: data['in_foreground'], - viewNames: viewNamesJson?.map((e) => e as String).toList(), - textScale: data['text_scale'], - ); + name: data['app_name'], + version: data['app_version'], + identifier: data['app_identifier'], + build: data['app_build'], + buildType: data['build_type'], + startTime: data['app_start_time'] != null + ? DateTime.tryParse(data['app_start_time']) + : null, + deviceAppHash: data['device_app_hash'], + appMemory: data['app_memory'], + inForeground: data['in_foreground'], + viewNames: viewNamesJson?.map((e) => e as String).toList(), + textScale: data['text_scale'], + unknown: unknownFrom(data, { + 'app_name', + 'app_version', + 'app_identifier', + 'app_build', + 'build_type', + 'app_start_time', + 'device_app_hash', + 'app_memory', + 'in_foreground', + 'view_names', + 'text_scale', + })); } /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final Map json = { if (name != null) 'app_name': name!, if (version != null) 'app_version': version!, if (identifier != null) 'app_identifier': identifier!, @@ -91,6 +109,8 @@ class SentryApp { if (viewNames != null && viewNames!.isNotEmpty) 'view_names': viewNames!, if (textScale != null) 'text_scale': textScale!, }; + json.addAll(unknown ?? {}); + return json; } SentryApp clone() => SentryApp( @@ -105,6 +125,7 @@ class SentryApp { inForeground: inForeground, viewNames: viewNames, textScale: textScale, + unknown: unknown, ); SentryApp copyWith({ @@ -132,5 +153,6 @@ class SentryApp { inForeground: inForeground ?? this.inForeground, viewNames: viewNames ?? this.viewNames, textScale: textScale ?? this.textScale, + unknown: unknown, ); } diff --git a/dart/test/protocol/sentry_app_test.dart b/dart/test/protocol/sentry_app_test.dart index 0fdef8a780..fbc468d3d9 100644 --- a/dart/test/protocol/sentry_app_test.dart +++ b/dart/test/protocol/sentry_app_test.dart @@ -2,6 +2,8 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final testStartTime = DateTime.fromMicrosecondsSinceEpoch(0); @@ -16,6 +18,7 @@ void main() { inForeground: true, viewNames: ['fixture-viewName', 'fixture-viewName2'], textScale: 2.0, + unknown: testUnknown, ); final sentryAppJson = { @@ -30,6 +33,7 @@ void main() { 'view_names': ['fixture-viewName', 'fixture-viewName2'], 'text_scale': 2.0, }; + sentryAppJson.addAll(testUnknown); group('json', () { test('toJson', () { From f42d9936fd6baec60280e271baf99e2e08fe98be Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 15:34:30 +0200 Subject: [PATCH 11/43] Add `unknown` map to `SentryBrowser ` --- dart/lib/src/protocol/sentry_browser.dart | 24 +++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/dart/lib/src/protocol/sentry_browser.dart b/dart/lib/src/protocol/sentry_browser.dart index f2807e1092..417f6bb497 100644 --- a/dart/lib/src/protocol/sentry_browser.dart +++ b/dart/lib/src/protocol/sentry_browser.dart @@ -1,5 +1,7 @@ import 'package:meta/meta.dart'; +import 'unknown.dart'; + /// Carries information about the browser or user agent for web-related errors. /// /// This can either be the browser this event ocurred in, or the user @@ -9,7 +11,7 @@ class SentryBrowser { static const type = 'browser'; /// Creates an instance of [SentryBrowser]. - const SentryBrowser({this.name, this.version}); + const SentryBrowser({this.name, this.version, this.unknown}); /// Human readable application name, as it appears on the platform. final String? name; @@ -17,21 +19,30 @@ class SentryBrowser { /// Human readable application version, as it appears on the platform. final String? version; + @internal + final Map? unknown; + /// Deserializes a [SentryBrowser] from JSON [Map]. factory SentryBrowser.fromJson(Map data) => SentryBrowser( - name: data['name'], - version: data['version'], - ); + name: data['name'], + version: data['version'], + unknown: unknownFrom(data, {'name', 'version'})); /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { if (name != null) 'name': name, if (version != null) 'version': version, }; + json.addAll(unknown ?? {}); + return json; } - SentryBrowser clone() => SentryBrowser(name: name, version: version); + SentryBrowser clone() => SentryBrowser( + name: name, + version: version, + unknown: unknown, + ); SentryBrowser copyWith({ String? name, @@ -40,5 +51,6 @@ class SentryBrowser { SentryBrowser( name: name ?? this.name, version: version ?? this.version, + unknown: unknown, ); } From 6a2449e975459e38e84ce398442e3ed7a7d3df64 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 15:37:27 +0200 Subject: [PATCH 12/43] Add `unknown` map to `SentryCulture` --- dart/lib/src/protocol/sentry_culture.dart | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/protocol/sentry_culture.dart b/dart/lib/src/protocol/sentry_culture.dart index e48a973131..4aa9176f2a 100644 --- a/dart/lib/src/protocol/sentry_culture.dart +++ b/dart/lib/src/protocol/sentry_culture.dart @@ -1,5 +1,7 @@ import 'package:meta/meta.dart'; +import 'unknown.dart'; + /// Culture Context describes certain properties of the culture in which the /// software is used. @immutable @@ -12,6 +14,7 @@ class SentryCulture { this.locale, this.is24HourFormat, this.timezone, + this.unknown, }); factory SentryCulture.fromJson(Map data) => SentryCulture( @@ -20,6 +23,13 @@ class SentryCulture { locale: data['locale'], is24HourFormat: data['is_24_hour_format'], timezone: data['timezone'], + unknown: unknownFrom(data, { + 'calendar', + 'display_name', + 'locale', + 'is_24_hour_format', + 'timezone', + }), ); /// Optional: For example `GregorianCalendar`. Free form string. @@ -39,15 +49,20 @@ class SentryCulture { /// Optional. The timezone of the locale. For example, `Europe/Vienna`. final String? timezone; + @internal + final Map? unknown; + /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { if (calendar != null) 'calendar': calendar!, if (displayName != null) 'display_name': displayName!, if (locale != null) 'locale': locale!, if (is24HourFormat != null) 'is_24_hour_format': is24HourFormat!, if (timezone != null) 'timezone': timezone!, }; + json.addAll(unknown ?? {}); + return json; } SentryCulture clone() => SentryCulture( @@ -56,6 +71,7 @@ class SentryCulture { locale: locale, is24HourFormat: is24HourFormat, timezone: timezone, + unknown: unknown, ); SentryCulture copyWith({ @@ -71,5 +87,6 @@ class SentryCulture { locale: locale ?? this.locale, is24HourFormat: is24HourFormat ?? this.is24HourFormat, timezone: timezone ?? this.timezone, + unknown: unknown, ); } From ca57838ab523acbc268c16aecd6dca7f600511c8 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 15:41:33 +0200 Subject: [PATCH 13/43] Add `unknown` map to `SentryDevice ` --- dart/lib/src/protocol/sentry_device.dart | 49 +++++++++++++++++++++- dart/test/protocol/sentry_device_test.dart | 4 ++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/protocol/sentry_device.dart b/dart/lib/src/protocol/sentry_device.dart index cad8c765f5..d0b3242661 100644 --- a/dart/lib/src/protocol/sentry_device.dart +++ b/dart/lib/src/protocol/sentry_device.dart @@ -1,5 +1,6 @@ import 'package:meta/meta.dart'; import '../sentry_options.dart'; +import 'unknown.dart'; /// If a device is on portrait or landscape mode enum SentryOrientation { portrait, landscape } @@ -46,6 +47,7 @@ class SentryDevice { this.supportsGyroscope, this.supportsAudio, this.supportsLocationService, + this.unknown, }) : assert( batteryLevel == null || (batteryLevel >= 0 && batteryLevel <= 100), ); @@ -171,6 +173,9 @@ class SentryDevice { /// Optional. Is the device capable of reporting its location? final bool? supportsLocationService; + @internal + final Map? unknown; + /// Deserializes a [SentryDevice] from JSON [Map]. factory SentryDevice.fromJson(Map data) => SentryDevice( name: data['name'], @@ -217,11 +222,49 @@ class SentryDevice { supportsGyroscope: data['supports_gyroscope'], supportsAudio: data['supports_audio'], supportsLocationService: data['supports_location_service'], + unknown: unknownFrom(data, { + 'name', + 'family', + 'model', + 'model_id', + 'arch', + 'battery_level', + 'orientation', + 'manufacturer', + 'brand', + 'screen_height_pixels', + 'screen_width_pixels', + 'screen_density', + 'screen_dpi', + 'online', + 'charging', + 'low_memory', + 'simulator', + 'memory_size', + 'free_memory', + 'usable_memory', + 'storage_size', + 'free_storage', + 'external_storage_size', + 'external_free_storage', + 'boot_time', + 'processor_count', + 'cpu_description', + 'processor_frequency', + 'device_type', + 'battery_status', + 'device_unique_identifier', + 'supports_vibration', + 'supports_accelerometer', + 'supports_gyroscope', + 'supports_audio', + 'supports_location_service', + }), ); /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { if (name != null) 'name': name, if (family != null) 'family': family, if (model != null) 'model': model, @@ -265,6 +308,8 @@ class SentryDevice { if (supportsLocationService != null) 'supports_location_service': supportsLocationService, }; + json.addAll(unknown ?? {}); + return json; } SentryDevice clone() => SentryDevice( @@ -304,6 +349,7 @@ class SentryDevice { supportsGyroscope: supportsGyroscope, supportsAudio: supportsAudio, supportsLocationService: supportsLocationService, + unknown: unknown, ); SentryDevice copyWith({ @@ -384,5 +430,6 @@ class SentryDevice { supportsAudio: supportsAudio ?? this.supportsAudio, supportsLocationService: supportsLocationService ?? this.supportsLocationService, + unknown: unknown, ); } diff --git a/dart/test/protocol/sentry_device_test.dart b/dart/test/protocol/sentry_device_test.dart index d7ed3e518f..7f405e09bf 100644 --- a/dart/test/protocol/sentry_device_test.dart +++ b/dart/test/protocol/sentry_device_test.dart @@ -2,6 +2,8 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final testBootTime = DateTime.fromMicrosecondsSinceEpoch(0); @@ -42,6 +44,7 @@ void main() { supportsVibration: true, screenHeightPixels: 100, screenWidthPixels: 100, + unknown: testUnknown, ); final sentryDeviceJson = { @@ -82,6 +85,7 @@ void main() { 'screen_height_pixels': 100, 'screen_width_pixels': 100, }; + sentryDeviceJson.addAll(testUnknown); group('json', () { test('toJson', () { From 333b302c3802b65ea5463cd535f696bf76641c3d Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 15:52:59 +0200 Subject: [PATCH 14/43] Add `unknown` map to `SentryEvent` --- dart/lib/src/protocol/sentry_event.dart | 37 ++++++++- dart/test/sentry_event_test.dart | 102 +++++++++++++----------- 2 files changed, 91 insertions(+), 48 deletions(-) diff --git a/dart/lib/src/protocol/sentry_event.dart b/dart/lib/src/protocol/sentry_event.dart index 32a76b9885..fa949b8be3 100644 --- a/dart/lib/src/protocol/sentry_event.dart +++ b/dart/lib/src/protocol/sentry_event.dart @@ -3,6 +3,7 @@ import 'package:meta/meta.dart'; import '../protocol.dart'; import '../throwable_mechanism.dart'; import '../utils.dart'; +import 'unknown.dart'; /// An event to be reported to Sentry.io. @immutable @@ -37,6 +38,7 @@ class SentryEvent with SentryEventLike { this.request, this.debugMeta, this.type, + this.unknown, }) : eventId = eventId ?? SentryId.newId(), timestamp = timestamp ?? getUtcDateTime(), contexts = contexts ?? Contexts(), @@ -189,6 +191,9 @@ class SentryEvent with SentryEventLike { /// defaults to 'default' final String? type; + @internal + final Map? unknown; + @override SentryEvent copyWith({ SentryId? eventId, @@ -251,6 +256,7 @@ class SentryEvent with SentryEventLike { this.exceptions, threads: (threads != null ? List.from(threads) : null) ?? this.threads, type: type ?? this.type, + unknown: unknown, ); /// Deserializes a [SentryEvent] from JSON [Map]. @@ -329,6 +335,33 @@ class SentryEvent with SentryEventLike { : null, exceptions: exceptions, type: json['type'], + unknown: unknownFrom(json, { + 'breadcrumbs', + 'threads', + 'exception', + 'modules', + 'tags', + 'timestamp', + 'level', + 'fingerprint', + 'sdk', + 'message', + 'user', + 'contexts', + 'request', + 'debug_meta', + 'extra', + 'event_id', + 'platform', + 'logger', + 'server_name', + 'release', + 'dist', + 'environment', + 'transaction', + 'culprit', + 'type', + }), ); } @@ -368,7 +401,7 @@ class SentryEvent with SentryEventLike { .where((e) => e.isNotEmpty) .toList(growable: false); - return { + final json = { 'event_id': eventId.toString(), if (timestamp != null) 'timestamp': formatDateAsIso8601WithMillisPrecision(timestamp!), @@ -400,5 +433,7 @@ class SentryEvent with SentryEventLike { 'exception': {'values': exceptionsJson}, if (threadJson?.isNotEmpty ?? false) 'threads': {'values': threadJson}, }; + json.addAll(unknown ?? {}); + return json; } } diff --git a/dart/test/sentry_event_test.dart b/dart/test/sentry_event_test.dart index 4e661638a8..fe9d3b4d48 100644 --- a/dart/test/sentry_event_test.dart +++ b/dart/test/sentry_event_test.dart @@ -7,6 +7,8 @@ import 'package:sentry/sentry.dart'; import 'package:sentry/src/version.dart'; import 'package:test/test.dart'; +import 'mocks.dart'; + void main() { group('deserialize', () { final sentryId = SentryId.empty(); @@ -60,6 +62,7 @@ void main() { }, 'type': 'type', }; + sentryEventJson.addAll(testUnknown); final emptyFieldsSentryEventJson = { 'event_id': sentryId.toString(), @@ -105,6 +108,7 @@ void main() { expect(sentryEvent.request, isNull); expect(sentryEvent.debugMeta, isNull); expect(sentryEvent.type, isNull); + expect(sentryEvent.unknown, isNull); }); }); @@ -184,52 +188,56 @@ void main() { expect( SentryEvent( - eventId: SentryId.empty(), - timestamp: timestamp, - platform: sdkPlatform(platformChecker.isWeb), - message: SentryMessage( - 'test-message 1 2', - template: 'test-message %d %d', - params: ['1', '2'], - ), - transaction: '/test/1', - level: SentryLevel.debug, - culprit: 'Professor Moriarty', - tags: const { - 'a': 'b', - 'c': 'd', - }, - // ignore: deprecated_member_use_from_same_package - extra: const { - 'e': 'f', - 'g': 2, - }, - fingerprint: const [SentryEvent.defaultFingerprint, 'foo'], - user: user, - breadcrumbs: breadcrumbs, - request: request, - debugMeta: DebugMeta( - sdk: SdkInfo( - sdkName: 'sentry.dart', - versionMajor: 4, - versionMinor: 1, - versionPatchlevel: 2, - ), - images: const [ - DebugImage( - type: 'macho', - debugId: '84a04d24-0e60-3810-a8c0-90a65e2df61a', - debugFile: 'libDiagnosticMessagesClient.dylib', - codeFile: '/usr/lib/libDiagnosticMessagesClient.dylib', - imageAddr: '0x7fffe668e000', - imageSize: 8192, - arch: 'x86_64', - codeId: '123', - ) - ], - ), - type: 'type', - ).toJson(), + eventId: SentryId.empty(), + timestamp: timestamp, + platform: sdkPlatform(platformChecker.isWeb), + message: SentryMessage( + 'test-message 1 2', + template: 'test-message %d %d', + params: ['1', '2'], + ), + transaction: '/test/1', + level: SentryLevel.debug, + culprit: 'Professor Moriarty', + tags: const { + 'a': 'b', + 'c': 'd', + }, + // ignore: deprecated_member_use_from_same_package + extra: const { + 'e': 'f', + 'g': 2, + }, + fingerprint: const [ + SentryEvent.defaultFingerprint, + 'foo' + ], + user: user, + breadcrumbs: breadcrumbs, + request: request, + debugMeta: DebugMeta( + sdk: SdkInfo( + sdkName: 'sentry.dart', + versionMajor: 4, + versionMinor: 1, + versionPatchlevel: 2, + ), + images: const [ + DebugImage( + type: 'macho', + debugId: '84a04d24-0e60-3810-a8c0-90a65e2df61a', + debugFile: 'libDiagnosticMessagesClient.dylib', + codeFile: '/usr/lib/libDiagnosticMessagesClient.dylib', + imageAddr: '0x7fffe668e000', + imageSize: 8192, + arch: 'x86_64', + codeId: '123', + ) + ], + ), + type: 'type', + unknown: testUnknown) + .toJson(), { 'platform': platformChecker.isWeb ? 'javascript' : 'other', 'event_id': '00000000000000000000000000000000', @@ -286,7 +294,7 @@ void main() { ] }, 'type': 'type', - }, + }..addAll(testUnknown), ); }); From f27e586d5c97b2c1c33d997bc530f187ec6e3a8b Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 15:56:26 +0200 Subject: [PATCH 15/43] Add `unknown` map to `SentryException` --- dart/lib/src/protocol/sentry_exception.dart | 18 +++++++++++++++++- dart/test/protocol/sentry_exception_test.dart | 4 ++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/protocol/sentry_exception.dart b/dart/lib/src/protocol/sentry_exception.dart index 45de1b5c9c..3b4a92f9a1 100644 --- a/dart/lib/src/protocol/sentry_exception.dart +++ b/dart/lib/src/protocol/sentry_exception.dart @@ -1,6 +1,7 @@ import 'package:meta/meta.dart'; import '../protocol.dart'; +import 'unknown.dart'; /// The Exception Interface specifies an exception or error that occurred in a program. @immutable @@ -25,6 +26,9 @@ class SentryException { final dynamic throwable; + @internal + final Map? unknown; + const SentryException({ required this.type, required this.value, @@ -33,6 +37,7 @@ class SentryException { this.mechanism, this.threadId, this.throwable, + this.unknown, }); /// Deserializes a [SentryException] from JSON [Map]. @@ -49,12 +54,20 @@ class SentryException { mechanism: mechanismJson != null ? Mechanism.fromJson(mechanismJson) : null, threadId: json['thread_id'], + unknown: unknownFrom(json, { + 'stacktrace', + 'mechanism', + 'type', + 'value', + 'module', + 'thread_id', + }), ); } /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { if (type != null) 'type': type, if (value != null) 'value': value, if (module != null) 'module': module, @@ -62,6 +75,8 @@ class SentryException { if (mechanism != null) 'mechanism': mechanism!.toJson(), if (threadId != null) 'thread_id': threadId, }; + json.addAll(unknown ?? {}); + return json; } SentryException copyWith({ @@ -81,5 +96,6 @@ class SentryException { mechanism: mechanism ?? this.mechanism, threadId: threadId ?? this.threadId, throwable: throwable ?? this.throwable, + unknown: unknown, ); } diff --git a/dart/test/protocol/sentry_exception_test.dart b/dart/test/protocol/sentry_exception_test.dart index 15c75b0191..4541e67332 100644 --- a/dart/test/protocol/sentry_exception_test.dart +++ b/dart/test/protocol/sentry_exception_test.dart @@ -2,6 +2,8 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final sentryException = SentryException( type: 'type', @@ -10,6 +12,7 @@ void main() { stackTrace: SentryStackTrace(frames: [SentryStackFrame(absPath: 'abs')]), mechanism: Mechanism(type: 'type'), threadId: 1, + unknown: testUnknown, ); final sentryExceptionJson = { @@ -24,6 +27,7 @@ void main() { 'mechanism': {'type': 'type'}, 'thread_id': 1, }; + sentryExceptionJson.addAll(testUnknown); group('json', () { test('fromJson', () { From d5f92f2225853acf3771268449b8f92ee4998e39 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 15:59:47 +0200 Subject: [PATCH 16/43] Add `unknown` map to `SentryGpu` --- dart/lib/src/protocol/sentry_gpu.dart | 29 ++++++++++++++++++++++++- dart/test/protocol/sentry_gpu_test.dart | 23 ++++++++++++-------- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/dart/lib/src/protocol/sentry_gpu.dart b/dart/lib/src/protocol/sentry_gpu.dart index f428e674bb..620f046290 100644 --- a/dart/lib/src/protocol/sentry_gpu.dart +++ b/dart/lib/src/protocol/sentry_gpu.dart @@ -12,6 +12,8 @@ import 'package:meta/meta.dart'; +import 'unknown.dart'; + /// GPU context describes the GPU of the device. @immutable class SentryGpu { @@ -65,6 +67,9 @@ class SentryGpu { /// Whether ray tracing is available on the device. final bool? supportsRayTracing; + @internal + final Map? unknown; + const SentryGpu({ this.name, this.id, @@ -81,6 +86,7 @@ class SentryGpu { this.supportsDrawCallInstancing, this.supportsGeometryShaders, this.supportsRayTracing, + this.unknown, }); /// Deserializes a [SentryGpu] from JSON [Map]. @@ -100,6 +106,23 @@ class SentryGpu { supportsDrawCallInstancing: data['supports_draw_call_instancing'], supportsGeometryShaders: data['supports_geometry_shaders'], supportsRayTracing: data['supports_ray_tracing'], + unknown: unknownFrom(data, { + 'name', + 'id', + 'vendor_id', + 'vendor_name', + 'memory_size', + 'api_type', + 'multi_threaded_rendering', + 'version', + 'npot_support', + 'graphics_shader_level', + 'max_texture_size', + 'supports_compute_shaders', + 'supports_draw_call_instancing', + 'supports_geometry_shaders', + 'supports_ray_tracing', + }), ); SentryGpu clone() => SentryGpu( @@ -118,11 +141,12 @@ class SentryGpu { supportsDrawCallInstancing: supportsDrawCallInstancing, supportsGeometryShaders: supportsGeometryShaders, supportsRayTracing: supportsRayTracing, + unknown: unknown, ); /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { if (name != null) 'name': name, if (id != null) 'id': id, if (vendorId != null) 'vendor_id': vendorId, @@ -145,6 +169,8 @@ class SentryGpu { if (supportsRayTracing != null) 'supports_ray_tracing': supportsRayTracing, }; + json.addAll(unknown ?? {}); + return json; } SentryGpu copyWith({ @@ -184,5 +210,6 @@ class SentryGpu { supportsGeometryShaders: supportsGeometryShaders ?? this.supportsGeometryShaders, supportsRayTracing: supportsRayTracing ?? this.supportsRayTracing, + unknown: unknown, ); } diff --git a/dart/test/protocol/sentry_gpu_test.dart b/dart/test/protocol/sentry_gpu_test.dart index 443b50ea91..af2907a648 100644 --- a/dart/test/protocol/sentry_gpu_test.dart +++ b/dart/test/protocol/sentry_gpu_test.dart @@ -2,17 +2,21 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final sentryGpu = SentryGpu( - name: 'fixture-name', - id: 1, - vendorId: '2', - vendorName: 'fixture-vendorName', - memorySize: 3, - apiType: 'fixture-apiType', - multiThreadedRendering: true, - version: '4', - npotSupport: 'fixture-npotSupport'); + name: 'fixture-name', + id: 1, + vendorId: '2', + vendorName: 'fixture-vendorName', + memorySize: 3, + apiType: 'fixture-apiType', + multiThreadedRendering: true, + version: '4', + npotSupport: 'fixture-npotSupport', + unknown: testUnknown, + ); final sentryGpuJson = { 'name': 'fixture-name', @@ -25,6 +29,7 @@ void main() { 'version': '4', 'npot_support': 'fixture-npotSupport' }; + sentryGpuJson.addAll(testUnknown); group('json', () { test('toJson', () { From 1924e07313c364daeba0c08d9e6f808ec2524413 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 16:03:22 +0200 Subject: [PATCH 17/43] Add `unknown` map to `SentryMessage ` --- dart/lib/src/protocol/sentry_message.dart | 26 +++++++++++++++------ dart/test/protocol/sentry_message_test.dart | 4 ++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/dart/lib/src/protocol/sentry_message.dart b/dart/lib/src/protocol/sentry_message.dart index 6115458ef2..a06990469f 100644 --- a/dart/lib/src/protocol/sentry_message.dart +++ b/dart/lib/src/protocol/sentry_message.dart @@ -1,5 +1,7 @@ import 'package:meta/meta.dart'; +import 'unknown.dart'; + /// The Message Interface carries a log message that describes an event or error. /// Optionally, it can carry a format string and structured parameters. This can help to group similar messages into the same issue. /// example of a serialized message: @@ -23,24 +25,33 @@ class SentryMessage { /// A list of formatting parameters, preferably strings. Non-strings will be coerced to strings. final List? params; - const SentryMessage(this.formatted, {this.template, this.params}); + @internal + final Map? unknown; + + const SentryMessage( + this.formatted, { + this.template, + this.params, + this.unknown, + }); /// Deserializes a [SentryMessage] from JSON [Map]. factory SentryMessage.fromJson(Map json) { - return SentryMessage( - json['formatted'], - template: json['message'], - params: json['params'], - ); + return SentryMessage(json['formatted'], + template: json['message'], + params: json['params'], + unknown: unknownFrom(json, {'formatted', 'message', 'params'})); } /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { 'formatted': formatted, if (template != null) 'message': template, if (params?.isNotEmpty ?? false) 'params': params, }; + json.addAll(unknown ?? {}); + return json; } SentryMessage copyWith({ @@ -52,5 +63,6 @@ class SentryMessage { formatted ?? this.formatted, template: template ?? this.template, params: params ?? this.params, + unknown: unknown, ); } diff --git a/dart/test/protocol/sentry_message_test.dart b/dart/test/protocol/sentry_message_test.dart index 7112642ed2..b89c0ef08f 100644 --- a/dart/test/protocol/sentry_message_test.dart +++ b/dart/test/protocol/sentry_message_test.dart @@ -2,11 +2,14 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final sentryMessage = SentryMessage( 'message 1', template: 'message %d', params: ['1'], + unknown: testUnknown, ); final sentryMessageJson = { @@ -14,6 +17,7 @@ void main() { 'message': 'message %d', 'params': ['1'], }; + sentryMessageJson.addAll(testUnknown); group('json', () { test('toJson', () { From 1dc46f75e8ddcc9667c8638c92c9515c8c891499 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 16:07:16 +0200 Subject: [PATCH 18/43] Add `unknown` map to `SentryOperatingSystem` --- .../src/protocol/sentry_operating_system.dart | 21 ++++++++++++++++++- .../sentry_operating_system_test.dart | 17 +++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/dart/lib/src/protocol/sentry_operating_system.dart b/dart/lib/src/protocol/sentry_operating_system.dart index 89839e8da1..5d798d7ea0 100644 --- a/dart/lib/src/protocol/sentry_operating_system.dart +++ b/dart/lib/src/protocol/sentry_operating_system.dart @@ -1,5 +1,7 @@ import 'package:meta/meta.dart'; +import 'unknown.dart'; + /// Describes the operating system on which the event was created. /// /// In web contexts, this is the operating system of the browse @@ -16,6 +18,7 @@ class SentryOperatingSystem { this.rooted, this.rawDescription, this.theme, + this.unknown, }); /// The name of the operating system. @@ -45,6 +48,9 @@ class SentryOperatingSystem { /// Describes whether the OS runs in dark mode or not. final String? theme; + @internal + final Map? unknown; + /// Deserializes a [SentryOperatingSystem] from JSON [Map]. factory SentryOperatingSystem.fromJson(Map data) => SentryOperatingSystem( @@ -55,11 +61,20 @@ class SentryOperatingSystem { rooted: data['rooted'], rawDescription: data['raw_description'], theme: data['theme'], + unknown: unknownFrom(data, { + 'name', + 'version', + 'build', + 'kernel_version', + 'rooted', + 'raw_description', + 'theme', + }), ); /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { if (name != null) 'name': name, if (version != null) 'version': version, if (build != null) 'build': build, @@ -68,6 +83,8 @@ class SentryOperatingSystem { if (rawDescription != null) 'raw_description': rawDescription, if (theme != null) 'theme': theme, }; + json.addAll(unknown ?? {}); + return json; } SentryOperatingSystem clone() => SentryOperatingSystem( @@ -78,6 +95,7 @@ class SentryOperatingSystem { rooted: rooted, rawDescription: rawDescription, theme: theme, + unknown: unknown, ); SentryOperatingSystem copyWith({ @@ -97,5 +115,6 @@ class SentryOperatingSystem { rooted: rooted ?? this.rooted, rawDescription: rawDescription ?? this.rawDescription, theme: theme ?? this.theme, + unknown: unknown, ); } diff --git a/dart/test/protocol/sentry_operating_system_test.dart b/dart/test/protocol/sentry_operating_system_test.dart index dee235712d..9ca41e8590 100644 --- a/dart/test/protocol/sentry_operating_system_test.dart +++ b/dart/test/protocol/sentry_operating_system_test.dart @@ -2,14 +2,18 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final sentryOperatingSystem = SentryOperatingSystem( - name: 'fixture-name', - version: 'fixture-version', - build: 'fixture-build', - kernelVersion: 'fixture-kernelVersion', - rooted: true, - rawDescription: 'fixture-rawDescription'); + name: 'fixture-name', + version: 'fixture-version', + build: 'fixture-build', + kernelVersion: 'fixture-kernelVersion', + rooted: true, + rawDescription: 'fixture-rawDescription', + unknown: testUnknown, + ); final sentryOperatingSystemJson = { 'name': 'fixture-name', @@ -19,6 +23,7 @@ void main() { 'rooted': true, 'raw_description': 'fixture-rawDescription' }; + sentryOperatingSystemJson.addAll(testUnknown); group('json', () { test('toJson', () { From f8def7f173549cff79c245ddeedd0ea3895fe079 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 9 Jul 2024 16:11:56 +0200 Subject: [PATCH 19/43] Add `unknown` map to `SentryPackage` --- dart/lib/src/protocol/sentry_package.dart | 13 +++++++++++-- dart/test/protocol/sentry_package_test.dart | 4 ++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/dart/lib/src/protocol/sentry_package.dart b/dart/lib/src/protocol/sentry_package.dart index 8157a50aeb..bee8e21f6f 100644 --- a/dart/lib/src/protocol/sentry_package.dart +++ b/dart/lib/src/protocol/sentry_package.dart @@ -1,10 +1,12 @@ import 'package:meta/meta.dart'; +import 'unknown.dart'; + /// A [SentryPackage] part of the SDK. @immutable class SentryPackage { /// Creates an [SentryPackage] object that is part of the SDK. - const SentryPackage(this.name, this.version); + const SentryPackage(this.name, this.version, {this.unknown}); /// The name of the SDK. final String name; @@ -12,20 +14,26 @@ class SentryPackage { /// The version of the SDK. final String version; + @internal + final Map? unknown; + /// Deserializes a [SentryPackage] from JSON [Map]. factory SentryPackage.fromJson(Map json) { return SentryPackage( json['name'], json['version'], + unknown: unknownFrom(json, {'name', 'version'}), ); } /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { 'name': name, 'version': version, }; + json.addAll(unknown ?? {}); + return json; } SentryPackage copyWith({ @@ -35,5 +43,6 @@ class SentryPackage { SentryPackage( name ?? this.name, version ?? this.version, + unknown: unknown, ); } diff --git a/dart/test/protocol/sentry_package_test.dart b/dart/test/protocol/sentry_package_test.dart index b8c1d40e71..7f9e82bfc4 100644 --- a/dart/test/protocol/sentry_package_test.dart +++ b/dart/test/protocol/sentry_package_test.dart @@ -2,16 +2,20 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final sentryPackage = SentryPackage( 'name', 'version', + unknown: testUnknown, ); final sentryPackageJson = { 'name': 'name', 'version': 'version', }; + sentryPackageJson.addAll(testUnknown); group('json', () { test('toJson', () { From 8a2bff29400175f60ac99349941b182ccb1eb75b Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 15 Jul 2024 13:57:18 +0200 Subject: [PATCH 20/43] Add `unknown` map to `SentryRequest` --- dart/lib/src/protocol/sentry_request.dart | 24 ++++++++++++++++++++- dart/test/protocol/sentry_request_test.dart | 4 ++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/protocol/sentry_request.dart b/dart/lib/src/protocol/sentry_request.dart index b5ee7d003c..eb5a22a5cb 100644 --- a/dart/lib/src/protocol/sentry_request.dart +++ b/dart/lib/src/protocol/sentry_request.dart @@ -1,4 +1,5 @@ import 'package:meta/meta.dart'; +import 'package:sentry/src/protocol/unknown.dart'; import '../utils/iterable_utils.dart'; import '../utils/http_sanitizer.dart'; @@ -69,6 +70,9 @@ class SentryRequest { /// its target specification. final String? apiTarget; + @internal + final Map? unknown; + SentryRequest({ this.url, this.method, @@ -81,6 +85,7 @@ class SentryRequest { Map? env, @Deprecated('Will be removed in v8. Use [data] instead') Map? other, + this.unknown, }) : _data = data, _headers = headers != null ? Map.from(headers) : null, // Look for a 'Set-Cookie' header (case insensitive) if not given. @@ -132,12 +137,24 @@ class SentryRequest { other: json.containsKey('other') ? Map.from(json['other']) : null, fragment: json['fragment'], apiTarget: json['api_target'], + unknown: unknownFrom(json, { + 'url', + 'method', + 'query_string', + 'cookies', + 'data', + 'headers', + 'env', + 'other', + 'fragment', + 'api_target', + }), ); } /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { if (url != null) 'url': url, if (method != null) 'method': method, if (queryString != null) 'query_string': queryString, @@ -150,6 +167,10 @@ class SentryRequest { if (fragment != null) 'fragment': fragment, if (apiTarget != null) 'api_target': apiTarget, }; + if (unknown != null) { + json.addAll(unknown ?? {}); + } + return json; } SentryRequest copyWith({ @@ -178,5 +199,6 @@ class SentryRequest { apiTarget: apiTarget ?? this.apiTarget, // ignore: deprecated_member_use_from_same_package other: other ?? _other, + unknown: unknown, ); } diff --git a/dart/test/protocol/sentry_request_test.dart b/dart/test/protocol/sentry_request_test.dart index a1d186632b..0aeb24dc1d 100644 --- a/dart/test/protocol/sentry_request_test.dart +++ b/dart/test/protocol/sentry_request_test.dart @@ -2,6 +2,8 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final sentryRequest = SentryRequest( url: 'url', @@ -14,6 +16,7 @@ void main() { apiTarget: 'GraphQL', // ignore: deprecated_member_use_from_same_package other: {'other_key': 'other_value'}, + unknown: testUnknown, ); final sentryRequestJson = { @@ -27,6 +30,7 @@ void main() { 'api_target': 'GraphQL', 'other': {'other_key': 'other_value'}, }; + sentryRequestJson.addAll(testUnknown); group('json', () { test('toJson', () { From 2aef9e997fdf4500acc13b3d0b0f09135b877e57 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 15 Jul 2024 14:02:40 +0200 Subject: [PATCH 21/43] Add `unknown` map to `SentryRuntime` --- dart/lib/src/protocol/sentry_runtime.dart | 20 +++++++++++++++++++- dart/test/protocol/sentry_runtime_test.dart | 4 ++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/protocol/sentry_runtime.dart b/dart/lib/src/protocol/sentry_runtime.dart index 960f48c170..6b966dc402 100644 --- a/dart/lib/src/protocol/sentry_runtime.dart +++ b/dart/lib/src/protocol/sentry_runtime.dart @@ -1,5 +1,7 @@ import 'package:meta/meta.dart'; +import 'unknown.dart'; + /// Describes a runtime in more detail. /// /// Typically this context is used multiple times if multiple runtimes @@ -17,6 +19,7 @@ class SentryRuntime { this.compiler, this.rawDescription, this.build, + this.unknown, }) : assert(key == null || key.length >= 1); /// Key used in the JSON and which will be displayed @@ -44,6 +47,9 @@ class SentryRuntime { /// Application build string, if it is separate from the version. final String? build; + @internal + final Map? unknown; + /// Deserializes a [SentryRuntime] from JSON [Map]. factory SentryRuntime.fromJson(Map data) => SentryRuntime( name: data['name'], @@ -51,17 +57,28 @@ class SentryRuntime { compiler: data['compiler'], rawDescription: data['raw_description'], build: data['build'], + unknown: unknownFrom(data, { + 'name', + 'version', + 'compiler', + 'raw_description', + 'build', + }), ); /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { if (name != null) 'name': name, if (compiler != null) 'compiler': compiler, if (version != null) 'version': version, if (rawDescription != null) 'raw_description': rawDescription, if (build != null) 'build': build, }; + if (unknown != null) { + json.addAll(unknown ?? {}); + } + return json; } SentryRuntime clone() => SentryRuntime( @@ -88,5 +105,6 @@ class SentryRuntime { compiler: compiler ?? this.compiler, rawDescription: rawDescription ?? this.rawDescription, build: build ?? this.build, + unknown: unknown, ); } diff --git a/dart/test/protocol/sentry_runtime_test.dart b/dart/test/protocol/sentry_runtime_test.dart index 578eb8c9a3..2537950d8e 100644 --- a/dart/test/protocol/sentry_runtime_test.dart +++ b/dart/test/protocol/sentry_runtime_test.dart @@ -2,12 +2,15 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final sentryRuntime = SentryRuntime( key: 'key', name: 'name', version: 'version', rawDescription: 'rawDescription', + unknown: testUnknown, ); final sentryRuntimeJson = { @@ -15,6 +18,7 @@ void main() { 'version': 'version', 'raw_description': 'rawDescription', }; + sentryRuntimeJson.addAll(testUnknown); group('json', () { test('toJson', () { From 50b21c18c80b5af313897db493f185ce4aa00534 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 15 Jul 2024 14:11:05 +0200 Subject: [PATCH 22/43] Add `unknown` map to `SentryStackFrame` --- dart/lib/src/protocol/sentry_stack_frame.dart | 35 ++++++++++++++++++- .../protocol/sentry_stack_frame_test.dart | 4 +++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/protocol/sentry_stack_frame.dart b/dart/lib/src/protocol/sentry_stack_frame.dart index 12eb5de4f6..f31f2eb468 100644 --- a/dart/lib/src/protocol/sentry_stack_frame.dart +++ b/dart/lib/src/protocol/sentry_stack_frame.dart @@ -1,4 +1,5 @@ import 'package:meta/meta.dart'; +import 'package:sentry/src/protocol/unknown.dart'; /// Frames belong to a StackTrace /// It should contain at least a filename, function or instruction_addr @@ -26,6 +27,7 @@ class SentryStackFrame { List? preContext, List? postContext, Map? vars, + this.unknown, }) : _framesOmitted = framesOmitted != null ? List.from(framesOmitted) : null, _preContext = preContext != null ? List.from(preContext) : null, @@ -124,6 +126,9 @@ class SentryStackFrame { /// This is relevant for languages like Swift, C++ or Rust. final String? symbol; + @internal + final Map? unknown; + /// Deserializes a [SentryStackFrame] from JSON [Map]. factory SentryStackFrame.fromJson(Map json) { return SentryStackFrame( @@ -148,12 +153,35 @@ class SentryStackFrame { vars: json['vars'], symbol: json['symbol'], stackStart: json['stack_start'], + unknown: unknownFrom(json, { + 'abs_path', + 'filename', + 'function', + 'module', + 'lineno', + 'colno', + 'context_line', + 'in_app', + 'package', + 'native', + 'platform', + 'image_addr', + 'symbol_addr', + 'instruction_addr', + 'raw_function', + 'frames_omitted', + 'pre_context', + 'post_context', + 'vars', + 'symbol', + 'stack_start', + }), ); } /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { if (_preContext?.isNotEmpty ?? false) 'pre_context': _preContext, if (_postContext?.isNotEmpty ?? false) 'post_context': _postContext, if (_vars?.isNotEmpty ?? false) 'vars': _vars, @@ -176,6 +204,10 @@ class SentryStackFrame { if (symbol != null) 'symbol': symbol, if (stackStart != null) 'stack_start': stackStart, }; + if (unknown != null) { + json.addAll(unknown ?? {}); + } + return json; } SentryStackFrame copyWith({ @@ -223,5 +255,6 @@ class SentryStackFrame { vars: vars ?? _vars, symbol: symbol ?? symbol, stackStart: stackStart ?? stackStart, + unknown: unknown, ); } diff --git a/dart/test/protocol/sentry_stack_frame_test.dart b/dart/test/protocol/sentry_stack_frame_test.dart index 69b5ad30fa..eb4619dfbc 100644 --- a/dart/test/protocol/sentry_stack_frame_test.dart +++ b/dart/test/protocol/sentry_stack_frame_test.dart @@ -2,6 +2,8 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final sentryStackFrame = SentryStackFrame( absPath: 'absPath', @@ -23,6 +25,7 @@ void main() { preContext: ['a'], postContext: ['b'], vars: {'key': 'value'}, + unknown: testUnknown, ); final sentryStackFrameJson = { @@ -46,6 +49,7 @@ void main() { 'instruction_addr': 'instructionAddr', 'raw_function': 'rawFunction', }; + sentryStackFrameJson.addAll(testUnknown); group('json', () { test('toJson', () { From afb78d0d98148ac73069442f6f1273d8b87b2564 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 15 Jul 2024 14:19:35 +0200 Subject: [PATCH 23/43] Add `unknown` map to `SentryStackFrame` --- dart/lib/src/protocol/sentry_stack_trace.dart | 13 ++++++++++++- dart/test/protocol/sentry_stack_trace_test.dart | 4 ++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/protocol/sentry_stack_trace.dart b/dart/lib/src/protocol/sentry_stack_trace.dart index c8a6076726..d31a297d53 100644 --- a/dart/lib/src/protocol/sentry_stack_trace.dart +++ b/dart/lib/src/protocol/sentry_stack_trace.dart @@ -1,6 +1,7 @@ import 'package:meta/meta.dart'; import 'sentry_stack_frame.dart'; +import 'unknown.dart'; /// Stacktrace holds information about the frames of the stack. @immutable @@ -10,6 +11,7 @@ class SentryStackTrace { Map? registers, this.lang, this.snapshot, + this.unknown, }) : _frames = frames, _registers = Map.from(registers ?? {}); @@ -44,6 +46,9 @@ class SentryStackTrace { /// signal. final bool? snapshot; + @internal + final Map? unknown; + /// Deserializes a [SentryStackTrace] from JSON [Map]. factory SentryStackTrace.fromJson(Map json) { final framesJson = json['frames'] as List?; @@ -56,12 +61,13 @@ class SentryStackTrace { registers: json['registers'], lang: json['lang'], snapshot: json['snapshot'], + unknown: unknownFrom(json, {'frames', 'registers', 'lang', 'snapshot'}), ); } /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { if (_frames?.isNotEmpty ?? false) 'frames': _frames?.map((frame) => frame.toJson()).toList(growable: false), @@ -69,6 +75,10 @@ class SentryStackTrace { if (lang != null) 'lang': lang, if (snapshot != null) 'snapshot': snapshot, }; + if (unknown != null) { + json.addAll(unknown ?? {}); + } + return json; } SentryStackTrace copyWith({ @@ -78,5 +88,6 @@ class SentryStackTrace { SentryStackTrace( frames: frames ?? this.frames, registers: registers ?? this.registers, + unknown: unknown, ); } diff --git a/dart/test/protocol/sentry_stack_trace_test.dart b/dart/test/protocol/sentry_stack_trace_test.dart index ce3f4817d6..35388ec2cb 100644 --- a/dart/test/protocol/sentry_stack_trace_test.dart +++ b/dart/test/protocol/sentry_stack_trace_test.dart @@ -2,10 +2,13 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final sentryStackTrace = SentryStackTrace( frames: [SentryStackFrame(absPath: 'abs')], registers: {'key': 'value'}, + unknown: testUnknown, ); final sentryStackTraceJson = { @@ -14,6 +17,7 @@ void main() { ], 'registers': {'key': 'value'}, }; + sentryStackTraceJson.addAll(testUnknown); group('json', () { test('toJson', () { From 7ef81098eda29787755a97ae32f6f1b16b53a4c3 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 15 Jul 2024 14:31:08 +0200 Subject: [PATCH 24/43] Add `unknown` map to `SentryThread` --- dart/lib/src/protocol/sentry_thread.dart | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/protocol/sentry_thread.dart b/dart/lib/src/protocol/sentry_thread.dart index c6ce13c15a..157cf1370d 100644 --- a/dart/lib/src/protocol/sentry_thread.dart +++ b/dart/lib/src/protocol/sentry_thread.dart @@ -1,6 +1,7 @@ import 'package:meta/meta.dart'; import 'sentry_stack_trace.dart'; +import 'unknown.dart'; /// The Threads Interface specifies threads that were running at the time an /// event happened. These threads can also contain stack traces. @@ -13,6 +14,7 @@ class SentryThread { this.crashed, this.current, this.stacktrace, + this.unknown, }); factory SentryThread.fromJson(Map json) { @@ -23,6 +25,13 @@ class SentryThread { current: json['current'] as bool?, stacktrace: json['stacktrace'] == null ? null : SentryStackTrace.fromJson(json), + unknown: unknownFrom(json, { + 'id', + 'name', + 'crashed', + 'current', + 'stacktrace', + }), ); } @@ -44,15 +53,22 @@ class SentryThread { /// See https://develop.sentry.dev/sdk/event-payloads/stacktrace/ final SentryStackTrace? stacktrace; + @internal + final Map? unknown; + Map toJson() { final stacktrace = this.stacktrace; - return { + final json = { if (id != null) 'id': id, if (name != null) 'name': name, if (crashed != null) 'crashed': crashed, if (current != null) 'current': current, if (stacktrace != null) 'stacktrace': stacktrace.toJson(), }; + if (unknown != null) { + json.addAll(unknown ?? {}); + } + return json; } SentryThread copyWith({ @@ -68,6 +84,7 @@ class SentryThread { crashed: crashed ?? this.crashed, current: current ?? this.current, stacktrace: stacktrace ?? this.stacktrace, + unknown: unknown, ); } } From ee6494ac0e60c1a16b41180fdce7854a80cc3dc6 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 15 Jul 2024 14:38:42 +0200 Subject: [PATCH 25/43] Add `unknown` map to `SentryTraceContext` --- .../src/protocol/sentry_trace_context.dart | 21 ++++++++++++++++++- dart/test/sentry_trace_context_test.dart | 19 ++++++++++------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/dart/lib/src/protocol/sentry_trace_context.dart b/dart/lib/src/protocol/sentry_trace_context.dart index 25c4ca7ad8..54ac15b1fb 100644 --- a/dart/lib/src/protocol/sentry_trace_context.dart +++ b/dart/lib/src/protocol/sentry_trace_context.dart @@ -3,6 +3,7 @@ import 'package:meta/meta.dart'; import '../../sentry.dart'; import '../propagation_context.dart'; import '../protocol.dart'; +import 'unknown.dart'; @immutable class SentryTraceContext { @@ -37,6 +38,9 @@ class SentryTraceContext { /// @see final String? origin; + @internal + final Map? unknown; + factory SentryTraceContext.fromJson(Map json) { return SentryTraceContext( operation: json['op'] as String, @@ -51,12 +55,21 @@ class SentryTraceContext { : SpanStatus.fromString(json['status'] as String), sampled: true, origin: json['origin'] == null ? null : json['origin'] as String?, + unknown: unknownFrom(json, { + 'op', + 'span_id', + 'parent_span_id', + 'trace_id', + 'description', + 'status', + 'origin', + }), ); } /// Item encoded as JSON Map toJson() { - return { + final json = { 'span_id': spanId.toString(), 'trace_id': traceId.toString(), 'op': operation, @@ -65,6 +78,10 @@ class SentryTraceContext { if (status != null) 'status': status!.toString(), if (origin != null) 'origin': origin, }; + if (unknown != null) { + json.addAll(unknown ?? {}); + } + return json; } SentryTraceContext clone() => SentryTraceContext( @@ -76,6 +93,7 @@ class SentryTraceContext { parentSpanId: parentSpanId, sampled: sampled, origin: origin, + unknown: unknown, ); SentryTraceContext({ @@ -87,6 +105,7 @@ class SentryTraceContext { this.description, this.status, this.origin, + this.unknown, }) : traceId = traceId ?? SentryId.newId(), spanId = spanId ?? SpanId.newId(); diff --git a/dart/test/sentry_trace_context_test.dart b/dart/test/sentry_trace_context_test.dart index dde599bef1..9030b48182 100644 --- a/dart/test/sentry_trace_context_test.dart +++ b/dart/test/sentry_trace_context_test.dart @@ -1,6 +1,8 @@ import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import 'mocks.dart'; + void main() { final fixture = Fixture(); @@ -19,7 +21,7 @@ void main() { }); test('fromJson deserializes', () { - final map = { + final map = { 'op': 'op', 'span_id': '0000000000000000', 'trace_id': '00000000000000000000000000000000', @@ -28,6 +30,7 @@ void main() { 'status': 'aborted', 'origin': 'auto.ui' }; + map.addAll(testUnknown); final traceContext = SentryTraceContext.fromJson(map); expect(traceContext.description, 'desc'); @@ -43,11 +46,13 @@ void main() { class Fixture { SentryTraceContext getSut() { return SentryTraceContext( - operation: 'op', - parentSpanId: SpanId.newId(), - description: 'desc', - sampled: true, - status: SpanStatus.aborted(), - origin: 'auto.ui'); + operation: 'op', + parentSpanId: SpanId.newId(), + description: 'desc', + sampled: true, + status: SpanStatus.aborted(), + origin: 'auto.ui', + unknown: testUnknown, + ); } } From 33ea294b0e4047c778e9883e8ae32e5bbe1c1ff6 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 15 Jul 2024 14:46:04 +0200 Subject: [PATCH 26/43] Add `unknown` map to `SentryTraceContextHeader` --- dart/lib/src/sentry_trace_context_header.dart | 24 ++++++++++++++++- .../sentry_trace_context_header_test.dart | 26 +++++++++++++++---- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/dart/lib/src/sentry_trace_context_header.dart b/dart/lib/src/sentry_trace_context_header.dart index d1ee5368af..dd91f17c7c 100644 --- a/dart/lib/src/sentry_trace_context_header.dart +++ b/dart/lib/src/sentry_trace_context_header.dart @@ -1,4 +1,7 @@ +import 'package:meta/meta.dart'; + import 'protocol/sentry_id.dart'; +import 'protocol/unknown.dart'; import 'sentry_baggage.dart'; import 'sentry_options.dart'; @@ -13,6 +16,7 @@ class SentryTraceContextHeader { this.transaction, this.sampleRate, this.sampled, + this.unknown, }); final SentryId traceId; @@ -27,6 +31,9 @@ class SentryTraceContextHeader { final String? sampleRate; final String? sampled; + @internal + final Map? unknown; + /// Deserializes a [SentryTraceContextHeader] from JSON [Map]. factory SentryTraceContextHeader.fromJson(Map json) { return SentryTraceContextHeader( @@ -39,12 +46,23 @@ class SentryTraceContextHeader { transaction: json['transaction'], sampleRate: json['sample_rate'], sampled: json['sampled'], + unknown: unknownFrom(json, { + 'trace_id', + 'public_key', + 'release', + 'environment', + 'user_id', + 'user_segment', + 'transaction', + 'sample_rate', + 'sampled', + }), ); } /// Produces a [Map] that can be serialized to JSON. Map toJson() { - return { + final json = { 'trace_id': traceId.toString(), 'public_key': publicKey, if (release != null) 'release': release, @@ -56,6 +74,10 @@ class SentryTraceContextHeader { if (sampleRate != null) 'sample_rate': sampleRate, if (sampled != null) 'sampled': sampled, }; + if (unknown != null) { + json.addAll(unknown ?? {}); + } + return json; } SentryBaggage toBaggage({ diff --git a/dart/test/sentry_trace_context_header_test.dart b/dart/test/sentry_trace_context_header_test.dart index c4f856f344..db9a2d3621 100644 --- a/dart/test/sentry_trace_context_header_test.dart +++ b/dart/test/sentry_trace_context_header_test.dart @@ -2,11 +2,27 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import 'mocks.dart'; + void main() { group('$SentryTraceContextHeader', () { - final id = SentryId.newId(); + final traceId = SentryId.newId(); + + final context = SentryTraceContextHeader( + traceId, + '123', + release: 'release', + environment: 'environment', + userId: 'user_id', + userSegment: 'user_segment', + transaction: 'transaction', + sampleRate: '1.0', + sampled: 'false', + unknown: testUnknown, + ); + final mapJson = { - 'trace_id': '$id', + 'trace_id': '$traceId', 'public_key': '123', 'release': 'release', 'environment': 'environment', @@ -16,10 +32,10 @@ void main() { 'sample_rate': '1.0', 'sampled': 'false' }; - final context = SentryTraceContextHeader.fromJson(mapJson); + mapJson.addAll(testUnknown); test('fromJson', () { - expect(context.traceId.toString(), id.toString()); + expect(context.traceId.toString(), traceId.toString()); expect(context.publicKey, '123'); expect(context.release, 'release'); expect(context.environment, 'environment'); @@ -41,7 +57,7 @@ void main() { final baggage = context.toBaggage(); expect(baggage.toHeaderString(), - 'sentry-trace_id=${id.toString()},sentry-public_key=123,sentry-release=release,sentry-environment=environment,sentry-user_id=user_id,sentry-user_segment=user_segment,sentry-transaction=transaction,sentry-sample_rate=1.0,sentry-sampled=false'); + 'sentry-trace_id=${traceId.toString()},sentry-public_key=123,sentry-release=release,sentry-environment=environment,sentry-user_id=user_id,sentry-user_segment=user_segment,sentry-transaction=transaction,sentry-sample_rate=1.0,sentry-sampled=false'); }); }); } From 934004e0c8b4cfa0a00b1bfede8cd560a39ce1dd Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 15 Jul 2024 14:50:53 +0200 Subject: [PATCH 27/43] Add `unknown` map to `SentryTransactionInf` --- .../src/protocol/sentry_transaction_info.dart | 17 +++++++++++++++-- .../protocol/sentry_transaction_info_test.dart | 14 +++++++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/dart/lib/src/protocol/sentry_transaction_info.dart b/dart/lib/src/protocol/sentry_transaction_info.dart index 96b520eb5a..3e302dfcd5 100644 --- a/dart/lib/src/protocol/sentry_transaction_info.dart +++ b/dart/lib/src/protocol/sentry_transaction_info.dart @@ -1,12 +1,23 @@ +import 'package:meta/meta.dart'; + +import 'unknown.dart'; + class SentryTransactionInfo { - SentryTransactionInfo(this.source); + SentryTransactionInfo(this.source, {this.unknown}); final String source; + @internal + final Map? unknown; + Map toJson() { - return { + final json = { 'source': source, }; + if (unknown != null) { + json.addAll(unknown ?? {}); + } + return json; } SentryTransactionInfo copyWith({ @@ -14,12 +25,14 @@ class SentryTransactionInfo { }) { return SentryTransactionInfo( source ?? this.source, + unknown: unknown, ); } factory SentryTransactionInfo.fromJson(Map json) { return SentryTransactionInfo( json['source'], + unknown: unknownFrom(json, {'source'}), ); } } diff --git a/dart/test/protocol/sentry_transaction_info_test.dart b/dart/test/protocol/sentry_transaction_info_test.dart index 951fb08453..31438d820c 100644 --- a/dart/test/protocol/sentry_transaction_info_test.dart +++ b/dart/test/protocol/sentry_transaction_info_test.dart @@ -1,16 +1,24 @@ import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { group('$SentryTransactionInfo', () { + final info = SentryTransactionInfo( + 'component', + unknown: testUnknown, + ); + + final json = {'source': 'component'}; + json.addAll(testUnknown); + test('returns source', () { - final info = SentryTransactionInfo('component'); expect(info.source, 'component'); }); test('toJson has source', () { - final info = SentryTransactionInfo('component'); - expect(info.toJson(), {'source': 'component'}); + expect(info.toJson(), json); }); test('fromJson has source', () { From fbb0fad7dd98cce0abe2ed420479a74074ae7dbb Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 15 Jul 2024 14:54:56 +0200 Subject: [PATCH 28/43] Add `unknown` map to `SentryUser` --- dart/lib/src/protocol/sentry_user.dart | 23 ++++++++++++++++++++++- dart/test/protocol/sentry_user_test.dart | 4 ++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/protocol/sentry_user.dart b/dart/lib/src/protocol/sentry_user.dart index c173432fcd..c952ba3db2 100644 --- a/dart/lib/src/protocol/sentry_user.dart +++ b/dart/lib/src/protocol/sentry_user.dart @@ -1,6 +1,7 @@ import 'package:meta/meta.dart'; import '../../sentry.dart'; +import 'unknown.dart'; /// Describes the current user associated with the application, such as the /// currently signed in user. @@ -44,6 +45,7 @@ class SentryUser { Map? data, @Deprecated('Will be removed in v8. Use [data] instead') Map? extras, + this.unknown, }) : assert( id != null || username != null || @@ -92,6 +94,9 @@ class SentryUser { /// Human readable name of the user. final String? name; + @internal + final Map? unknown; + /// Deserializes a [SentryUser] from JSON [Map]. factory SentryUser.fromJson(Map json) { var extras = json['extras']; @@ -120,13 +125,24 @@ class SentryUser { name: json['name'], // ignore: deprecated_member_use_from_same_package extras: extras, + unknown: unknownFrom(json, { + 'id', + 'username', + 'email', + 'ip_address', + 'segment', + 'data', + 'geo', + 'name', + 'extras', + }), ); } /// Produces a [Map] that can be serialized to JSON. Map toJson() { final geoJson = geo?.toJson(); - return { + final json = { if (id != null) 'id': id, if (username != null) 'username': username, if (email != null) 'email': email, @@ -139,6 +155,10 @@ class SentryUser { if (name != null) 'name': name, if (geoJson != null && geoJson.isNotEmpty) 'geo': geoJson, }; + if (unknown != null) { + json.addAll(unknown ?? {}); + } + return json; } SentryUser copyWith({ @@ -165,6 +185,7 @@ class SentryUser { extras: extras ?? this.extras, geo: geo ?? this.geo, name: name ?? this.name, + unknown: unknown, ); } } diff --git a/dart/test/protocol/sentry_user_test.dart b/dart/test/protocol/sentry_user_test.dart index d3c8e078ba..1ffe284aee 100644 --- a/dart/test/protocol/sentry_user_test.dart +++ b/dart/test/protocol/sentry_user_test.dart @@ -2,6 +2,8 @@ import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; +import '../mocks.dart'; + void main() { final sentryUser = SentryUser( id: 'id', @@ -10,6 +12,7 @@ void main() { ipAddress: 'ipAddress', data: {'key': 'value'}, segment: 'seg', + unknown: testUnknown, ); final sentryUserJson = { @@ -20,6 +23,7 @@ void main() { 'data': {'key': 'value'}, 'segment': 'seg', }; + sentryUserJson.addAll(testUnknown); group('json', () { test('toJson', () { From 7953f45a7950d279e9fab0ccb949a08fd326b607 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 15 Jul 2024 15:03:40 +0200 Subject: [PATCH 29/43] Add `unknown` map to `SentryUserFeedback` --- dart/lib/src/sentry_user_feedback.dart | 20 +++++++- dart/test/sentry_user_feedback_test.dart | 62 ++++++++++++++---------- 2 files changed, 56 insertions(+), 26 deletions(-) diff --git a/dart/lib/src/sentry_user_feedback.dart b/dart/lib/src/sentry_user_feedback.dart index 7ba8c0d6f1..f4b034fc96 100644 --- a/dart/lib/src/sentry_user_feedback.dart +++ b/dart/lib/src/sentry_user_feedback.dart @@ -1,4 +1,7 @@ +import 'package:meta/meta.dart'; + import 'protocol.dart'; +import 'protocol/unknown.dart'; class SentryUserFeedback { SentryUserFeedback({ @@ -6,6 +9,7 @@ class SentryUserFeedback { this.name, this.email, this.comments, + this.unknown, }) : assert(eventId != SentryId.empty() && (name?.isNotEmpty == true || email?.isNotEmpty == true || @@ -17,6 +21,12 @@ class SentryUserFeedback { name: json['name'], email: json['email'], comments: json['comments'], + unknown: unknownFrom(json, { + 'event_id', + 'name', + 'email', + 'comments', + }), ); } @@ -32,13 +42,20 @@ class SentryUserFeedback { /// Recommended: Comments of the user about what happened. final String? comments; + @internal + final Map? unknown; + Map toJson() { - return { + final json = { 'event_id': eventId.toString(), if (name != null) 'name': name, if (email != null) 'email': email, if (comments != null) 'comments': comments, }; + if (unknown != null) { + json.addAll(unknown ?? {}); + } + return json; } SentryUserFeedback copyWith({ @@ -52,6 +69,7 @@ class SentryUserFeedback { name: name ?? this.name, email: email ?? this.email, comments: comments ?? this.comments, + unknown: unknown, ); } } diff --git a/dart/test/sentry_user_feedback_test.dart b/dart/test/sentry_user_feedback_test.dart index 6051798b65..6a27f2644e 100644 --- a/dart/test/sentry_user_feedback_test.dart +++ b/dart/test/sentry_user_feedback_test.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; import 'package:sentry/src/sentry_item_type.dart'; import 'package:test/test.dart'; @@ -7,35 +8,39 @@ import 'mocks/mock_transport.dart'; void main() { group('$SentryUserFeedback', () { + final id = SentryId.newId(); + + final feedback = SentryUserFeedback( + eventId: id, + comments: 'this is awesome', + email: 'sentry@example.com', + name: 'Rockstar Developer', + unknown: testUnknown, + ); + final feedbackJson = { + 'event_id': id.toString(), + 'comments': 'this is awesome', + 'email': 'sentry@example.com', + 'name': 'Rockstar Developer', + }; + feedbackJson.addAll(testUnknown); + test('toJson', () { - final id = SentryId.newId(); - final feedback = SentryUserFeedback( - eventId: id, - comments: 'this is awesome', - email: 'sentry@example.com', - name: 'Rockstar Developer', + final json = feedback.toJson(); + expect( + MapEquality().equals(feedbackJson, json), + true, ); - expect(feedback.toJson(), { - 'event_id': id.toString(), - 'comments': 'this is awesome', - 'email': 'sentry@example.com', - 'name': 'Rockstar Developer', - }); }); test('fromJson', () { - final id = SentryId.newId(); - final feedback = SentryUserFeedback.fromJson({ - 'event_id': id.toString(), - 'comments': 'this is awesome', - 'email': 'sentry@example.com', - 'name': 'Rockstar Developer', - }); - - expect(feedback.eventId.toString(), id.toString()); - expect(feedback.comments, 'this is awesome'); - expect(feedback.email, 'sentry@example.com'); - expect(feedback.name, 'Rockstar Developer'); + final feedback = SentryRuntime.fromJson(feedbackJson); + final json = feedback.toJson(); + + expect( + MapEquality().equals(feedbackJson, json), + true, + ); }); test('copyWith', () { @@ -169,6 +174,7 @@ class SentryUserFeedbackWithoutAssert implements SentryUserFeedback { this.name, this.email, this.comments, + this.unknown, }); @override @@ -183,14 +189,19 @@ class SentryUserFeedbackWithoutAssert implements SentryUserFeedback { @override final String? comments; + @override + Map? unknown; + @override Map toJson() { - return { + final json = { 'event_id': eventId.toString(), if (name != null) 'name': name, if (email != null) 'email': email, if (comments != null) 'comments': comments, }; + json.addAll(unknown ?? {}); + return json; } @override @@ -205,6 +216,7 @@ class SentryUserFeedbackWithoutAssert implements SentryUserFeedback { name: name ?? this.name, email: email ?? this.email, comments: comments ?? this.comments, + unknown: unknown, ); } } From cf6e461c882bd54baa0bd9de593f09b7fe3f3a24 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 15 Jul 2024 15:11:07 +0200 Subject: [PATCH 30/43] Add missing u param --- dart/lib/src/protocol/sentry_runtime.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/dart/lib/src/protocol/sentry_runtime.dart b/dart/lib/src/protocol/sentry_runtime.dart index 6b966dc402..f01e7cd69c 100644 --- a/dart/lib/src/protocol/sentry_runtime.dart +++ b/dart/lib/src/protocol/sentry_runtime.dart @@ -88,6 +88,7 @@ class SentryRuntime { compiler: compiler, rawDescription: rawDescription, build: build, + unknown: unknown, ); SentryRuntime copyWith({ From 41026d20362c78012f995e83a7fca1e964e84a51 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 15 Jul 2024 15:13:15 +0200 Subject: [PATCH 31/43] add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3149156e2..965afd87f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ ### Improvements - Set dart runtime version with parsed `Platform.version` ([#2156](https://github.com/getsentry/sentry-dart/pull/2156)) +- Deserialize and serialize unknown fields ([#2153](https://github.com/getsentry/sentry-dart/pull/2153)) ### Dependencies From 6d7dd338d4f1730a5d664736d4c64ac13cfe3ac5 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 15 Jul 2024 15:14:00 +0200 Subject: [PATCH 32/43] run dart fix --- dart/lib/src/protocol/sentry_request.dart | 2 +- dart/lib/src/protocol/sentry_stack_frame.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dart/lib/src/protocol/sentry_request.dart b/dart/lib/src/protocol/sentry_request.dart index eb5a22a5cb..c03cb8e68c 100644 --- a/dart/lib/src/protocol/sentry_request.dart +++ b/dart/lib/src/protocol/sentry_request.dart @@ -1,5 +1,5 @@ import 'package:meta/meta.dart'; -import 'package:sentry/src/protocol/unknown.dart'; +import 'unknown.dart'; import '../utils/iterable_utils.dart'; import '../utils/http_sanitizer.dart'; diff --git a/dart/lib/src/protocol/sentry_stack_frame.dart b/dart/lib/src/protocol/sentry_stack_frame.dart index f31f2eb468..5721a071cc 100644 --- a/dart/lib/src/protocol/sentry_stack_frame.dart +++ b/dart/lib/src/protocol/sentry_stack_frame.dart @@ -1,5 +1,5 @@ import 'package:meta/meta.dart'; -import 'package:sentry/src/protocol/unknown.dart'; +import 'unknown.dart'; /// Frames belong to a StackTrace /// It should contain at least a filename, function or instruction_addr From 49341c1c3165ef91627b4798592fab1f7a0caf6f Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 15 Jul 2024 15:26:19 +0200 Subject: [PATCH 33/43] add missing properties to SentryStackTrace copyWith --- dart/lib/src/protocol/sentry_stack_trace.dart | 4 ++++ dart/test/protocol/sentry_stack_trace_test.dart | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/dart/lib/src/protocol/sentry_stack_trace.dart b/dart/lib/src/protocol/sentry_stack_trace.dart index d31a297d53..a90bffeb47 100644 --- a/dart/lib/src/protocol/sentry_stack_trace.dart +++ b/dart/lib/src/protocol/sentry_stack_trace.dart @@ -84,10 +84,14 @@ class SentryStackTrace { SentryStackTrace copyWith({ List? frames, Map? registers, + String? lang, + bool? snapshot, }) => SentryStackTrace( frames: frames ?? this.frames, registers: registers ?? this.registers, + lang: lang ?? this.lang, + snapshot: snapshot ?? this.snapshot, unknown: unknown, ); } diff --git a/dart/test/protocol/sentry_stack_trace_test.dart b/dart/test/protocol/sentry_stack_trace_test.dart index 35388ec2cb..4c40032381 100644 --- a/dart/test/protocol/sentry_stack_trace_test.dart +++ b/dart/test/protocol/sentry_stack_trace_test.dart @@ -8,6 +8,8 @@ void main() { final sentryStackTrace = SentryStackTrace( frames: [SentryStackFrame(absPath: 'abs')], registers: {'key': 'value'}, + lang: 'de', + snapshot: true, unknown: testUnknown, ); @@ -16,6 +18,8 @@ void main() { {'abs_path': 'abs'} ], 'registers': {'key': 'value'}, + 'lang': 'de', + 'snapshot': true, }; sentryStackTraceJson.addAll(testUnknown); From 7a2dc8b838d8182bc228407a4ca3c323fb7f1215 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 15 Jul 2024 15:48:30 +0200 Subject: [PATCH 34/43] fix test --- dart/lib/src/protocol/sentry_request.dart | 4 +--- dart/lib/src/protocol/sentry_runtime.dart | 4 +--- dart/lib/src/protocol/sentry_stack_frame.dart | 4 +--- dart/lib/src/protocol/sentry_stack_trace.dart | 4 +--- dart/lib/src/protocol/sentry_thread.dart | 4 +--- dart/lib/src/protocol/sentry_trace_context.dart | 4 +--- dart/lib/src/protocol/sentry_transaction_info.dart | 4 +--- dart/lib/src/protocol/sentry_user.dart | 4 +--- dart/lib/src/sentry_trace_context_header.dart | 4 +--- dart/lib/src/sentry_user_feedback.dart | 4 +--- dart/test/contexts_test.dart | 1 - 11 files changed, 10 insertions(+), 31 deletions(-) diff --git a/dart/lib/src/protocol/sentry_request.dart b/dart/lib/src/protocol/sentry_request.dart index c03cb8e68c..0fd115b6f4 100644 --- a/dart/lib/src/protocol/sentry_request.dart +++ b/dart/lib/src/protocol/sentry_request.dart @@ -167,9 +167,7 @@ class SentryRequest { if (fragment != null) 'fragment': fragment, if (apiTarget != null) 'api_target': apiTarget, }; - if (unknown != null) { - json.addAll(unknown ?? {}); - } + json.addAll(unknown ?? {}); return json; } diff --git a/dart/lib/src/protocol/sentry_runtime.dart b/dart/lib/src/protocol/sentry_runtime.dart index f01e7cd69c..f36194b9ce 100644 --- a/dart/lib/src/protocol/sentry_runtime.dart +++ b/dart/lib/src/protocol/sentry_runtime.dart @@ -75,9 +75,7 @@ class SentryRuntime { if (rawDescription != null) 'raw_description': rawDescription, if (build != null) 'build': build, }; - if (unknown != null) { - json.addAll(unknown ?? {}); - } + json.addAll(unknown ?? {}); return json; } diff --git a/dart/lib/src/protocol/sentry_stack_frame.dart b/dart/lib/src/protocol/sentry_stack_frame.dart index 5721a071cc..ddbd86f94d 100644 --- a/dart/lib/src/protocol/sentry_stack_frame.dart +++ b/dart/lib/src/protocol/sentry_stack_frame.dart @@ -204,9 +204,7 @@ class SentryStackFrame { if (symbol != null) 'symbol': symbol, if (stackStart != null) 'stack_start': stackStart, }; - if (unknown != null) { - json.addAll(unknown ?? {}); - } + json.addAll(unknown ?? {}); return json; } diff --git a/dart/lib/src/protocol/sentry_stack_trace.dart b/dart/lib/src/protocol/sentry_stack_trace.dart index a90bffeb47..a0dfa1b6d1 100644 --- a/dart/lib/src/protocol/sentry_stack_trace.dart +++ b/dart/lib/src/protocol/sentry_stack_trace.dart @@ -75,9 +75,7 @@ class SentryStackTrace { if (lang != null) 'lang': lang, if (snapshot != null) 'snapshot': snapshot, }; - if (unknown != null) { - json.addAll(unknown ?? {}); - } + json.addAll(unknown ?? {}); return json; } diff --git a/dart/lib/src/protocol/sentry_thread.dart b/dart/lib/src/protocol/sentry_thread.dart index 157cf1370d..471ce072ce 100644 --- a/dart/lib/src/protocol/sentry_thread.dart +++ b/dart/lib/src/protocol/sentry_thread.dart @@ -65,9 +65,7 @@ class SentryThread { if (current != null) 'current': current, if (stacktrace != null) 'stacktrace': stacktrace.toJson(), }; - if (unknown != null) { - json.addAll(unknown ?? {}); - } + json.addAll(unknown ?? {}); return json; } diff --git a/dart/lib/src/protocol/sentry_trace_context.dart b/dart/lib/src/protocol/sentry_trace_context.dart index 54ac15b1fb..25bf471fc5 100644 --- a/dart/lib/src/protocol/sentry_trace_context.dart +++ b/dart/lib/src/protocol/sentry_trace_context.dart @@ -78,9 +78,7 @@ class SentryTraceContext { if (status != null) 'status': status!.toString(), if (origin != null) 'origin': origin, }; - if (unknown != null) { - json.addAll(unknown ?? {}); - } + json.addAll(unknown ?? {}); return json; } diff --git a/dart/lib/src/protocol/sentry_transaction_info.dart b/dart/lib/src/protocol/sentry_transaction_info.dart index 3e302dfcd5..37c7c62077 100644 --- a/dart/lib/src/protocol/sentry_transaction_info.dart +++ b/dart/lib/src/protocol/sentry_transaction_info.dart @@ -14,9 +14,7 @@ class SentryTransactionInfo { final json = { 'source': source, }; - if (unknown != null) { - json.addAll(unknown ?? {}); - } + json.addAll(unknown ?? {}); return json; } diff --git a/dart/lib/src/protocol/sentry_user.dart b/dart/lib/src/protocol/sentry_user.dart index c952ba3db2..0895d21d6f 100644 --- a/dart/lib/src/protocol/sentry_user.dart +++ b/dart/lib/src/protocol/sentry_user.dart @@ -155,9 +155,7 @@ class SentryUser { if (name != null) 'name': name, if (geoJson != null && geoJson.isNotEmpty) 'geo': geoJson, }; - if (unknown != null) { - json.addAll(unknown ?? {}); - } + json.addAll(unknown ?? {}); return json; } diff --git a/dart/lib/src/sentry_trace_context_header.dart b/dart/lib/src/sentry_trace_context_header.dart index dd91f17c7c..d3724c82f4 100644 --- a/dart/lib/src/sentry_trace_context_header.dart +++ b/dart/lib/src/sentry_trace_context_header.dart @@ -74,9 +74,7 @@ class SentryTraceContextHeader { if (sampleRate != null) 'sample_rate': sampleRate, if (sampled != null) 'sampled': sampled, }; - if (unknown != null) { - json.addAll(unknown ?? {}); - } + json.addAll(unknown ?? {}); return json; } diff --git a/dart/lib/src/sentry_user_feedback.dart b/dart/lib/src/sentry_user_feedback.dart index f4b034fc96..93a8e04463 100644 --- a/dart/lib/src/sentry_user_feedback.dart +++ b/dart/lib/src/sentry_user_feedback.dart @@ -52,9 +52,7 @@ class SentryUserFeedback { if (email != null) 'email': email, if (comments != null) 'comments': comments, }; - if (unknown != null) { - json.addAll(unknown ?? {}); - } + json.addAll(unknown ?? {}); return json; } diff --git a/dart/test/contexts_test.dart b/dart/test/contexts_test.dart index 7cce3a79ea..bd975960dd 100644 --- a/dart/test/contexts_test.dart +++ b/dart/test/contexts_test.dart @@ -224,7 +224,6 @@ const jsonContexts = ''' "memory_size": 17179869184, "storage_size": 1023683072000, "boot_time": "2020-11-18T13:28:11Z", - "timezone": "GMT+1", "usable_memory": 17114120192 }, "app": { From 14588ad1fd2d8f60cd7bbcafde8492e78e5e5378 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 15 Jul 2024 16:01:56 +0200 Subject: [PATCH 35/43] add missing field --- dart/test/contexts_test.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/dart/test/contexts_test.dart b/dart/test/contexts_test.dart index bd975960dd..31cc55b7cd 100644 --- a/dart/test/contexts_test.dart +++ b/dart/test/contexts_test.dart @@ -173,6 +173,7 @@ void main() { MapEquality().equals( contexts.app!.toJson(), { + 'app_id': 'D533244D-985D-3996-9FC2-9FA353D28586', 'app_name': 'sentry_flutter_example', 'app_version': '0.1.2', 'app_identifier': 'io.sentry.flutter.example', From 1aab0d48a2b43747de39f342e2f4e2823efeb7e9 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 16 Jul 2024 10:26:33 +0200 Subject: [PATCH 36/43] Use spread operator to add unknown fields --- dart/lib/src/protocol/breadcrumb.dart | 5 ++--- dart/lib/src/protocol/debug_image.dart | 5 ++--- dart/lib/src/protocol/debug_meta.dart | 7 +++---- dart/lib/src/protocol/mechanism.dart | 5 ++--- dart/lib/src/protocol/metric_summary.dart | 5 ++--- dart/lib/src/protocol/sdk_info.dart | 5 ++--- dart/lib/src/protocol/sdk_version.dart | 5 ++--- dart/lib/src/protocol/sentry_app.dart | 5 ++--- dart/lib/src/protocol/sentry_browser.dart | 5 ++--- dart/lib/src/protocol/sentry_culture.dart | 5 ++--- dart/lib/src/protocol/sentry_device.dart | 5 ++--- dart/lib/src/protocol/sentry_event.dart | 5 ++--- dart/lib/src/protocol/sentry_exception.dart | 5 ++--- dart/lib/src/protocol/sentry_gpu.dart | 5 ++--- dart/lib/src/protocol/sentry_message.dart | 5 ++--- dart/lib/src/protocol/sentry_operating_system.dart | 5 ++--- dart/lib/src/protocol/sentry_package.dart | 5 ++--- dart/lib/src/protocol/sentry_request.dart | 5 ++--- dart/lib/src/protocol/sentry_runtime.dart | 5 ++--- dart/lib/src/protocol/sentry_stack_frame.dart | 5 ++--- dart/lib/src/protocol/sentry_stack_trace.dart | 5 ++--- dart/lib/src/protocol/sentry_thread.dart | 5 ++--- dart/lib/src/protocol/sentry_trace_context.dart | 5 ++--- dart/lib/src/protocol/sentry_transaction_info.dart | 5 ++--- dart/lib/src/protocol/sentry_user.dart | 5 ++--- dart/lib/src/sentry_trace_context_header.dart | 5 ++--- dart/lib/src/sentry_user_feedback.dart | 5 ++--- dart/test/sentry_user_feedback_test.dart | 5 ++--- 28 files changed, 57 insertions(+), 85 deletions(-) diff --git a/dart/lib/src/protocol/breadcrumb.dart b/dart/lib/src/protocol/breadcrumb.dart index dd6868fd85..675e33d6bb 100644 --- a/dart/lib/src/protocol/breadcrumb.dart +++ b/dart/lib/src/protocol/breadcrumb.dart @@ -191,16 +191,15 @@ class Breadcrumb { /// Converts this breadcrumb to a map that can be serialized to JSON according /// to the Sentry protocol. Map toJson() { - final json = { + return { 'timestamp': formatDateAsIso8601WithMillisPrecision(timestamp), if (message != null) 'message': message, if (category != null) 'category': category, if (data?.isNotEmpty ?? false) 'data': data, if (level != null) 'level': level!.name, if (type != null) 'type': type, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } Breadcrumb copyWith({ diff --git a/dart/lib/src/protocol/debug_image.dart b/dart/lib/src/protocol/debug_image.dart index 64862ea157..cf8f9e6689 100644 --- a/dart/lib/src/protocol/debug_image.dart +++ b/dart/lib/src/protocol/debug_image.dart @@ -109,7 +109,7 @@ class DebugImage { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { 'type': type, if (uuid != null) 'uuid': uuid, if (debugId != null) 'debug_id': debugId, @@ -123,9 +123,8 @@ class DebugImage { if (codeId != null) 'code_id': codeId, if (cpuType != null) 'cpu_type': cpuType, if (cpuSubtype != null) 'cpu_subtype': cpuSubtype, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } DebugImage copyWith({ diff --git a/dart/lib/src/protocol/debug_meta.dart b/dart/lib/src/protocol/debug_meta.dart index 908be86c48..6475469003 100644 --- a/dart/lib/src/protocol/debug_meta.dart +++ b/dart/lib/src/protocol/debug_meta.dart @@ -40,16 +40,15 @@ class DebugMeta { /// Produces a [Map] that can be serialized to JSON. Map toJson() { final sdkInfo = sdk?.toJson(); - final json = { + return { 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), + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } DebugMeta copyWith({ diff --git a/dart/lib/src/protocol/mechanism.dart b/dart/lib/src/protocol/mechanism.dart index 5cc5018fa1..cd2d165810 100644 --- a/dart/lib/src/protocol/mechanism.dart +++ b/dart/lib/src/protocol/mechanism.dart @@ -167,7 +167,7 @@ class Mechanism { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { 'type': type, if (description != null) 'description': description, if (helpLink != null) 'help_link': helpLink, @@ -179,8 +179,7 @@ class Mechanism { if (source != null) 'source': source, if (exceptionId != null) 'exception_id': exceptionId, if (parentId != null) 'parent_id': parentId, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } } diff --git a/dart/lib/src/protocol/metric_summary.dart b/dart/lib/src/protocol/metric_summary.dart index 9396ad1fe7..555a292d5b 100644 --- a/dart/lib/src/protocol/metric_summary.dart +++ b/dart/lib/src/protocol/metric_summary.dart @@ -46,14 +46,13 @@ class MetricSummary { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { 'min': min, 'max': max, 'count': count, 'sum': sum, if (tags?.isNotEmpty ?? false) 'tags': tags, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } } diff --git a/dart/lib/src/protocol/sdk_info.dart b/dart/lib/src/protocol/sdk_info.dart index dd69217bbf..f7312c334a 100644 --- a/dart/lib/src/protocol/sdk_info.dart +++ b/dart/lib/src/protocol/sdk_info.dart @@ -39,14 +39,13 @@ class SdkInfo { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { if (sdkName != null) 'sdk_name': sdkName, if (versionMajor != null) 'version_major': versionMajor, if (versionMinor != null) 'version_minor': versionMinor, if (versionPatchlevel != null) 'version_patchlevel': versionPatchlevel, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SdkInfo copyWith({ diff --git a/dart/lib/src/protocol/sdk_version.dart b/dart/lib/src/protocol/sdk_version.dart index 6154225ac9..5f4f63b5ae 100644 --- a/dart/lib/src/protocol/sdk_version.dart +++ b/dart/lib/src/protocol/sdk_version.dart @@ -87,15 +87,14 @@ class SdkVersion { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final Map json = { + return { 'name': name, 'version': version, if (packages.isNotEmpty) 'packages': packages.map((p) => p.toJson()).toList(growable: false), if (integrations.isNotEmpty) 'integrations': integrations, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } /// Adds a package diff --git a/dart/lib/src/protocol/sentry_app.dart b/dart/lib/src/protocol/sentry_app.dart index d302a63623..b08f9e40a3 100644 --- a/dart/lib/src/protocol/sentry_app.dart +++ b/dart/lib/src/protocol/sentry_app.dart @@ -96,7 +96,7 @@ class SentryApp { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final Map json = { + return { if (name != null) 'app_name': name!, if (version != null) 'app_version': version!, if (identifier != null) 'app_identifier': identifier!, @@ -108,9 +108,8 @@ class SentryApp { if (inForeground != null) 'in_foreground': inForeground!, if (viewNames != null && viewNames!.isNotEmpty) 'view_names': viewNames!, if (textScale != null) 'text_scale': textScale!, + ...?unknown }; - json.addAll(unknown ?? {}); - return json; } SentryApp clone() => SentryApp( diff --git a/dart/lib/src/protocol/sentry_browser.dart b/dart/lib/src/protocol/sentry_browser.dart index 417f6bb497..e95791cdac 100644 --- a/dart/lib/src/protocol/sentry_browser.dart +++ b/dart/lib/src/protocol/sentry_browser.dart @@ -30,12 +30,11 @@ class SentryBrowser { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { if (name != null) 'name': name, if (version != null) 'version': version, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryBrowser clone() => SentryBrowser( diff --git a/dart/lib/src/protocol/sentry_culture.dart b/dart/lib/src/protocol/sentry_culture.dart index 4aa9176f2a..760b7de37b 100644 --- a/dart/lib/src/protocol/sentry_culture.dart +++ b/dart/lib/src/protocol/sentry_culture.dart @@ -54,15 +54,14 @@ class SentryCulture { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { if (calendar != null) 'calendar': calendar!, if (displayName != null) 'display_name': displayName!, if (locale != null) 'locale': locale!, if (is24HourFormat != null) 'is_24_hour_format': is24HourFormat!, if (timezone != null) 'timezone': timezone!, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryCulture clone() => SentryCulture( diff --git a/dart/lib/src/protocol/sentry_device.dart b/dart/lib/src/protocol/sentry_device.dart index d0b3242661..3df51e1b51 100644 --- a/dart/lib/src/protocol/sentry_device.dart +++ b/dart/lib/src/protocol/sentry_device.dart @@ -264,7 +264,7 @@ class SentryDevice { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { if (name != null) 'name': name, if (family != null) 'family': family, if (model != null) 'model': model, @@ -307,9 +307,8 @@ class SentryDevice { if (supportsAudio != null) 'supports_audio': supportsAudio, if (supportsLocationService != null) 'supports_location_service': supportsLocationService, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryDevice clone() => SentryDevice( diff --git a/dart/lib/src/protocol/sentry_event.dart b/dart/lib/src/protocol/sentry_event.dart index fa949b8be3..b155ec7adf 100644 --- a/dart/lib/src/protocol/sentry_event.dart +++ b/dart/lib/src/protocol/sentry_event.dart @@ -401,7 +401,7 @@ class SentryEvent with SentryEventLike { .where((e) => e.isNotEmpty) .toList(growable: false); - final json = { + return { 'event_id': eventId.toString(), if (timestamp != null) 'timestamp': formatDateAsIso8601WithMillisPrecision(timestamp!), @@ -432,8 +432,7 @@ class SentryEvent with SentryEventLike { if (exceptionsJson?.isNotEmpty ?? false) 'exception': {'values': exceptionsJson}, if (threadJson?.isNotEmpty ?? false) 'threads': {'values': threadJson}, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } } diff --git a/dart/lib/src/protocol/sentry_exception.dart b/dart/lib/src/protocol/sentry_exception.dart index 3b4a92f9a1..8f0f79b259 100644 --- a/dart/lib/src/protocol/sentry_exception.dart +++ b/dart/lib/src/protocol/sentry_exception.dart @@ -67,16 +67,15 @@ class SentryException { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { if (type != null) 'type': type, if (value != null) 'value': value, if (module != null) 'module': module, if (stackTrace != null) 'stacktrace': stackTrace!.toJson(), if (mechanism != null) 'mechanism': mechanism!.toJson(), if (threadId != null) 'thread_id': threadId, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryException copyWith({ diff --git a/dart/lib/src/protocol/sentry_gpu.dart b/dart/lib/src/protocol/sentry_gpu.dart index 620f046290..ee72074c62 100644 --- a/dart/lib/src/protocol/sentry_gpu.dart +++ b/dart/lib/src/protocol/sentry_gpu.dart @@ -146,7 +146,7 @@ class SentryGpu { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { if (name != null) 'name': name, if (id != null) 'id': id, if (vendorId != null) 'vendor_id': vendorId, @@ -168,9 +168,8 @@ class SentryGpu { 'supports_geometry_shaders': supportsGeometryShaders, if (supportsRayTracing != null) 'supports_ray_tracing': supportsRayTracing, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryGpu copyWith({ diff --git a/dart/lib/src/protocol/sentry_message.dart b/dart/lib/src/protocol/sentry_message.dart index a06990469f..1d75c35b7f 100644 --- a/dart/lib/src/protocol/sentry_message.dart +++ b/dart/lib/src/protocol/sentry_message.dart @@ -45,13 +45,12 @@ class SentryMessage { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { 'formatted': formatted, if (template != null) 'message': template, if (params?.isNotEmpty ?? false) 'params': params, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryMessage copyWith({ diff --git a/dart/lib/src/protocol/sentry_operating_system.dart b/dart/lib/src/protocol/sentry_operating_system.dart index 5d798d7ea0..09e4b53057 100644 --- a/dart/lib/src/protocol/sentry_operating_system.dart +++ b/dart/lib/src/protocol/sentry_operating_system.dart @@ -74,7 +74,7 @@ class SentryOperatingSystem { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { if (name != null) 'name': name, if (version != null) 'version': version, if (build != null) 'build': build, @@ -82,9 +82,8 @@ class SentryOperatingSystem { if (rooted != null) 'rooted': rooted, if (rawDescription != null) 'raw_description': rawDescription, if (theme != null) 'theme': theme, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryOperatingSystem clone() => SentryOperatingSystem( diff --git a/dart/lib/src/protocol/sentry_package.dart b/dart/lib/src/protocol/sentry_package.dart index bee8e21f6f..af2ddba13a 100644 --- a/dart/lib/src/protocol/sentry_package.dart +++ b/dart/lib/src/protocol/sentry_package.dart @@ -28,12 +28,11 @@ class SentryPackage { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { 'name': name, 'version': version, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryPackage copyWith({ diff --git a/dart/lib/src/protocol/sentry_request.dart b/dart/lib/src/protocol/sentry_request.dart index 0fd115b6f4..c7e3b37c77 100644 --- a/dart/lib/src/protocol/sentry_request.dart +++ b/dart/lib/src/protocol/sentry_request.dart @@ -154,7 +154,7 @@ class SentryRequest { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { if (url != null) 'url': url, if (method != null) 'method': method, if (queryString != null) 'query_string': queryString, @@ -166,9 +166,8 @@ class SentryRequest { if (other.isNotEmpty) 'other': other, if (fragment != null) 'fragment': fragment, if (apiTarget != null) 'api_target': apiTarget, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryRequest copyWith({ diff --git a/dart/lib/src/protocol/sentry_runtime.dart b/dart/lib/src/protocol/sentry_runtime.dart index f36194b9ce..76815a9952 100644 --- a/dart/lib/src/protocol/sentry_runtime.dart +++ b/dart/lib/src/protocol/sentry_runtime.dart @@ -68,15 +68,14 @@ class SentryRuntime { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { if (name != null) 'name': name, if (compiler != null) 'compiler': compiler, if (version != null) 'version': version, if (rawDescription != null) 'raw_description': rawDescription, if (build != null) 'build': build, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryRuntime clone() => SentryRuntime( diff --git a/dart/lib/src/protocol/sentry_stack_frame.dart b/dart/lib/src/protocol/sentry_stack_frame.dart index ddbd86f94d..ede652f76a 100644 --- a/dart/lib/src/protocol/sentry_stack_frame.dart +++ b/dart/lib/src/protocol/sentry_stack_frame.dart @@ -181,7 +181,7 @@ class SentryStackFrame { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { if (_preContext?.isNotEmpty ?? false) 'pre_context': _preContext, if (_postContext?.isNotEmpty ?? false) 'post_context': _postContext, if (_vars?.isNotEmpty ?? false) 'vars': _vars, @@ -203,9 +203,8 @@ class SentryStackFrame { if (rawFunction != null) 'raw_function': rawFunction, if (symbol != null) 'symbol': symbol, if (stackStart != null) 'stack_start': stackStart, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryStackFrame copyWith({ diff --git a/dart/lib/src/protocol/sentry_stack_trace.dart b/dart/lib/src/protocol/sentry_stack_trace.dart index a0dfa1b6d1..2460998792 100644 --- a/dart/lib/src/protocol/sentry_stack_trace.dart +++ b/dart/lib/src/protocol/sentry_stack_trace.dart @@ -67,16 +67,15 @@ class SentryStackTrace { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { if (_frames?.isNotEmpty ?? false) 'frames': _frames?.map((frame) => frame.toJson()).toList(growable: false), if (_registers?.isNotEmpty ?? false) 'registers': _registers, if (lang != null) 'lang': lang, if (snapshot != null) 'snapshot': snapshot, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryStackTrace copyWith({ diff --git a/dart/lib/src/protocol/sentry_thread.dart b/dart/lib/src/protocol/sentry_thread.dart index 471ce072ce..88f2bd85f0 100644 --- a/dart/lib/src/protocol/sentry_thread.dart +++ b/dart/lib/src/protocol/sentry_thread.dart @@ -58,15 +58,14 @@ class SentryThread { Map toJson() { final stacktrace = this.stacktrace; - final json = { + return { if (id != null) 'id': id, if (name != null) 'name': name, if (crashed != null) 'crashed': crashed, if (current != null) 'current': current, if (stacktrace != null) 'stacktrace': stacktrace.toJson(), + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryThread copyWith({ diff --git a/dart/lib/src/protocol/sentry_trace_context.dart b/dart/lib/src/protocol/sentry_trace_context.dart index 25bf471fc5..b3504b7d11 100644 --- a/dart/lib/src/protocol/sentry_trace_context.dart +++ b/dart/lib/src/protocol/sentry_trace_context.dart @@ -69,7 +69,7 @@ class SentryTraceContext { /// Item encoded as JSON Map toJson() { - final json = { + return { 'span_id': spanId.toString(), 'trace_id': traceId.toString(), 'op': operation, @@ -77,9 +77,8 @@ class SentryTraceContext { if (description != null) 'description': description, if (status != null) 'status': status!.toString(), if (origin != null) 'origin': origin, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryTraceContext clone() => SentryTraceContext( diff --git a/dart/lib/src/protocol/sentry_transaction_info.dart b/dart/lib/src/protocol/sentry_transaction_info.dart index 37c7c62077..6e13bcb08d 100644 --- a/dart/lib/src/protocol/sentry_transaction_info.dart +++ b/dart/lib/src/protocol/sentry_transaction_info.dart @@ -11,11 +11,10 @@ class SentryTransactionInfo { final Map? unknown; Map toJson() { - final json = { + return { 'source': source, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryTransactionInfo copyWith({ diff --git a/dart/lib/src/protocol/sentry_user.dart b/dart/lib/src/protocol/sentry_user.dart index 0895d21d6f..c5ff602ddc 100644 --- a/dart/lib/src/protocol/sentry_user.dart +++ b/dart/lib/src/protocol/sentry_user.dart @@ -142,7 +142,7 @@ class SentryUser { /// Produces a [Map] that can be serialized to JSON. Map toJson() { final geoJson = geo?.toJson(); - final json = { + return { if (id != null) 'id': id, if (username != null) 'username': username, if (email != null) 'email': email, @@ -154,9 +154,8 @@ class SentryUser { if (extras?.isNotEmpty ?? false) 'extras': extras, if (name != null) 'name': name, if (geoJson != null && geoJson.isNotEmpty) 'geo': geoJson, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryUser copyWith({ diff --git a/dart/lib/src/sentry_trace_context_header.dart b/dart/lib/src/sentry_trace_context_header.dart index d3724c82f4..c18701a479 100644 --- a/dart/lib/src/sentry_trace_context_header.dart +++ b/dart/lib/src/sentry_trace_context_header.dart @@ -62,7 +62,7 @@ class SentryTraceContextHeader { /// Produces a [Map] that can be serialized to JSON. Map toJson() { - final json = { + return { 'trace_id': traceId.toString(), 'public_key': publicKey, if (release != null) 'release': release, @@ -73,9 +73,8 @@ class SentryTraceContextHeader { if (transaction != null) 'transaction': transaction, if (sampleRate != null) 'sample_rate': sampleRate, if (sampled != null) 'sampled': sampled, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryBaggage toBaggage({ diff --git a/dart/lib/src/sentry_user_feedback.dart b/dart/lib/src/sentry_user_feedback.dart index 93a8e04463..d401b2a648 100644 --- a/dart/lib/src/sentry_user_feedback.dart +++ b/dart/lib/src/sentry_user_feedback.dart @@ -46,14 +46,13 @@ class SentryUserFeedback { final Map? unknown; Map toJson() { - final json = { + return { 'event_id': eventId.toString(), if (name != null) 'name': name, if (email != null) 'email': email, if (comments != null) 'comments': comments, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } SentryUserFeedback copyWith({ diff --git a/dart/test/sentry_user_feedback_test.dart b/dart/test/sentry_user_feedback_test.dart index 6a27f2644e..49dba04706 100644 --- a/dart/test/sentry_user_feedback_test.dart +++ b/dart/test/sentry_user_feedback_test.dart @@ -194,14 +194,13 @@ class SentryUserFeedbackWithoutAssert implements SentryUserFeedback { @override Map toJson() { - final json = { + return { 'event_id': eventId.toString(), if (name != null) 'name': name, if (email != null) 'email': email, if (comments != null) 'comments': comments, + ...?unknown, }; - json.addAll(unknown ?? {}); - return json; } @override From c5abedcd74753cad83a5310b2ef8295238235ad4 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 16 Jul 2024 11:22:34 +0200 Subject: [PATCH 37/43] Keep track of unknwon keys via AccessAwareMap --- dart/lib/src/protocol/access_aware_map.dart | 50 +++++++ dart/lib/src/protocol/breadcrumb.dart | 15 +- dart/lib/src/protocol/debug_image.dart | 21 +-- dart/lib/src/protocol/debug_meta.dart | 7 +- dart/lib/src/protocol/mechanism.dart | 19 +-- dart/lib/src/protocol/metric_summary.dart | 27 ++-- dart/lib/src/protocol/sdk_info.dart | 12 +- dart/lib/src/protocol/sdk_version.dart | 25 ++-- dart/lib/src/protocol/sentry_app.dart | 46 +++--- dart/lib/src/protocol/sentry_browser.dart | 14 +- dart/lib/src/protocol/sentry_culture.dart | 27 ++-- dart/lib/src/protocol/sentry_device.dart | 136 +++++++----------- dart/lib/src/protocol/sentry_event.dart | 34 +---- dart/lib/src/protocol/sentry_exception.dart | 15 +- dart/lib/src/protocol/sentry_gpu.dart | 57 +++----- dart/lib/src/protocol/sentry_message.dart | 15 +- .../src/protocol/sentry_operating_system.dart | 34 ++--- dart/lib/src/protocol/sentry_package.dart | 7 +- dart/lib/src/protocol/sentry_request.dart | 18 +-- dart/lib/src/protocol/sentry_runtime.dart | 27 ++-- dart/lib/src/protocol/sentry_stack_frame.dart | 29 +--- dart/lib/src/protocol/sentry_stack_trace.dart | 7 +- dart/lib/src/protocol/sentry_thread.dart | 13 +- .../src/protocol/sentry_trace_context.dart | 15 +- .../src/protocol/sentry_transaction_info.dart | 7 +- dart/lib/src/protocol/sentry_user.dart | 18 +-- dart/lib/src/protocol/unknown.dart | 15 -- dart/lib/src/sentry_trace_context_header.dart | 17 +-- dart/lib/src/sentry_user_feedback.dart | 12 +- .../test/protocol/access_aware_map_tests.dart | 74 ++++++++++ 30 files changed, 366 insertions(+), 447 deletions(-) create mode 100644 dart/lib/src/protocol/access_aware_map.dart delete mode 100644 dart/lib/src/protocol/unknown.dart create mode 100644 dart/test/protocol/access_aware_map_tests.dart diff --git a/dart/lib/src/protocol/access_aware_map.dart b/dart/lib/src/protocol/access_aware_map.dart new file mode 100644 index 0000000000..9332f75520 --- /dev/null +++ b/dart/lib/src/protocol/access_aware_map.dart @@ -0,0 +1,50 @@ +import 'dart:collection'; + +import 'package:meta/meta.dart'; + +@internal +class AccessAwareMap extends MapBase { + AccessAwareMap(this._map); + + final Map _map; + final Set _accessedKeys = {}; + + Set get accessedKeys => _accessedKeys; + + @override + V? operator [](Object? key) { + if (key is String) { + _accessedKeys.add(key); + } + return _map[key]; + } + + @override + void operator []=(String key, V value) { + _map[key] = value; + } + + @override + void clear() { + _map.clear(); + _accessedKeys.clear(); + } + + @override + Iterable get keys => _map.keys; + + @override + V? remove(Object? key) { + return _map.remove(key); + } + + Map? notAccessed() { + Map unknown = _map.keys + .where((key) => !accessedKeys.contains(key)) + .fold>({}, (map, key) { + map[key] = _map[key]; + return map; + }); + return unknown.isNotEmpty ? unknown : null; + } +} diff --git a/dart/lib/src/protocol/breadcrumb.dart b/dart/lib/src/protocol/breadcrumb.dart index 675e33d6bb..dd6de2a93b 100644 --- a/dart/lib/src/protocol/breadcrumb.dart +++ b/dart/lib/src/protocol/breadcrumb.dart @@ -2,7 +2,7 @@ import 'package:meta/meta.dart'; import '../utils.dart'; import '../protocol.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// Structured data to describe more information prior to the event captured. /// See `Sentry.captureEvent()`. @@ -162,7 +162,9 @@ class Breadcrumb { final Map? unknown; /// Deserializes a [Breadcrumb] from JSON [Map]. - factory Breadcrumb.fromJson(Map json) { + factory Breadcrumb.fromJson(Map jsonData) { + final json = AccessAwareMap(jsonData); + final levelName = json['level']; final timestamp = json['timestamp']; @@ -177,14 +179,7 @@ class Breadcrumb { data: data, level: levelName != null ? SentryLevel.fromName(levelName) : null, type: json['type'], - unknown: unknownFrom(json, { - 'level', - 'timestamp', - 'data', - 'message', - 'category', - 'type', - }), + unknown: json.notAccessed(), ); } diff --git a/dart/lib/src/protocol/debug_image.dart b/dart/lib/src/protocol/debug_image.dart index cf8f9e6689..3ede0909b5 100644 --- a/dart/lib/src/protocol/debug_image.dart +++ b/dart/lib/src/protocol/debug_image.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// The list of debug images contains all dynamic libraries loaded into /// the process and their memory addresses. @@ -74,7 +74,8 @@ class DebugImage { }); /// Deserializes a [DebugImage] from JSON [Map]. - factory DebugImage.fromJson(Map json) { + factory DebugImage.fromJson(Map data) { + final json = AccessAwareMap(data); return DebugImage( type: json['type'], name: json['name'], @@ -89,21 +90,7 @@ class DebugImage { codeId: json['code_id'], cpuType: json['cpu_type'], cpuSubtype: json['cpu_subtype'], - unknown: unknownFrom(json, { - 'type', - 'name', - 'image_addr', - 'image_vmaddr', - 'debug_id', - 'debug_file', - 'image_size', - 'uuid', - 'code_file', - 'arch', - 'code_id', - 'cpu_type', - 'cpu_subtype', - }), + unknown: json.notAccessed(), ); } diff --git a/dart/lib/src/protocol/debug_meta.dart b/dart/lib/src/protocol/debug_meta.dart index 6475469003..84fb450b53 100644 --- a/dart/lib/src/protocol/debug_meta.dart +++ b/dart/lib/src/protocol/debug_meta.dart @@ -1,7 +1,7 @@ import 'package:meta/meta.dart'; import '../protocol.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// The debug meta interface carries debug information for processing errors and crash reports. @immutable @@ -24,7 +24,8 @@ class DebugMeta { final Map? unknown; /// Deserializes a [DebugMeta] from JSON [Map]. - factory DebugMeta.fromJson(Map json) { + factory DebugMeta.fromJson(Map data) { + final json = AccessAwareMap(data); final sdkInfoJson = json['sdk_info']; final debugImagesJson = json['images'] as List?; return DebugMeta( @@ -33,7 +34,7 @@ class DebugMeta { ?.map((debugImageJson) => DebugImage.fromJson(debugImageJson as Map)) .toList(), - unknown: unknownFrom(json, {'sdk_info', 'images'}), + unknown: json.notAccessed(), ); } diff --git a/dart/lib/src/protocol/mechanism.dart b/dart/lib/src/protocol/mechanism.dart index cd2d165810..840aa6554f 100644 --- a/dart/lib/src/protocol/mechanism.dart +++ b/dart/lib/src/protocol/mechanism.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// Sentry Exception Mechanism /// The exception mechanism is an optional field residing @@ -126,7 +126,8 @@ class Mechanism { ); /// Deserializes a [Mechanism] from JSON [Map]. - factory Mechanism.fromJson(Map json) { + factory Mechanism.fromJson(Map jsonData) { + final json = AccessAwareMap(jsonData); var data = json['data']; if (data != null) { data = Map.from(data as Map); @@ -149,19 +150,7 @@ class Mechanism { source: json['source'], exceptionId: json['exception_id'], parentId: json['parent_id'], - unknown: unknownFrom(json, { - 'data', - 'meta', - 'type', - 'description', - 'help_link', - 'handled', - 'synthetic', - 'is_exception_group', - 'source', - 'exception_id', - 'parent_id', - }), + unknown: json.notAccessed(), ); } diff --git a/dart/lib/src/protocol/metric_summary.dart b/dart/lib/src/protocol/metric_summary.dart index 555a292d5b..8b4691c625 100644 --- a/dart/lib/src/protocol/metric_summary.dart +++ b/dart/lib/src/protocol/metric_summary.dart @@ -1,7 +1,7 @@ import 'package:meta/meta.dart'; import '../metrics/metric.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; class MetricSummary { final num min; @@ -29,20 +29,17 @@ class MetricSummary { this.unknown}); /// Deserializes a [MetricSummary] from JSON [Map]. - factory MetricSummary.fromJson(Map data) => MetricSummary( - min: data['min'], - max: data['max'], - count: data['count'], - sum: data['sum'], - tags: data['tags']?.cast(), - unknown: unknownFrom(data, { - 'min', - 'max', - 'count', - 'sum', - 'tags', - }), - ); + 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() { diff --git a/dart/lib/src/protocol/sdk_info.dart b/dart/lib/src/protocol/sdk_info.dart index f7312c334a..2bc4632081 100644 --- a/dart/lib/src/protocol/sdk_info.dart +++ b/dart/lib/src/protocol/sdk_info.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// An object describing the system SDK. @immutable @@ -22,18 +22,14 @@ class SdkInfo { }); /// Deserializes a [SdkInfo] from JSON [Map]. - factory SdkInfo.fromJson(Map json) { + factory SdkInfo.fromJson(Map data) { + final json = AccessAwareMap(data); return SdkInfo( sdkName: json['sdk_name'], versionMajor: json['version_major'], versionMinor: json['version_minor'], versionPatchlevel: json['version_patchlevel'], - unknown: unknownFrom(json, { - 'sdk_name', - 'version_major', - 'version_minor', - 'version_patchlevel', - }), + unknown: json.notAccessed(), ); } diff --git a/dart/lib/src/protocol/sdk_version.dart b/dart/lib/src/protocol/sdk_version.dart index 5f4f63b5ae..76e914ae41 100644 --- a/dart/lib/src/protocol/sdk_version.dart +++ b/dart/lib/src/protocol/sdk_version.dart @@ -1,7 +1,7 @@ import 'package:meta/meta.dart'; import 'sentry_package.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// Describes the SDK that is submitting events to Sentry. /// @@ -67,22 +67,19 @@ class SdkVersion { final Map? unknown; /// Deserializes a [SdkVersion] from JSON [Map]. - factory SdkVersion.fromJson(Map json) { + factory SdkVersion.fromJson(Map data) { + final json = AccessAwareMap(data); final packagesJson = json['packages'] as List?; final integrationsJson = json['integrations'] as List?; return SdkVersion( - name: json['name'], - version: json['version'], - packages: packagesJson - ?.map((e) => SentryPackage.fromJson(e as Map)) - .toList(), - integrations: integrationsJson?.map((e) => e as String).toList(), - unknown: unknownFrom(json, { - 'name', - 'version' - 'packages', - 'integrations', - })); + name: json['name'], + version: json['version'], + packages: packagesJson + ?.map((e) => SentryPackage.fromJson(e as Map)) + .toList(), + integrations: integrationsJson?.map((e) => e as String).toList(), + unknown: json.notAccessed(), + ); } /// Produces a [Map] that can be serialized to JSON. diff --git a/dart/lib/src/protocol/sentry_app.dart b/dart/lib/src/protocol/sentry_app.dart index b08f9e40a3..700ebeb154 100644 --- a/dart/lib/src/protocol/sentry_app.dart +++ b/dart/lib/src/protocol/sentry_app.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// App context describes the application. /// @@ -64,34 +64,24 @@ class SentryApp { /// Deserializes a [SentryApp] from JSON [Map]. factory SentryApp.fromJson(Map data) { - final viewNamesJson = data['view_names'] as List?; + final json = AccessAwareMap(data); + final viewNamesJson = json['view_names'] as List?; return SentryApp( - name: data['app_name'], - version: data['app_version'], - identifier: data['app_identifier'], - build: data['app_build'], - buildType: data['build_type'], - startTime: data['app_start_time'] != null - ? DateTime.tryParse(data['app_start_time']) - : null, - deviceAppHash: data['device_app_hash'], - appMemory: data['app_memory'], - inForeground: data['in_foreground'], - viewNames: viewNamesJson?.map((e) => e as String).toList(), - textScale: data['text_scale'], - unknown: unknownFrom(data, { - 'app_name', - 'app_version', - 'app_identifier', - 'app_build', - 'build_type', - 'app_start_time', - 'device_app_hash', - 'app_memory', - 'in_foreground', - 'view_names', - 'text_scale', - })); + name: json['app_name'], + version: json['app_version'], + identifier: json['app_identifier'], + build: json['app_build'], + buildType: json['build_type'], + startTime: json['app_start_time'] != null + ? DateTime.tryParse(json['app_start_time']) + : null, + deviceAppHash: json['device_app_hash'], + appMemory: json['app_memory'], + inForeground: json['in_foreground'], + viewNames: viewNamesJson?.map((e) => e as String).toList(), + textScale: json['text_scale'], + unknown: json.notAccessed(), + ); } /// Produces a [Map] that can be serialized to JSON. diff --git a/dart/lib/src/protocol/sentry_browser.dart b/dart/lib/src/protocol/sentry_browser.dart index e95791cdac..2f015c94ea 100644 --- a/dart/lib/src/protocol/sentry_browser.dart +++ b/dart/lib/src/protocol/sentry_browser.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// Carries information about the browser or user agent for web-related errors. /// @@ -23,10 +23,14 @@ class SentryBrowser { final Map? unknown; /// Deserializes a [SentryBrowser] from JSON [Map]. - factory SentryBrowser.fromJson(Map data) => SentryBrowser( - name: data['name'], - version: data['version'], - unknown: unknownFrom(data, {'name', 'version'})); + factory SentryBrowser.fromJson(Map data) { + final json = AccessAwareMap(data); + return SentryBrowser( + name: json['name'], + version: json['version'], + unknown: json.notAccessed(), + ); + } /// Produces a [Map] that can be serialized to JSON. Map toJson() { diff --git a/dart/lib/src/protocol/sentry_culture.dart b/dart/lib/src/protocol/sentry_culture.dart index 760b7de37b..52fc0fc714 100644 --- a/dart/lib/src/protocol/sentry_culture.dart +++ b/dart/lib/src/protocol/sentry_culture.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// Culture Context describes certain properties of the culture in which the /// software is used. @@ -17,20 +17,17 @@ class SentryCulture { this.unknown, }); - factory SentryCulture.fromJson(Map data) => SentryCulture( - calendar: data['calendar'], - displayName: data['display_name'], - locale: data['locale'], - is24HourFormat: data['is_24_hour_format'], - timezone: data['timezone'], - unknown: unknownFrom(data, { - 'calendar', - 'display_name', - 'locale', - 'is_24_hour_format', - 'timezone', - }), - ); + factory SentryCulture.fromJson(Map data) { + final json = AccessAwareMap(data); + return SentryCulture( + calendar: json['calendar'], + displayName: json['display_name'], + locale: json['locale'], + is24HourFormat: json['is_24_hour_format'], + timezone: json['timezone'], + unknown: json.notAccessed(), + ); + } /// Optional: For example `GregorianCalendar`. Free form string. final String? calendar; diff --git a/dart/lib/src/protocol/sentry_device.dart b/dart/lib/src/protocol/sentry_device.dart index 3df51e1b51..6f8cd59376 100644 --- a/dart/lib/src/protocol/sentry_device.dart +++ b/dart/lib/src/protocol/sentry_device.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; import '../sentry_options.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// If a device is on portrait or landscape mode enum SentryOrientation { portrait, landscape } @@ -177,90 +177,56 @@ class SentryDevice { final Map? unknown; /// Deserializes a [SentryDevice] from JSON [Map]. - factory SentryDevice.fromJson(Map data) => SentryDevice( - name: data['name'], - family: data['family'], - model: data['model'], - modelId: data['model_id'], - arch: data['arch'], - batteryLevel: - (data['battery_level'] is num ? data['battery_level'] as num : null) - ?.toDouble(), - orientation: data['orientation'] == 'portrait' - ? SentryOrientation.portrait - : data['orientation'] == 'landscape' - ? SentryOrientation.landscape - : null, - manufacturer: data['manufacturer'], - brand: data['brand'], - screenHeightPixels: data['screen_height_pixels']?.toInt(), - screenWidthPixels: data['screen_width_pixels']?.toInt(), - screenDensity: data['screen_density'], - screenDpi: data['screen_dpi'], - online: data['online'], - charging: data['charging'], - lowMemory: data['low_memory'], - simulator: data['simulator'], - memorySize: data['memory_size'], - freeMemory: data['free_memory'], - usableMemory: data['usable_memory'], - storageSize: data['storage_size'], - freeStorage: data['free_storage'], - externalStorageSize: data['external_storage_size'], - externalFreeStorage: data['external_free_storage'], - bootTime: data['boot_time'] != null - ? DateTime.tryParse(data['boot_time']) - : null, - processorCount: data['processor_count'], - cpuDescription: data['cpu_description'], - processorFrequency: data['processor_frequency'], - deviceType: data['device_type'], - batteryStatus: data['battery_status'], - deviceUniqueIdentifier: data['device_unique_identifier'], - supportsVibration: data['supports_vibration'], - supportsAccelerometer: data['supports_accelerometer'], - supportsGyroscope: data['supports_gyroscope'], - supportsAudio: data['supports_audio'], - supportsLocationService: data['supports_location_service'], - unknown: unknownFrom(data, { - 'name', - 'family', - 'model', - 'model_id', - 'arch', - 'battery_level', - 'orientation', - 'manufacturer', - 'brand', - 'screen_height_pixels', - 'screen_width_pixels', - 'screen_density', - 'screen_dpi', - 'online', - 'charging', - 'low_memory', - 'simulator', - 'memory_size', - 'free_memory', - 'usable_memory', - 'storage_size', - 'free_storage', - 'external_storage_size', - 'external_free_storage', - 'boot_time', - 'processor_count', - 'cpu_description', - 'processor_frequency', - 'device_type', - 'battery_status', - 'device_unique_identifier', - 'supports_vibration', - 'supports_accelerometer', - 'supports_gyroscope', - 'supports_audio', - 'supports_location_service', - }), - ); + factory SentryDevice.fromJson(Map data) { + final json = AccessAwareMap(data); + return SentryDevice( + name: json['name'], + family: json['family'], + model: json['model'], + modelId: json['model_id'], + arch: json['arch'], + batteryLevel: + (json['battery_level'] is num ? json['battery_level'] as num : null) + ?.toDouble(), + orientation: json['orientation'] == 'portrait' + ? SentryOrientation.portrait + : json['orientation'] == 'landscape' + ? SentryOrientation.landscape + : null, + manufacturer: json['manufacturer'], + brand: json['brand'], + screenHeightPixels: json['screen_height_pixels']?.toInt(), + screenWidthPixels: json['screen_width_pixels']?.toInt(), + screenDensity: json['screen_density'], + screenDpi: json['screen_dpi'], + online: json['online'], + charging: json['charging'], + lowMemory: json['low_memory'], + simulator: json['simulator'], + memorySize: json['memory_size'], + freeMemory: json['free_memory'], + usableMemory: json['usable_memory'], + storageSize: json['storage_size'], + freeStorage: json['free_storage'], + externalStorageSize: json['external_storage_size'], + externalFreeStorage: json['external_free_storage'], + bootTime: json['boot_time'] != null + ? DateTime.tryParse(json['boot_time']) + : null, + processorCount: json['processor_count'], + cpuDescription: json['cpu_description'], + processorFrequency: json['processor_frequency'], + deviceType: json['device_type'], + batteryStatus: json['battery_status'], + deviceUniqueIdentifier: json['device_unique_identifier'], + supportsVibration: json['supports_vibration'], + supportsAccelerometer: json['supports_accelerometer'], + supportsGyroscope: json['supports_gyroscope'], + supportsAudio: json['supports_audio'], + supportsLocationService: json['supports_location_service'], + unknown: json.notAccessed(), + ); + } /// Produces a [Map] that can be serialized to JSON. Map toJson() { diff --git a/dart/lib/src/protocol/sentry_event.dart b/dart/lib/src/protocol/sentry_event.dart index b155ec7adf..1abc711b83 100644 --- a/dart/lib/src/protocol/sentry_event.dart +++ b/dart/lib/src/protocol/sentry_event.dart @@ -3,7 +3,7 @@ import 'package:meta/meta.dart'; import '../protocol.dart'; import '../throwable_mechanism.dart'; import '../utils.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// An event to be reported to Sentry.io. @immutable @@ -260,7 +260,9 @@ class SentryEvent with SentryEventLike { ); /// Deserializes a [SentryEvent] from JSON [Map]. - factory SentryEvent.fromJson(Map json) { + factory SentryEvent.fromJson(Map data) { + final json = AccessAwareMap(data); + final breadcrumbsJson = json['breadcrumbs'] as List?; final breadcrumbs = breadcrumbsJson ?.map((e) => Breadcrumb.fromJson(e)) @@ -335,33 +337,7 @@ class SentryEvent with SentryEventLike { : null, exceptions: exceptions, type: json['type'], - unknown: unknownFrom(json, { - 'breadcrumbs', - 'threads', - 'exception', - 'modules', - 'tags', - 'timestamp', - 'level', - 'fingerprint', - 'sdk', - 'message', - 'user', - 'contexts', - 'request', - 'debug_meta', - 'extra', - 'event_id', - 'platform', - 'logger', - 'server_name', - 'release', - 'dist', - 'environment', - 'transaction', - 'culprit', - 'type', - }), + unknown: json.notAccessed(), ); } diff --git a/dart/lib/src/protocol/sentry_exception.dart b/dart/lib/src/protocol/sentry_exception.dart index 8f0f79b259..e52dd9668e 100644 --- a/dart/lib/src/protocol/sentry_exception.dart +++ b/dart/lib/src/protocol/sentry_exception.dart @@ -1,7 +1,7 @@ import 'package:meta/meta.dart'; import '../protocol.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// The Exception Interface specifies an exception or error that occurred in a program. @immutable @@ -41,7 +41,9 @@ class SentryException { }); /// Deserializes a [SentryException] from JSON [Map]. - factory SentryException.fromJson(Map json) { + factory SentryException.fromJson(Map data) { + final json = AccessAwareMap(data); + final stackTraceJson = json['stacktrace']; final mechanismJson = json['mechanism']; return SentryException( @@ -54,14 +56,7 @@ class SentryException { mechanism: mechanismJson != null ? Mechanism.fromJson(mechanismJson) : null, threadId: json['thread_id'], - unknown: unknownFrom(json, { - 'stacktrace', - 'mechanism', - 'type', - 'value', - 'module', - 'thread_id', - }), + unknown: json.notAccessed(), ); } diff --git a/dart/lib/src/protocol/sentry_gpu.dart b/dart/lib/src/protocol/sentry_gpu.dart index ee72074c62..6aa32a3168 100644 --- a/dart/lib/src/protocol/sentry_gpu.dart +++ b/dart/lib/src/protocol/sentry_gpu.dart @@ -12,7 +12,7 @@ import 'package:meta/meta.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// GPU context describes the GPU of the device. @immutable @@ -90,40 +90,27 @@ class SentryGpu { }); /// Deserializes a [SentryGpu] from JSON [Map]. - factory SentryGpu.fromJson(Map data) => SentryGpu( - name: data['name'], - id: data['id'], - vendorId: data['vendor_id'], - vendorName: data['vendor_name'], - memorySize: data['memory_size'], - apiType: data['api_type'], - multiThreadedRendering: data['multi_threaded_rendering'], - version: data['version'], - npotSupport: data['npot_support'], - graphicsShaderLevel: data['graphics_shader_level'], - maxTextureSize: data['max_texture_size'], - supportsComputeShaders: data['supports_compute_shaders'], - supportsDrawCallInstancing: data['supports_draw_call_instancing'], - supportsGeometryShaders: data['supports_geometry_shaders'], - supportsRayTracing: data['supports_ray_tracing'], - unknown: unknownFrom(data, { - 'name', - 'id', - 'vendor_id', - 'vendor_name', - 'memory_size', - 'api_type', - 'multi_threaded_rendering', - 'version', - 'npot_support', - 'graphics_shader_level', - 'max_texture_size', - 'supports_compute_shaders', - 'supports_draw_call_instancing', - 'supports_geometry_shaders', - 'supports_ray_tracing', - }), - ); + factory SentryGpu.fromJson(Map data) { + final json = AccessAwareMap(data); + return SentryGpu( + name: json['name'], + id: json['id'], + vendorId: json['vendor_id'], + vendorName: json['vendor_name'], + memorySize: json['memory_size'], + apiType: json['api_type'], + multiThreadedRendering: json['multi_threaded_rendering'], + version: json['version'], + npotSupport: json['npot_support'], + graphicsShaderLevel: json['graphics_shader_level'], + maxTextureSize: json['max_texture_size'], + supportsComputeShaders: json['supports_compute_shaders'], + supportsDrawCallInstancing: json['supports_draw_call_instancing'], + supportsGeometryShaders: json['supports_geometry_shaders'], + supportsRayTracing: json['supports_ray_tracing'], + unknown: json.notAccessed(), + ); + } SentryGpu clone() => SentryGpu( name: name, diff --git a/dart/lib/src/protocol/sentry_message.dart b/dart/lib/src/protocol/sentry_message.dart index 1d75c35b7f..11c64d6ac8 100644 --- a/dart/lib/src/protocol/sentry_message.dart +++ b/dart/lib/src/protocol/sentry_message.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// The Message Interface carries a log message that describes an event or error. /// Optionally, it can carry a format string and structured parameters. This can help to group similar messages into the same issue. @@ -36,11 +36,14 @@ class SentryMessage { }); /// Deserializes a [SentryMessage] from JSON [Map]. - factory SentryMessage.fromJson(Map json) { - return SentryMessage(json['formatted'], - template: json['message'], - params: json['params'], - unknown: unknownFrom(json, {'formatted', 'message', 'params'})); + factory SentryMessage.fromJson(Map data) { + final json = AccessAwareMap(data); + return SentryMessage( + json['formatted'], + template: json['message'], + params: json['params'], + unknown: json.notAccessed(), + ); } /// Produces a [Map] that can be serialized to JSON. diff --git a/dart/lib/src/protocol/sentry_operating_system.dart b/dart/lib/src/protocol/sentry_operating_system.dart index 09e4b53057..4595cd12fc 100644 --- a/dart/lib/src/protocol/sentry_operating_system.dart +++ b/dart/lib/src/protocol/sentry_operating_system.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// Describes the operating system on which the event was created. /// @@ -52,25 +52,19 @@ class SentryOperatingSystem { final Map? unknown; /// Deserializes a [SentryOperatingSystem] from JSON [Map]. - factory SentryOperatingSystem.fromJson(Map data) => - SentryOperatingSystem( - name: data['name'], - version: data['version'], - build: data['build'], - kernelVersion: data['kernel_version'], - rooted: data['rooted'], - rawDescription: data['raw_description'], - theme: data['theme'], - unknown: unknownFrom(data, { - 'name', - 'version', - 'build', - 'kernel_version', - 'rooted', - 'raw_description', - 'theme', - }), - ); + factory SentryOperatingSystem.fromJson(Map data) { + final json = AccessAwareMap(data); + return SentryOperatingSystem( + name: json['name'], + version: json['version'], + build: json['build'], + kernelVersion: json['kernel_version'], + rooted: json['rooted'], + rawDescription: json['raw_description'], + theme: json['theme'], + unknown: json.notAccessed(), + ); + } /// Produces a [Map] that can be serialized to JSON. Map toJson() { diff --git a/dart/lib/src/protocol/sentry_package.dart b/dart/lib/src/protocol/sentry_package.dart index af2ddba13a..9e569370e9 100644 --- a/dart/lib/src/protocol/sentry_package.dart +++ b/dart/lib/src/protocol/sentry_package.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// A [SentryPackage] part of the SDK. @immutable @@ -18,11 +18,12 @@ class SentryPackage { final Map? unknown; /// Deserializes a [SentryPackage] from JSON [Map]. - factory SentryPackage.fromJson(Map json) { + factory SentryPackage.fromJson(Map data) { + final json = AccessAwareMap(data); return SentryPackage( json['name'], json['version'], - unknown: unknownFrom(json, {'name', 'version'}), + unknown: json.notAccessed(), ); } diff --git a/dart/lib/src/protocol/sentry_request.dart b/dart/lib/src/protocol/sentry_request.dart index c7e3b37c77..d59bcb9d06 100644 --- a/dart/lib/src/protocol/sentry_request.dart +++ b/dart/lib/src/protocol/sentry_request.dart @@ -1,5 +1,5 @@ import 'package:meta/meta.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; import '../utils/iterable_utils.dart'; import '../utils/http_sanitizer.dart'; @@ -124,7 +124,8 @@ class SentryRequest { } /// Deserializes a [SentryRequest] from JSON [Map]. - factory SentryRequest.fromJson(Map json) { + factory SentryRequest.fromJson(Map data) { + final json = AccessAwareMap(data); return SentryRequest( url: json['url'], method: json['method'], @@ -137,18 +138,7 @@ class SentryRequest { other: json.containsKey('other') ? Map.from(json['other']) : null, fragment: json['fragment'], apiTarget: json['api_target'], - unknown: unknownFrom(json, { - 'url', - 'method', - 'query_string', - 'cookies', - 'data', - 'headers', - 'env', - 'other', - 'fragment', - 'api_target', - }), + unknown: json.notAccessed(), ); } diff --git a/dart/lib/src/protocol/sentry_runtime.dart b/dart/lib/src/protocol/sentry_runtime.dart index 76815a9952..5ccfb7db38 100644 --- a/dart/lib/src/protocol/sentry_runtime.dart +++ b/dart/lib/src/protocol/sentry_runtime.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// Describes a runtime in more detail. /// @@ -51,20 +51,17 @@ class SentryRuntime { final Map? unknown; /// Deserializes a [SentryRuntime] from JSON [Map]. - factory SentryRuntime.fromJson(Map data) => SentryRuntime( - name: data['name'], - version: data['version'], - compiler: data['compiler'], - rawDescription: data['raw_description'], - build: data['build'], - unknown: unknownFrom(data, { - 'name', - 'version', - 'compiler', - 'raw_description', - 'build', - }), - ); + factory SentryRuntime.fromJson(Map data) { + final json = AccessAwareMap(data); + return SentryRuntime( + name: json['name'], + version: json['version'], + compiler: json['compiler'], + rawDescription: json['raw_description'], + build: json['build'], + unknown: json.notAccessed(), + ); + } /// Produces a [Map] that can be serialized to JSON. Map toJson() { diff --git a/dart/lib/src/protocol/sentry_stack_frame.dart b/dart/lib/src/protocol/sentry_stack_frame.dart index ede652f76a..0d5cd9a49e 100644 --- a/dart/lib/src/protocol/sentry_stack_frame.dart +++ b/dart/lib/src/protocol/sentry_stack_frame.dart @@ -1,5 +1,5 @@ import 'package:meta/meta.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// Frames belong to a StackTrace /// It should contain at least a filename, function or instruction_addr @@ -130,7 +130,8 @@ class SentryStackFrame { final Map? unknown; /// Deserializes a [SentryStackFrame] from JSON [Map]. - factory SentryStackFrame.fromJson(Map json) { + factory SentryStackFrame.fromJson(Map data) { + final json = AccessAwareMap(data); return SentryStackFrame( absPath: json['abs_path'], fileName: json['filename'], @@ -153,29 +154,7 @@ class SentryStackFrame { vars: json['vars'], symbol: json['symbol'], stackStart: json['stack_start'], - unknown: unknownFrom(json, { - 'abs_path', - 'filename', - 'function', - 'module', - 'lineno', - 'colno', - 'context_line', - 'in_app', - 'package', - 'native', - 'platform', - 'image_addr', - 'symbol_addr', - 'instruction_addr', - 'raw_function', - 'frames_omitted', - 'pre_context', - 'post_context', - 'vars', - 'symbol', - 'stack_start', - }), + unknown: json.notAccessed(), ); } diff --git a/dart/lib/src/protocol/sentry_stack_trace.dart b/dart/lib/src/protocol/sentry_stack_trace.dart index 2460998792..3238dd901c 100644 --- a/dart/lib/src/protocol/sentry_stack_trace.dart +++ b/dart/lib/src/protocol/sentry_stack_trace.dart @@ -1,7 +1,7 @@ import 'package:meta/meta.dart'; import 'sentry_stack_frame.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// Stacktrace holds information about the frames of the stack. @immutable @@ -50,7 +50,8 @@ class SentryStackTrace { final Map? unknown; /// Deserializes a [SentryStackTrace] from JSON [Map]. - factory SentryStackTrace.fromJson(Map json) { + factory SentryStackTrace.fromJson(Map data) { + final json = AccessAwareMap(data); final framesJson = json['frames'] as List?; return SentryStackTrace( frames: framesJson != null @@ -61,7 +62,7 @@ class SentryStackTrace { registers: json['registers'], lang: json['lang'], snapshot: json['snapshot'], - unknown: unknownFrom(json, {'frames', 'registers', 'lang', 'snapshot'}), + unknown: json.notAccessed(), ); } diff --git a/dart/lib/src/protocol/sentry_thread.dart b/dart/lib/src/protocol/sentry_thread.dart index 88f2bd85f0..52e34e2b73 100644 --- a/dart/lib/src/protocol/sentry_thread.dart +++ b/dart/lib/src/protocol/sentry_thread.dart @@ -1,7 +1,7 @@ import 'package:meta/meta.dart'; import 'sentry_stack_trace.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// The Threads Interface specifies threads that were running at the time an /// event happened. These threads can also contain stack traces. @@ -17,7 +17,8 @@ class SentryThread { this.unknown, }); - factory SentryThread.fromJson(Map json) { + factory SentryThread.fromJson(Map data) { + final json = AccessAwareMap(data); return SentryThread( id: json['id'] as int?, name: json['name'] as String?, @@ -25,13 +26,7 @@ class SentryThread { current: json['current'] as bool?, stacktrace: json['stacktrace'] == null ? null : SentryStackTrace.fromJson(json), - unknown: unknownFrom(json, { - 'id', - 'name', - 'crashed', - 'current', - 'stacktrace', - }), + unknown: json.notAccessed(), ); } diff --git a/dart/lib/src/protocol/sentry_trace_context.dart b/dart/lib/src/protocol/sentry_trace_context.dart index b3504b7d11..9763018ed8 100644 --- a/dart/lib/src/protocol/sentry_trace_context.dart +++ b/dart/lib/src/protocol/sentry_trace_context.dart @@ -3,7 +3,7 @@ import 'package:meta/meta.dart'; import '../../sentry.dart'; import '../propagation_context.dart'; import '../protocol.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; @immutable class SentryTraceContext { @@ -41,7 +41,8 @@ class SentryTraceContext { @internal final Map? unknown; - factory SentryTraceContext.fromJson(Map json) { + factory SentryTraceContext.fromJson(Map data) { + final json = AccessAwareMap(data); return SentryTraceContext( operation: json['op'] as String, spanId: SpanId.fromId(json['span_id'] as String), @@ -55,15 +56,7 @@ class SentryTraceContext { : SpanStatus.fromString(json['status'] as String), sampled: true, origin: json['origin'] == null ? null : json['origin'] as String?, - unknown: unknownFrom(json, { - 'op', - 'span_id', - 'parent_span_id', - 'trace_id', - 'description', - 'status', - 'origin', - }), + unknown: json.notAccessed(), ); } diff --git a/dart/lib/src/protocol/sentry_transaction_info.dart b/dart/lib/src/protocol/sentry_transaction_info.dart index 6e13bcb08d..23588a7f26 100644 --- a/dart/lib/src/protocol/sentry_transaction_info.dart +++ b/dart/lib/src/protocol/sentry_transaction_info.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; class SentryTransactionInfo { SentryTransactionInfo(this.source, {this.unknown}); @@ -26,10 +26,11 @@ class SentryTransactionInfo { ); } - factory SentryTransactionInfo.fromJson(Map json) { + factory SentryTransactionInfo.fromJson(Map data) { + final json = AccessAwareMap(data); return SentryTransactionInfo( json['source'], - unknown: unknownFrom(json, {'source'}), + unknown: json.notAccessed(), ); } } diff --git a/dart/lib/src/protocol/sentry_user.dart b/dart/lib/src/protocol/sentry_user.dart index c5ff602ddc..d337e217f4 100644 --- a/dart/lib/src/protocol/sentry_user.dart +++ b/dart/lib/src/protocol/sentry_user.dart @@ -1,7 +1,7 @@ import 'package:meta/meta.dart'; import '../../sentry.dart'; -import 'unknown.dart'; +import 'access_aware_map.dart'; /// Describes the current user associated with the application, such as the /// currently signed in user. @@ -98,7 +98,9 @@ class SentryUser { final Map? unknown; /// Deserializes a [SentryUser] from JSON [Map]. - factory SentryUser.fromJson(Map json) { + factory SentryUser.fromJson(Map jsonData) { + final json = AccessAwareMap(jsonData); + var extras = json['extras']; if (extras != null) { extras = Map.from(extras); @@ -125,17 +127,7 @@ class SentryUser { name: json['name'], // ignore: deprecated_member_use_from_same_package extras: extras, - unknown: unknownFrom(json, { - 'id', - 'username', - 'email', - 'ip_address', - 'segment', - 'data', - 'geo', - 'name', - 'extras', - }), + unknown: json.notAccessed(), ); } diff --git a/dart/lib/src/protocol/unknown.dart b/dart/lib/src/protocol/unknown.dart deleted file mode 100644 index 1900e58d94..0000000000 --- a/dart/lib/src/protocol/unknown.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:meta/meta.dart'; - -@internal -Map? unknownFrom( - Map json, - Set knownKeys, -) { - Map unknown = json.keys - .where((key) => !knownKeys.contains(key)) - .fold>({}, (map, key) { - map[key] = json[key]; - return map; - }); - return unknown.isNotEmpty ? unknown : null; -} diff --git a/dart/lib/src/sentry_trace_context_header.dart b/dart/lib/src/sentry_trace_context_header.dart index c18701a479..f455fb65bf 100644 --- a/dart/lib/src/sentry_trace_context_header.dart +++ b/dart/lib/src/sentry_trace_context_header.dart @@ -1,7 +1,7 @@ import 'package:meta/meta.dart'; import 'protocol/sentry_id.dart'; -import 'protocol/unknown.dart'; +import 'protocol/access_aware_map.dart'; import 'sentry_baggage.dart'; import 'sentry_options.dart'; @@ -35,7 +35,8 @@ class SentryTraceContextHeader { final Map? unknown; /// Deserializes a [SentryTraceContextHeader] from JSON [Map]. - factory SentryTraceContextHeader.fromJson(Map json) { + factory SentryTraceContextHeader.fromJson(Map data) { + final json = AccessAwareMap(data); return SentryTraceContextHeader( SentryId.fromId(json['trace_id']), json['public_key'], @@ -46,17 +47,7 @@ class SentryTraceContextHeader { transaction: json['transaction'], sampleRate: json['sample_rate'], sampled: json['sampled'], - unknown: unknownFrom(json, { - 'trace_id', - 'public_key', - 'release', - 'environment', - 'user_id', - 'user_segment', - 'transaction', - 'sample_rate', - 'sampled', - }), + unknown: json.notAccessed(), ); } diff --git a/dart/lib/src/sentry_user_feedback.dart b/dart/lib/src/sentry_user_feedback.dart index d401b2a648..fff2c10ec0 100644 --- a/dart/lib/src/sentry_user_feedback.dart +++ b/dart/lib/src/sentry_user_feedback.dart @@ -1,7 +1,7 @@ import 'package:meta/meta.dart'; import 'protocol.dart'; -import 'protocol/unknown.dart'; +import 'protocol/access_aware_map.dart'; class SentryUserFeedback { SentryUserFeedback({ @@ -15,18 +15,14 @@ class SentryUserFeedback { email?.isNotEmpty == true || comments?.isNotEmpty == true)); - factory SentryUserFeedback.fromJson(Map json) { + factory SentryUserFeedback.fromJson(Map data) { + final json = AccessAwareMap(data); return SentryUserFeedback( eventId: SentryId.fromId(json['event_id']), name: json['name'], email: json['email'], comments: json['comments'], - unknown: unknownFrom(json, { - 'event_id', - 'name', - 'email', - 'comments', - }), + unknown: json.notAccessed(), ); } diff --git a/dart/test/protocol/access_aware_map_tests.dart b/dart/test/protocol/access_aware_map_tests.dart new file mode 100644 index 0000000000..409994b5ae --- /dev/null +++ b/dart/test/protocol/access_aware_map_tests.dart @@ -0,0 +1,74 @@ +import 'package:sentry/src/protocol/access_aware_map.dart'; +import 'package:test/test.dart'; + +void main() { + group('access aware', () { + test('collects accessedKeys', () { + final sut = AccessAwareMap({ + 'foo': 'foo', + 'bar': 'bar', + }); + + sut['foo']; + sut['bar']; + sut['baz']; + + expect(sut.accessedKeys, {'foo', 'bar', 'baz'}); + }); + + test('returns notAccessed data', () { + final sut = AccessAwareMap({ + 'foo': 'foo', + 'bar': 'bar', + }); + + sut['foo']; + + final notAccessed = sut.notAccessed(); + expect(notAccessed, isNotNull); + expect(notAccessed?.containsKey('foo'), false); + expect(notAccessed?.containsKey('bar'), true); + }); + }); + + group('map base functionality', () { + test('set value with []= operator', () { + final sut = AccessAwareMap({ + 'foo': 'foo', + }); + + sut['foo'] = 'bar'; + sut['bar'] = 'foo'; + + expect(sut['foo'], 'bar'); + expect(sut['bar'], 'foo'); + }); + + test('clear', () { + final sut = AccessAwareMap({ + 'foo': 'foo', + }); + + sut.clear(); + + expect(sut.accessedKeys.isEmpty, true); + expect(sut.isEmpty, true); + }); + + test('keys', () { + final sut = AccessAwareMap({ + 'foo': 'foo', + 'bar': 'bar', + }); + expect(sut.keys.toSet(), {'foo', 'bar'}); + }); + + test('remove', () { + final sut = AccessAwareMap({'foo': 'foo'}); + + sut.remove('foo'); + + expect(sut['foo'], isNull); + }); + }); +} From f7ad96eb93be4ab5377eaeb9d8a289a0939d5d0a Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 16 Jul 2024 11:43:41 +0200 Subject: [PATCH 38/43] fix changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca8a44bfb4..8cfb73e8ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Improvements + +- Deserialize and serialize unknown fields ([#2153](https://github.com/getsentry/sentry-dart/pull/2153)) + ## 8.4.0 ### Features @@ -25,7 +31,6 @@ ### Improvements - Set dart runtime version with parsed `Platform.version` ([#2156](https://github.com/getsentry/sentry-dart/pull/2156)) -- Deserialize and serialize unknown fields ([#2153](https://github.com/getsentry/sentry-dart/pull/2153)) ### Dependencies From a60c74ce19ac0097120357d7174e5808cd18b90f Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 29 Jul 2024 11:22:24 +0200 Subject: [PATCH 39/43] early return for access aware map --- dart/lib/src/protocol/access_aware_map.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dart/lib/src/protocol/access_aware_map.dart b/dart/lib/src/protocol/access_aware_map.dart index 9332f75520..a9739460a4 100644 --- a/dart/lib/src/protocol/access_aware_map.dart +++ b/dart/lib/src/protocol/access_aware_map.dart @@ -39,6 +39,9 @@ class AccessAwareMap extends MapBase { } Map? notAccessed() { + if (accessedKeys.length == _map.length) { + return null; + } Map unknown = _map.keys .where((key) => !accessedKeys.contains(key)) .fold>({}, (map, key) { From 91458ee7270f5643eae926d3d27641f223f30180 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 29 Jul 2024 11:35:04 +0200 Subject: [PATCH 40/43] add tests for mapbase --- .../test/protocol/access_aware_map_tests.dart | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/dart/test/protocol/access_aware_map_tests.dart b/dart/test/protocol/access_aware_map_tests.dart index 409994b5ae..15118a8487 100644 --- a/dart/test/protocol/access_aware_map_tests.dart +++ b/dart/test/protocol/access_aware_map_tests.dart @@ -1,7 +1,51 @@ +import 'package:collection/collection.dart'; import 'package:sentry/src/protocol/access_aware_map.dart'; import 'package:test/test.dart'; void main() { + group('MapBase', () { + test('set/get value for key', () { + final sut = AccessAwareMap({ + 'foo': 'foo', + }); + + sut['foo'] = 'bar'; + sut['bar'] = 'foo'; + + expect(sut['foo'], 'bar'); + expect(sut['bar'], 'foo'); + }); + + test('clear', () { + final sut = AccessAwareMap({ + 'foo': 'foo', + }); + + sut.clear(); + + expect(sut.isEmpty, true); + }); + + test('keys', () { + final sut = AccessAwareMap({ + 'foo': 'foo', + 'bar': 'bar', + }); + expect( + sut.keys.sortedBy((it) => it), ['bar', 'foo'].sortedBy((it) => it)); + }); + + test('remove', () { + final sut = AccessAwareMap({ + 'foo': 'foo', + }); + + sut.remove('foo'); + + expect(sut.isEmpty, true); + }); + }); + group('access aware', () { test('collects accessedKeys', () { final sut = AccessAwareMap({ From 294c0b2a799aacccb51f615ed25ce81aaf89f533 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 29 Jul 2024 11:36:00 +0200 Subject: [PATCH 41/43] fix cl --- CHANGELOG.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d88b42a7a..59623ea68f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,5 @@ # Changelog -## Unreleased - -### Improvements - -- Deserialize and serialize unknown fields ([#2153](https://github.com/getsentry/sentry-dart/pull/2153)) ## Unreleased ### Improvements @@ -32,6 +27,7 @@ class MyCustomExceptionIdentifier implements ExceptionIdentifier { SentryFlutter.init((options) => options..prependExceptionTypeIdentifier(MyCustomExceptionIdentifier())); ``` +- Deserialize and serialize unknown fields ([#2153](https://github.com/getsentry/sentry-dart/pull/2153)) ### Deprecated From 8471ec581f4efefebd42cfe368573c4008793eeb Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 29 Jul 2024 12:54:39 +0200 Subject: [PATCH 42/43] only track accessed keys with values, add unknown before other keys --- dart/lib/src/protocol/access_aware_map.dart | 14 +++++++------- dart/lib/src/protocol/breadcrumb.dart | 2 +- dart/lib/src/protocol/debug_image.dart | 2 +- dart/lib/src/protocol/debug_meta.dart | 2 +- dart/lib/src/protocol/mechanism.dart | 2 +- dart/lib/src/protocol/metric_summary.dart | 2 +- dart/lib/src/protocol/sdk_info.dart | 2 +- dart/lib/src/protocol/sdk_version.dart | 2 +- dart/lib/src/protocol/sentry_app.dart | 2 +- dart/lib/src/protocol/sentry_browser.dart | 2 +- dart/lib/src/protocol/sentry_culture.dart | 2 +- dart/lib/src/protocol/sentry_device.dart | 2 +- dart/lib/src/protocol/sentry_event.dart | 2 +- dart/lib/src/protocol/sentry_exception.dart | 2 +- dart/lib/src/protocol/sentry_gpu.dart | 2 +- dart/lib/src/protocol/sentry_message.dart | 2 +- dart/lib/src/protocol/sentry_operating_system.dart | 2 +- dart/lib/src/protocol/sentry_package.dart | 2 +- dart/lib/src/protocol/sentry_request.dart | 2 +- dart/lib/src/protocol/sentry_runtime.dart | 2 +- dart/lib/src/protocol/sentry_stack_frame.dart | 2 +- dart/lib/src/protocol/sentry_stack_trace.dart | 2 +- dart/lib/src/protocol/sentry_thread.dart | 2 +- dart/lib/src/protocol/sentry_trace_context.dart | 2 +- dart/lib/src/protocol/sentry_transaction_info.dart | 2 +- dart/lib/src/protocol/sentry_user.dart | 2 +- dart/lib/src/sentry_trace_context_header.dart | 2 +- dart/lib/src/sentry_user_feedback.dart | 2 +- dart/test/protocol/access_aware_map_tests.dart | 4 ++-- dart/test/protocol/sdk_info_test.dart | 3 +++ dart/test/protocol/sentry_user_test.dart | 2 ++ dart/test/sentry_user_feedback_test.dart | 2 +- 32 files changed, 42 insertions(+), 37 deletions(-) diff --git a/dart/lib/src/protocol/access_aware_map.dart b/dart/lib/src/protocol/access_aware_map.dart index a9739460a4..c8ea7b2395 100644 --- a/dart/lib/src/protocol/access_aware_map.dart +++ b/dart/lib/src/protocol/access_aware_map.dart @@ -7,14 +7,14 @@ class AccessAwareMap extends MapBase { AccessAwareMap(this._map); final Map _map; - final Set _accessedKeys = {}; + final Set _accessedKeysWithValues = {}; - Set get accessedKeys => _accessedKeys; + Set get accessedKeysWithValues => _accessedKeysWithValues; @override V? operator [](Object? key) { - if (key is String) { - _accessedKeys.add(key); + if (key is String && _map.containsKey(key)) { + _accessedKeysWithValues.add(key); } return _map[key]; } @@ -27,7 +27,7 @@ class AccessAwareMap extends MapBase { @override void clear() { _map.clear(); - _accessedKeys.clear(); + _accessedKeysWithValues.clear(); } @override @@ -39,11 +39,11 @@ class AccessAwareMap extends MapBase { } Map? notAccessed() { - if (accessedKeys.length == _map.length) { + if (_accessedKeysWithValues.length == _map.length) { return null; } Map unknown = _map.keys - .where((key) => !accessedKeys.contains(key)) + .where((key) => !_accessedKeysWithValues.contains(key)) .fold>({}, (map, key) { map[key] = _map[key]; return map; diff --git a/dart/lib/src/protocol/breadcrumb.dart b/dart/lib/src/protocol/breadcrumb.dart index dd6de2a93b..86eabc2ffc 100644 --- a/dart/lib/src/protocol/breadcrumb.dart +++ b/dart/lib/src/protocol/breadcrumb.dart @@ -187,13 +187,13 @@ class Breadcrumb { /// to the Sentry protocol. Map toJson() { return { + ...?unknown, 'timestamp': formatDateAsIso8601WithMillisPrecision(timestamp), if (message != null) 'message': message, if (category != null) 'category': category, if (data?.isNotEmpty ?? false) 'data': data, if (level != null) 'level': level!.name, if (type != null) 'type': type, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/debug_image.dart b/dart/lib/src/protocol/debug_image.dart index 3ede0909b5..6ff98cbf07 100644 --- a/dart/lib/src/protocol/debug_image.dart +++ b/dart/lib/src/protocol/debug_image.dart @@ -97,6 +97,7 @@ class DebugImage { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, 'type': type, if (uuid != null) 'uuid': uuid, if (debugId != null) 'debug_id': debugId, @@ -110,7 +111,6 @@ class DebugImage { if (codeId != null) 'code_id': codeId, if (cpuType != null) 'cpu_type': cpuType, if (cpuSubtype != null) 'cpu_subtype': cpuSubtype, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/debug_meta.dart b/dart/lib/src/protocol/debug_meta.dart index 84fb450b53..dd4e93c4e4 100644 --- a/dart/lib/src/protocol/debug_meta.dart +++ b/dart/lib/src/protocol/debug_meta.dart @@ -42,13 +42,13 @@ class DebugMeta { Map 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), - ...?unknown, }; } diff --git a/dart/lib/src/protocol/mechanism.dart b/dart/lib/src/protocol/mechanism.dart index 840aa6554f..fe6500b21b 100644 --- a/dart/lib/src/protocol/mechanism.dart +++ b/dart/lib/src/protocol/mechanism.dart @@ -157,6 +157,7 @@ class Mechanism { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, 'type': type, if (description != null) 'description': description, if (helpLink != null) 'help_link': helpLink, @@ -168,7 +169,6 @@ class Mechanism { if (source != null) 'source': source, if (exceptionId != null) 'exception_id': exceptionId, if (parentId != null) 'parent_id': parentId, - ...?unknown, }; } } diff --git a/dart/lib/src/protocol/metric_summary.dart b/dart/lib/src/protocol/metric_summary.dart index 8b4691c625..f5354bfdf7 100644 --- a/dart/lib/src/protocol/metric_summary.dart +++ b/dart/lib/src/protocol/metric_summary.dart @@ -44,12 +44,12 @@ class MetricSummary { /// 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, - ...?unknown, }; } } diff --git a/dart/lib/src/protocol/sdk_info.dart b/dart/lib/src/protocol/sdk_info.dart index 2bc4632081..f5aec76efc 100644 --- a/dart/lib/src/protocol/sdk_info.dart +++ b/dart/lib/src/protocol/sdk_info.dart @@ -36,11 +36,11 @@ class SdkInfo { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, if (sdkName != null) 'sdk_name': sdkName, if (versionMajor != null) 'version_major': versionMajor, if (versionMinor != null) 'version_minor': versionMinor, if (versionPatchlevel != null) 'version_patchlevel': versionPatchlevel, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/sdk_version.dart b/dart/lib/src/protocol/sdk_version.dart index 76e914ae41..b915fbdde8 100644 --- a/dart/lib/src/protocol/sdk_version.dart +++ b/dart/lib/src/protocol/sdk_version.dart @@ -85,12 +85,12 @@ class SdkVersion { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, 'name': name, 'version': version, if (packages.isNotEmpty) 'packages': packages.map((p) => p.toJson()).toList(growable: false), if (integrations.isNotEmpty) 'integrations': integrations, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/sentry_app.dart b/dart/lib/src/protocol/sentry_app.dart index 700ebeb154..8ef217c690 100644 --- a/dart/lib/src/protocol/sentry_app.dart +++ b/dart/lib/src/protocol/sentry_app.dart @@ -87,6 +87,7 @@ class SentryApp { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, if (name != null) 'app_name': name!, if (version != null) 'app_version': version!, if (identifier != null) 'app_identifier': identifier!, @@ -98,7 +99,6 @@ class SentryApp { if (inForeground != null) 'in_foreground': inForeground!, if (viewNames != null && viewNames!.isNotEmpty) 'view_names': viewNames!, if (textScale != null) 'text_scale': textScale!, - ...?unknown }; } diff --git a/dart/lib/src/protocol/sentry_browser.dart b/dart/lib/src/protocol/sentry_browser.dart index 2f015c94ea..a67e1abb7d 100644 --- a/dart/lib/src/protocol/sentry_browser.dart +++ b/dart/lib/src/protocol/sentry_browser.dart @@ -35,9 +35,9 @@ class SentryBrowser { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, if (name != null) 'name': name, if (version != null) 'version': version, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/sentry_culture.dart b/dart/lib/src/protocol/sentry_culture.dart index 52fc0fc714..68bcae5cd8 100644 --- a/dart/lib/src/protocol/sentry_culture.dart +++ b/dart/lib/src/protocol/sentry_culture.dart @@ -52,12 +52,12 @@ class SentryCulture { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, if (calendar != null) 'calendar': calendar!, if (displayName != null) 'display_name': displayName!, if (locale != null) 'locale': locale!, if (is24HourFormat != null) 'is_24_hour_format': is24HourFormat!, if (timezone != null) 'timezone': timezone!, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/sentry_device.dart b/dart/lib/src/protocol/sentry_device.dart index 6f8cd59376..1bc5c89b78 100644 --- a/dart/lib/src/protocol/sentry_device.dart +++ b/dart/lib/src/protocol/sentry_device.dart @@ -231,6 +231,7 @@ class SentryDevice { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, if (name != null) 'name': name, if (family != null) 'family': family, if (model != null) 'model': model, @@ -273,7 +274,6 @@ class SentryDevice { if (supportsAudio != null) 'supports_audio': supportsAudio, if (supportsLocationService != null) 'supports_location_service': supportsLocationService, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/sentry_event.dart b/dart/lib/src/protocol/sentry_event.dart index 1abc711b83..1b2765c426 100644 --- a/dart/lib/src/protocol/sentry_event.dart +++ b/dart/lib/src/protocol/sentry_event.dart @@ -378,6 +378,7 @@ class SentryEvent with SentryEventLike { .toList(growable: false); return { + ...?unknown, 'event_id': eventId.toString(), if (timestamp != null) 'timestamp': formatDateAsIso8601WithMillisPrecision(timestamp!), @@ -408,7 +409,6 @@ class SentryEvent with SentryEventLike { if (exceptionsJson?.isNotEmpty ?? false) 'exception': {'values': exceptionsJson}, if (threadJson?.isNotEmpty ?? false) 'threads': {'values': threadJson}, - ...?unknown, }; } } diff --git a/dart/lib/src/protocol/sentry_exception.dart b/dart/lib/src/protocol/sentry_exception.dart index e52dd9668e..9bf5f3fa13 100644 --- a/dart/lib/src/protocol/sentry_exception.dart +++ b/dart/lib/src/protocol/sentry_exception.dart @@ -63,13 +63,13 @@ class SentryException { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, if (type != null) 'type': type, if (value != null) 'value': value, if (module != null) 'module': module, if (stackTrace != null) 'stacktrace': stackTrace!.toJson(), if (mechanism != null) 'mechanism': mechanism!.toJson(), if (threadId != null) 'thread_id': threadId, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/sentry_gpu.dart b/dart/lib/src/protocol/sentry_gpu.dart index 6aa32a3168..bb6168813e 100644 --- a/dart/lib/src/protocol/sentry_gpu.dart +++ b/dart/lib/src/protocol/sentry_gpu.dart @@ -134,6 +134,7 @@ class SentryGpu { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, if (name != null) 'name': name, if (id != null) 'id': id, if (vendorId != null) 'vendor_id': vendorId, @@ -155,7 +156,6 @@ class SentryGpu { 'supports_geometry_shaders': supportsGeometryShaders, if (supportsRayTracing != null) 'supports_ray_tracing': supportsRayTracing, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/sentry_message.dart b/dart/lib/src/protocol/sentry_message.dart index 11c64d6ac8..bb9193f714 100644 --- a/dart/lib/src/protocol/sentry_message.dart +++ b/dart/lib/src/protocol/sentry_message.dart @@ -49,10 +49,10 @@ class SentryMessage { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, 'formatted': formatted, if (template != null) 'message': template, if (params?.isNotEmpty ?? false) 'params': params, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/sentry_operating_system.dart b/dart/lib/src/protocol/sentry_operating_system.dart index 4595cd12fc..8854a4d87f 100644 --- a/dart/lib/src/protocol/sentry_operating_system.dart +++ b/dart/lib/src/protocol/sentry_operating_system.dart @@ -69,6 +69,7 @@ class SentryOperatingSystem { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, if (name != null) 'name': name, if (version != null) 'version': version, if (build != null) 'build': build, @@ -76,7 +77,6 @@ class SentryOperatingSystem { if (rooted != null) 'rooted': rooted, if (rawDescription != null) 'raw_description': rawDescription, if (theme != null) 'theme': theme, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/sentry_package.dart b/dart/lib/src/protocol/sentry_package.dart index 9e569370e9..643ba910ed 100644 --- a/dart/lib/src/protocol/sentry_package.dart +++ b/dart/lib/src/protocol/sentry_package.dart @@ -30,9 +30,9 @@ class SentryPackage { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, 'name': name, 'version': version, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/sentry_request.dart b/dart/lib/src/protocol/sentry_request.dart index d59bcb9d06..6ad35cd34d 100644 --- a/dart/lib/src/protocol/sentry_request.dart +++ b/dart/lib/src/protocol/sentry_request.dart @@ -145,6 +145,7 @@ class SentryRequest { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, if (url != null) 'url': url, if (method != null) 'method': method, if (queryString != null) 'query_string': queryString, @@ -156,7 +157,6 @@ class SentryRequest { if (other.isNotEmpty) 'other': other, if (fragment != null) 'fragment': fragment, if (apiTarget != null) 'api_target': apiTarget, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/sentry_runtime.dart b/dart/lib/src/protocol/sentry_runtime.dart index 5ccfb7db38..02f8e632e8 100644 --- a/dart/lib/src/protocol/sentry_runtime.dart +++ b/dart/lib/src/protocol/sentry_runtime.dart @@ -66,12 +66,12 @@ class SentryRuntime { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, if (name != null) 'name': name, if (compiler != null) 'compiler': compiler, if (version != null) 'version': version, if (rawDescription != null) 'raw_description': rawDescription, if (build != null) 'build': build, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/sentry_stack_frame.dart b/dart/lib/src/protocol/sentry_stack_frame.dart index 0d5cd9a49e..edba949e9f 100644 --- a/dart/lib/src/protocol/sentry_stack_frame.dart +++ b/dart/lib/src/protocol/sentry_stack_frame.dart @@ -161,6 +161,7 @@ class SentryStackFrame { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, if (_preContext?.isNotEmpty ?? false) 'pre_context': _preContext, if (_postContext?.isNotEmpty ?? false) 'post_context': _postContext, if (_vars?.isNotEmpty ?? false) 'vars': _vars, @@ -182,7 +183,6 @@ class SentryStackFrame { if (rawFunction != null) 'raw_function': rawFunction, if (symbol != null) 'symbol': symbol, if (stackStart != null) 'stack_start': stackStart, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/sentry_stack_trace.dart b/dart/lib/src/protocol/sentry_stack_trace.dart index 3238dd901c..949318ec4c 100644 --- a/dart/lib/src/protocol/sentry_stack_trace.dart +++ b/dart/lib/src/protocol/sentry_stack_trace.dart @@ -69,13 +69,13 @@ class SentryStackTrace { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, if (_frames?.isNotEmpty ?? false) 'frames': _frames?.map((frame) => frame.toJson()).toList(growable: false), if (_registers?.isNotEmpty ?? false) 'registers': _registers, if (lang != null) 'lang': lang, if (snapshot != null) 'snapshot': snapshot, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/sentry_thread.dart b/dart/lib/src/protocol/sentry_thread.dart index 52e34e2b73..49dcd284f9 100644 --- a/dart/lib/src/protocol/sentry_thread.dart +++ b/dart/lib/src/protocol/sentry_thread.dart @@ -54,12 +54,12 @@ class SentryThread { Map toJson() { final stacktrace = this.stacktrace; return { + ...?unknown, if (id != null) 'id': id, if (name != null) 'name': name, if (crashed != null) 'crashed': crashed, if (current != null) 'current': current, if (stacktrace != null) 'stacktrace': stacktrace.toJson(), - ...?unknown, }; } diff --git a/dart/lib/src/protocol/sentry_trace_context.dart b/dart/lib/src/protocol/sentry_trace_context.dart index 9763018ed8..1d80541fd4 100644 --- a/dart/lib/src/protocol/sentry_trace_context.dart +++ b/dart/lib/src/protocol/sentry_trace_context.dart @@ -63,6 +63,7 @@ class SentryTraceContext { /// Item encoded as JSON Map toJson() { return { + ...?unknown, 'span_id': spanId.toString(), 'trace_id': traceId.toString(), 'op': operation, @@ -70,7 +71,6 @@ class SentryTraceContext { if (description != null) 'description': description, if (status != null) 'status': status!.toString(), if (origin != null) 'origin': origin, - ...?unknown, }; } diff --git a/dart/lib/src/protocol/sentry_transaction_info.dart b/dart/lib/src/protocol/sentry_transaction_info.dart index 23588a7f26..773b482646 100644 --- a/dart/lib/src/protocol/sentry_transaction_info.dart +++ b/dart/lib/src/protocol/sentry_transaction_info.dart @@ -12,8 +12,8 @@ class SentryTransactionInfo { Map toJson() { return { - 'source': source, ...?unknown, + 'source': source, }; } diff --git a/dart/lib/src/protocol/sentry_user.dart b/dart/lib/src/protocol/sentry_user.dart index d337e217f4..a62d7b9c58 100644 --- a/dart/lib/src/protocol/sentry_user.dart +++ b/dart/lib/src/protocol/sentry_user.dart @@ -135,6 +135,7 @@ class SentryUser { Map toJson() { final geoJson = geo?.toJson(); return { + ...?unknown, if (id != null) 'id': id, if (username != null) 'username': username, if (email != null) 'email': email, @@ -146,7 +147,6 @@ class SentryUser { if (extras?.isNotEmpty ?? false) 'extras': extras, if (name != null) 'name': name, if (geoJson != null && geoJson.isNotEmpty) 'geo': geoJson, - ...?unknown, }; } diff --git a/dart/lib/src/sentry_trace_context_header.dart b/dart/lib/src/sentry_trace_context_header.dart index f455fb65bf..ed7ec53653 100644 --- a/dart/lib/src/sentry_trace_context_header.dart +++ b/dart/lib/src/sentry_trace_context_header.dart @@ -54,6 +54,7 @@ class SentryTraceContextHeader { /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { + ...?unknown, 'trace_id': traceId.toString(), 'public_key': publicKey, if (release != null) 'release': release, @@ -64,7 +65,6 @@ class SentryTraceContextHeader { if (transaction != null) 'transaction': transaction, if (sampleRate != null) 'sample_rate': sampleRate, if (sampled != null) 'sampled': sampled, - ...?unknown, }; } diff --git a/dart/lib/src/sentry_user_feedback.dart b/dart/lib/src/sentry_user_feedback.dart index fff2c10ec0..055199ed61 100644 --- a/dart/lib/src/sentry_user_feedback.dart +++ b/dart/lib/src/sentry_user_feedback.dart @@ -43,11 +43,11 @@ class SentryUserFeedback { Map toJson() { return { + ...?unknown, 'event_id': eventId.toString(), if (name != null) 'name': name, if (email != null) 'email': email, if (comments != null) 'comments': comments, - ...?unknown, }; } diff --git a/dart/test/protocol/access_aware_map_tests.dart b/dart/test/protocol/access_aware_map_tests.dart index 15118a8487..b9c08f2b9a 100644 --- a/dart/test/protocol/access_aware_map_tests.dart +++ b/dart/test/protocol/access_aware_map_tests.dart @@ -57,7 +57,7 @@ void main() { sut['bar']; sut['baz']; - expect(sut.accessedKeys, {'foo', 'bar', 'baz'}); + expect(sut.accessedKeysWithValues, {'foo', 'bar', 'baz'}); }); test('returns notAccessed data', () { @@ -95,7 +95,7 @@ void main() { sut.clear(); - expect(sut.accessedKeys.isEmpty, true); + expect(sut.accessedKeysWithValues.isEmpty, true); expect(sut.isEmpty, true); }); diff --git a/dart/test/protocol/sdk_info_test.dart b/dart/test/protocol/sdk_info_test.dart index 822b5e59d0..522638f238 100644 --- a/dart/test/protocol/sdk_info_test.dart +++ b/dart/test/protocol/sdk_info_test.dart @@ -34,6 +34,9 @@ void main() { final sdkInfo = SdkInfo.fromJson(sdkInfoJson); final json = sdkInfo.toJson(); + print(sdkInfo); + print(json); + expect( MapEquality().equals(sdkInfoJson, json), true, diff --git a/dart/test/protocol/sentry_user_test.dart b/dart/test/protocol/sentry_user_test.dart index 1ffe284aee..dbc6e6cd87 100644 --- a/dart/test/protocol/sentry_user_test.dart +++ b/dart/test/protocol/sentry_user_test.dart @@ -29,6 +29,8 @@ void main() { test('toJson', () { final json = sentryUser.toJson(); + print("$json"); + expect( DeepCollectionEquality().equals(sentryUserJson, json), true, diff --git a/dart/test/sentry_user_feedback_test.dart b/dart/test/sentry_user_feedback_test.dart index 49dba04706..cb406f65b1 100644 --- a/dart/test/sentry_user_feedback_test.dart +++ b/dart/test/sentry_user_feedback_test.dart @@ -195,11 +195,11 @@ class SentryUserFeedbackWithoutAssert implements SentryUserFeedback { @override Map toJson() { return { + ...?unknown, 'event_id': eventId.toString(), if (name != null) 'name': name, if (email != null) 'email': email, if (comments != null) 'comments': comments, - ...?unknown, }; } From 7171ae67495b54ece1999f9659b10308b9b4c581 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 5 Aug 2024 13:21:25 +0200 Subject: [PATCH 43/43] fix cl --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c9b3a8cbe..4b0e831ac0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Improvements + +- Deserialize and serialize unknown fields ([#2153](https://github.com/getsentry/sentry-dart/pull/2153)) + ## 8.6.0 ### Improvements @@ -27,7 +33,6 @@ class MyCustomExceptionIdentifier implements ExceptionIdentifier { SentryFlutter.init((options) => options..prependExceptionTypeIdentifier(MyCustomExceptionIdentifier())); ``` -- Deserialize and serialize unknown fields ([#2153](https://github.com/getsentry/sentry-dart/pull/2153)) ### Deprecated