Skip to content

Commit 09f8959

Browse files
authored
Logs: Models & Envelopes (#2916)
1 parent 18b7c08 commit 09f8959

14 files changed

+340
-1
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Features
6+
7+
- Logs: Models & Envelopes ([#2916](https://github.com/getsentry/sentry-dart/pull/2916))
8+
39
## 9.0.0-beta.2
410

511
### Fixes

dart/lib/src/protocol.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,6 @@ export 'protocol/span_status.dart';
4141
export 'sentry_event_like.dart';
4242
export 'protocol/sentry_feature_flag.dart';
4343
export 'protocol/sentry_feature_flags.dart';
44+
export 'protocol/sentry_log.dart';
45+
export 'protocol/sentry_log_level.dart';
46+
export 'protocol/sentry_log_attribute.dart';
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import 'sentry_id.dart';
2+
import 'sentry_log_level.dart';
3+
import 'sentry_log_attribute.dart';
4+
5+
class SentryLog {
6+
DateTime timestamp;
7+
SentryId traceId;
8+
SentryLogLevel level;
9+
String body;
10+
Map<String, SentryLogAttribute> attributes;
11+
int? severityNumber;
12+
13+
SentryLog({
14+
required this.timestamp,
15+
required this.traceId,
16+
required this.level,
17+
required this.body,
18+
required this.attributes,
19+
this.severityNumber,
20+
});
21+
22+
Map<String, dynamic> toJson() {
23+
return {
24+
'timestamp': timestamp.toIso8601String(),
25+
'trace_id': traceId.toString(),
26+
'level': level.value,
27+
'body': body,
28+
'attributes':
29+
attributes.map((key, value) => MapEntry(key, value.toJson())),
30+
'severity_number': severityNumber ?? level.toSeverityNumber(),
31+
};
32+
}
33+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
class SentryLogAttribute {
2+
final dynamic value;
3+
final String type;
4+
5+
const SentryLogAttribute._(this.value, this.type);
6+
7+
factory SentryLogAttribute.string(String value) {
8+
return SentryLogAttribute._(value, 'string');
9+
}
10+
11+
factory SentryLogAttribute.boolean(bool value) {
12+
return SentryLogAttribute._(value, 'boolean');
13+
}
14+
15+
factory SentryLogAttribute.integer(int value) {
16+
return SentryLogAttribute._(value, 'integer');
17+
}
18+
19+
factory SentryLogAttribute.double(double value) {
20+
return SentryLogAttribute._(value, 'double');
21+
}
22+
23+
// In the future the SDK will also support string[], boolean[], integer[], double[] values.
24+
Map<String, dynamic> toJson() {
25+
return {
26+
'value': value,
27+
'type': type,
28+
};
29+
}
30+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
enum SentryLogLevel {
2+
trace('trace'),
3+
debug('debug'),
4+
info('info'),
5+
warn('warn'),
6+
error('error'),
7+
fatal('fatal');
8+
9+
final String value;
10+
const SentryLogLevel(this.value);
11+
12+
int toSeverityNumber() {
13+
switch (this) {
14+
case SentryLogLevel.trace:
15+
return 1;
16+
case SentryLogLevel.debug:
17+
return 5;
18+
case SentryLogLevel.info:
19+
return 9;
20+
case SentryLogLevel.warn:
21+
return 13;
22+
case SentryLogLevel.error:
23+
return 17;
24+
case SentryLogLevel.fatal:
25+
return 21;
26+
}
27+
}
28+
}

dart/lib/src/sentry_envelope.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,21 @@ class SentryEnvelope {
8181
);
8282
}
8383

84+
factory SentryEnvelope.fromLogs(
85+
List<SentryLog> items,
86+
SdkVersion sdkVersion,
87+
) {
88+
return SentryEnvelope(
89+
SentryEnvelopeHeader(
90+
null,
91+
sdkVersion,
92+
),
93+
[
94+
SentryEnvelopeItem.fromLogs(items),
95+
],
96+
);
97+
}
98+
8499
/// Stream binary data representation of `Envelope` file encoded.
85100
Stream<List<int>> envelopeStream(SentryOptions options) async* {
86101
yield utf8JsonEncoder.convert(header.toJson());

dart/lib/src/sentry_envelope_item.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,21 @@ class SentryEnvelopeItem {
6363
);
6464
}
6565

66+
factory SentryEnvelopeItem.fromLogs(List<SentryLog> items) {
67+
final payload = {
68+
'items': items.map((e) => e.toJson()).toList(),
69+
};
70+
return SentryEnvelopeItem(
71+
SentryEnvelopeItemHeader(
72+
SentryItemType.log,
73+
itemCount: items.length,
74+
contentType: 'application/vnd.sentry.items.log+json',
75+
),
76+
() => utf8JsonEncoder.convert(payload),
77+
originalObject: payload,
78+
);
79+
}
80+
6681
/// Header with info about type and length of data in bytes.
6782
final SentryEnvelopeItemHeader header;
6883

dart/lib/src/sentry_envelope_item_header.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
class SentryEnvelopeItemHeader {
33
SentryEnvelopeItemHeader(
44
this.type, {
5+
this.itemCount,
56
this.contentType,
67
this.fileName,
78
this.attachmentType,
@@ -10,6 +11,8 @@ class SentryEnvelopeItemHeader {
1011
/// Type of encoded data.
1112
final String type;
1213

14+
final int? itemCount;
15+
1316
final String? contentType;
1417

1518
final String? fileName;
@@ -19,6 +22,7 @@ class SentryEnvelopeItemHeader {
1922
/// Item header encoded as JSON
2023
Future<Map<String, dynamic>> toJson(int length) async {
2124
return {
25+
if (itemCount != null) 'item_count': itemCount,
2226
if (contentType != null) 'content_type': contentType,
2327
if (fileName != null) 'filename': fileName,
2428
if (attachmentType != null) 'attachment_type': attachmentType,

dart/lib/src/sentry_item_type.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ class SentryItemType {
55
static const String clientReport = 'client_report';
66
static const String profile = 'profile';
77
static const String statsd = 'statsd';
8+
static const String log = 'log';
89
static const String unknown = '__unknown__';
910
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import 'package:test/test.dart';
2+
import 'package:sentry/sentry.dart';
3+
4+
void main() {
5+
test('$SentryLogAttribute string to json', () {
6+
final attribute = SentryLogAttribute.string('test');
7+
final json = attribute.toJson();
8+
expect(json, {
9+
'value': 'test',
10+
'type': 'string',
11+
});
12+
});
13+
14+
test('$SentryLogAttribute boolean to json', () {
15+
final attribute = SentryLogAttribute.boolean(true);
16+
final json = attribute.toJson();
17+
expect(json, {
18+
'value': true,
19+
'type': 'boolean',
20+
});
21+
});
22+
23+
test('$SentryLogAttribute integer to json', () {
24+
final attribute = SentryLogAttribute.integer(1);
25+
final json = attribute.toJson();
26+
27+
expect(json, {
28+
'value': 1,
29+
'type': 'integer',
30+
});
31+
});
32+
33+
test('$SentryLogAttribute double to json', () {
34+
final attribute = SentryLogAttribute.double(1.0);
35+
final json = attribute.toJson();
36+
37+
expect(json, {
38+
'value': 1.0,
39+
'type': 'double',
40+
});
41+
});
42+
}

0 commit comments

Comments
 (0)