Skip to content

parse and report async gaps #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion bin/test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ Future<Null> main(List<String> rawArgs) async {
final SentryClient client = new SentryClient(dsn: dsn);

try {
throw new StateError('This is a test error');
await foo();
} catch (error, stackTrace) {
print('Reporting the following stack trace: ');
print(stackTrace);
final SentryResponse response = await client.captureException(
exception: error,
stackTrace: stackTrace,
Expand All @@ -35,3 +37,15 @@ Future<Null> main(List<String> rawArgs) async {
await client.close();
}
}

Future<Null> foo() async {
await bar();
}

Future<Null> bar() async {
await baz();
}

Future<Null> baz() async {
throw new StateError('This is a test error');
}
8 changes: 1 addition & 7 deletions lib/sentry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import 'dart:io';
import 'package:http/http.dart';
import 'package:meta/meta.dart';
import 'package:quiver/time.dart';
import 'package:stack_trace/stack_trace.dart';
import 'package:usage/uuid/uuid.dart';

import 'src/stack_trace.dart';
Expand Down Expand Up @@ -377,13 +376,8 @@ class Event {
}

if (stackTrace != null) {
assert(stackTrace is String || stackTrace is StackTrace);
final Trace trace = stackTrace is StackTrace
? new Trace.from(stackTrace)
: new Trace.parse(stackTrace);

json['stacktrace'] = <String, dynamic>{
'frames': trace.frames.map(stackTraceFrameToJsonFrame).toList(),
'frames': encodeStackTrace(stackTrace),
};
}

Expand Down
25 changes: 24 additions & 1 deletion lib/src/stack_trace.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,30 @@

import 'package:stack_trace/stack_trace.dart';

Map<String, dynamic> stackTraceFrameToJsonFrame(Frame frame) {
/// Sentry.io JSON encoding of a stack frame for the asynchronous suspension,
/// which is the gap between asynchronous calls.
const Map<String, dynamic> asynchronousGapFrameJson = const <String, dynamic>{
'abs_path': '<asynchronous suspension>',
};

/// Encodes [strackTrace] as JSON in the Sentry.io format.
///
/// [stackTrace] must be [String] or [StackTrace].
List<Map<String, dynamic>> encodeStackTrace(dynamic stackTrace) {
assert(stackTrace is String || stackTrace is StackTrace);
final Chain chain = stackTrace is StackTrace
? new Chain.forTrace(stackTrace)
: new Chain.parse(stackTrace);

final List<Map<String, dynamic>> frames = <Map<String, dynamic>>[];
for (int t = 0; t < chain.traces.length; t += 1) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not t++?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's Flutter style.

frames.addAll(chain.traces[t].frames.map(encodeStackTraceFrame));
if (t < chain.traces.length - 1) frames.add(asynchronousGapFrameJson);
}
return frames;
}

Map<String, dynamic> encodeStackTraceFrame(Frame frame) {
final Map<String, dynamic> json = <String, dynamic>{
'abs_path': _absolutePathForCrashReport(frame),
'function': frame.member,
Expand Down
2 changes: 1 addition & 1 deletion lib/src/version.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
library version;

/// The SDK version reported to Sentry.io in the submitted events.
const String sdkVersion = '0.0.3';
const String sdkVersion = '0.0.4';

/// The SDK name reported to Sentry.io in the submitted events.
const String sdkName = 'dart';
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: sentry
version: 0.0.3
version: 0.0.4
description: A pure Dart Sentry.io client.
author: Yegor Jbanov <[email protected]>
homepage: https://github.com/yjbanov/sentry
Expand Down
56 changes: 53 additions & 3 deletions test/stack_trace_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import 'package:stack_trace/stack_trace.dart';
import 'package:test/test.dart';

void main() {
group('stackTraceFrameToJsonFrame', () {
group('encodeStackTraceFrame', () {
test('marks dart: frames as not app frames', () {
final Frame frame = new Frame(Uri.parse('dart:core'), 1, 2, 'buzz');
expect(stackTraceFrameToJsonFrame(frame), {
expect(encodeStackTraceFrame(frame), {
'abs_path': 'dart:core',
'function': 'buzz',
'lineno': 1,
Expand All @@ -22,7 +22,57 @@ void main() {
test('cleanses absolute paths', () {
final Frame frame =
new Frame(Uri.parse('file://foo/bar/baz.dart'), 1, 2, 'buzz');
expect(stackTraceFrameToJsonFrame(frame)['abs_path'], 'baz.dart');
expect(encodeStackTraceFrame(frame)['abs_path'], 'baz.dart');
});
});

group('encodeStackTrace', () {
test('encodes a simple stack trace', () {
expect(encodeStackTrace('''
#0 baz (file:///pathto/test.dart:50:3)
#1 bar (file:///pathto/test.dart:46:9)
'''), [
{
'abs_path': 'test.dart',
'function': 'baz',
'lineno': 50,
'in_app': true,
'filename': 'test.dart'
},
{
'abs_path': 'test.dart',
'function': 'bar',
'lineno': 46,
'in_app': true,
'filename': 'test.dart'
}
]);
});

test('encodes an asynchronous stack trace', () {
expect(encodeStackTrace('''
#0 baz (file:///pathto/test.dart:50:3)
<asynchronous suspension>
#1 bar (file:///pathto/test.dart:46:9)
'''), [
{
'abs_path': 'test.dart',
'function': 'baz',
'lineno': 50,
'in_app': true,
'filename': 'test.dart'
},
{
'abs_path': '<asynchronous suspension>',
},
{
'abs_path': 'test.dart',
'function': 'bar',
'lineno': 46,
'in_app': true,
'filename': 'test.dart'
}
]);
});
});
}