Skip to content

Commit

Permalink
refactor: SentryNative integration
Browse files Browse the repository at this point in the history
  • Loading branch information
vaind committed Sep 12, 2023
1 parent 15b1e21 commit f1482f4
Show file tree
Hide file tree
Showing 13 changed files with 296 additions and 344 deletions.
135 changes: 74 additions & 61 deletions flutter/lib/src/native/sentry_native.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,17 @@ import 'dart:async';
import 'package:meta/meta.dart';

import '../../sentry_flutter.dart';
import 'sentry_native_channel.dart';
import 'sentry_native_binding.dart';

/// [SentryNative] holds state that it fetches from to the native SDKs. Always
/// use the shared instance with [SentryNative()].
/// [SentryNative] holds state that it fetches from to the native SDKs.
/// It forwards to platform-specific implementations of [SentryNativeBinding].
/// Any errors are logged and ignored.
@internal
class SentryNative {
SentryNative._();
final SentryOptions _options;
final SentryNativeBinding _binding;

static final SentryNative _instance = SentryNative._();

SentryNativeChannel? _nativeChannel;

factory SentryNative() {
return _instance;
}

SentryNativeChannel? get nativeChannel => _instance._nativeChannel;

/// Provide [nativeChannel] for native communication.
set nativeChannel(SentryNativeChannel? nativeChannel) {
_instance._nativeChannel = nativeChannel;
}
SentryNative(this._options, this._binding);

// AppStart

Expand All @@ -41,75 +30,99 @@ class SentryNative {
/// Fetch [NativeAppStart] from native channels. Can only be called once.
Future<NativeAppStart?> fetchNativeAppStart() async {
_didFetchAppStart = true;
return await _nativeChannel?.fetchNativeAppStart();
return _invoke("fetchNativeAppStart", _binding.fetchNativeAppStart);
}

// NativeFrames

Future<void> beginNativeFramesCollection() async {
await _nativeChannel?.beginNativeFrames();
}
Future<void> beginNativeFramesCollection() =>
_invoke("beginNativeFrames", _binding.beginNativeFrames);

Future<NativeFrames?> endNativeFramesCollection(SentryId traceId) async {
return await _nativeChannel?.endNativeFrames(traceId);
}
Future<NativeFrames?> endNativeFramesCollection(SentryId traceId) =>
_invoke("endNativeFrames", () => _binding.endNativeFrames(traceId));

// Scope

Future<void> setContexts(String key, dynamic value) async {
return await _nativeChannel?.setContexts(key, value);
}
Future<void> setContexts(String key, dynamic value) =>
_invoke("setContexts", () => _binding.setContexts(key, value));

Future<void> removeContexts(String key) async {
return await _nativeChannel?.removeContexts(key);
}
Future<void> removeContexts(String key) =>
_invoke("removeContexts", () => _binding.removeContexts(key));

Future<void> setUser(SentryUser? sentryUser) async {
return await _nativeChannel?.setUser(sentryUser);
}
Future<void> setUser(SentryUser? sentryUser) =>
_invoke("setUser", () => _binding.setUser(sentryUser));

Future<void> addBreadcrumb(Breadcrumb breadcrumb) async {
return await _nativeChannel?.addBreadcrumb(breadcrumb);
}
Future<void> addBreadcrumb(Breadcrumb breadcrumb) =>
_invoke("addBreadcrumb", () => _binding.addBreadcrumb(breadcrumb));

Future<void> clearBreadcrumbs() async {
return await _nativeChannel?.clearBreadcrumbs();
}
Future<void> clearBreadcrumbs() =>
_invoke("clearBreadcrumbs", _binding.clearBreadcrumbs);

Future<void> setExtra(String key, dynamic value) async {
return await _nativeChannel?.setExtra(key, value);
}
Future<void> setExtra(String key, dynamic value) =>
_invoke("setExtra", () => _binding.setExtra(key, value));

Future<void> removeExtra(String key) async {
return await _nativeChannel?.removeExtra(key);
}
Future<void> removeExtra(String key) =>
_invoke("removeExtra", () => _binding.removeExtra(key));

Future<void> setTag(String key, String value) async {
return await _nativeChannel?.setTag(key, value);
}
Future<void> setTag(String key, String value) =>
_invoke("setTag", () => _binding.setTag(key, value));

Future<void> removeTag(String key) async {
return await _nativeChannel?.removeTag(key);
}
Future<void> removeTag(String key) =>
_invoke("removeTag", () => _binding.removeTag(key));

Future<int?> startProfiler(SentryId traceId) async {
return _nativeChannel?.startProfiler(traceId);
}
int? startProfiler(SentryId traceId) =>
_invokeSync("startProfiler", () => _binding.startProfiler(traceId));

Future<void> discardProfiler(SentryId traceId) async {
return _nativeChannel?.discardProfiler(traceId);
}
Future<void> discardProfiler(SentryId traceId) =>
_invoke("discardProfiler", () => _binding.discardProfiler(traceId));

Future<Map<String, dynamic>?> collectProfile(
SentryId traceId, int startTimeNs, int endTimeNs) async {
return _nativeChannel?.collectProfile(traceId, startTimeNs, endTimeNs);
}
SentryId traceId, int startTimeNs, int endTimeNs) =>
_invoke("collectProfile",
() => _binding.collectProfile(traceId, startTimeNs, endTimeNs));

/// Reset state
void reset() {
appStartEnd = null;
_didFetchAppStart = false;
}

// Helpers
Future<T?> _invoke<T>(
String nativeMethodName, Future<T?> Function() fn) async {
try {
return await fn();
} catch (error, stackTrace) {
_logError(nativeMethodName, error, stackTrace);

Check warning on line 96 in flutter/lib/src/native/sentry_native.dart

View check run for this annotation

Codecov / codecov/patch

flutter/lib/src/native/sentry_native.dart#L96

Added line #L96 was not covered by tests
// ignore: invalid_use_of_internal_member
if (_options.devMode) {

Check warning on line 98 in flutter/lib/src/native/sentry_native.dart

View check run for this annotation

Codecov / codecov/patch

flutter/lib/src/native/sentry_native.dart#L98

Added line #L98 was not covered by tests
rethrow;
}
return null;
}
}

T? _invokeSync<T>(String nativeMethodName, T? Function() fn) {
try {
return fn();
} catch (error, stackTrace) {
_logError(nativeMethodName, error, stackTrace);

Check warning on line 109 in flutter/lib/src/native/sentry_native.dart

View check run for this annotation

Codecov / codecov/patch

flutter/lib/src/native/sentry_native.dart#L109

Added line #L109 was not covered by tests
// ignore: invalid_use_of_internal_member
if (_options.devMode) {

Check warning on line 111 in flutter/lib/src/native/sentry_native.dart

View check run for this annotation

Codecov / codecov/patch

flutter/lib/src/native/sentry_native.dart#L111

Added line #L111 was not covered by tests
rethrow;
}
return null;
}
}

void _logError(String nativeMethodName, Object error, StackTrace stackTrace) {
_options.logger(

Check warning on line 119 in flutter/lib/src/native/sentry_native.dart

View check run for this annotation

Codecov / codecov/patch

flutter/lib/src/native/sentry_native.dart#L118-L119

Added lines #L118 - L119 were not covered by tests
SentryLevel.error,
'Native call `$nativeMethodName` failed',

Check warning on line 121 in flutter/lib/src/native/sentry_native.dart

View check run for this annotation

Codecov / codecov/patch

flutter/lib/src/native/sentry_native.dart#L121

Added line #L121 was not covered by tests
exception: error,
stackTrace: stackTrace,
);
}
}

class NativeAppStart {
Expand Down
43 changes: 43 additions & 0 deletions flutter/lib/src/native/sentry_native_binding.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import 'dart:async';

import 'package:meta/meta.dart';

import '../../sentry_flutter.dart';
import 'sentry_native.dart';

/// Provide typed methods to access native layer.
@internal
abstract class SentryNativeBinding {
// TODO Move other native calls here.

Future<NativeAppStart?> fetchNativeAppStart();

Future<void> beginNativeFrames();

Future<NativeFrames?> endNativeFrames(SentryId id);

Future<void> setUser(SentryUser? user);

Future<void> addBreadcrumb(Breadcrumb breadcrumb);

Future<void> clearBreadcrumbs();

Future<void> setContexts(String key, dynamic value);

Future<void> removeContexts(String key);

Future<void> setExtra(String key, dynamic value);

Future<void> removeExtra(String key);

Future<void> setTag(String key, String value);

Future<void> removeTag(String key);

int? startProfiler(SentryId traceId);

Future<void> discardProfiler(SentryId traceId);

Future<Map<String, dynamic>?> collectProfile(
SentryId traceId, int startTimeNs, int endTimeNs);
}
Loading

0 comments on commit f1482f4

Please sign in to comment.