Skip to content

Commit 0a82a1e

Browse files
denrasemarandaneto
andauthored
Add sent_at to envelope header (#1428)
Co-authored-by: Manoel Aranda Neto <[email protected]>
1 parent c3b5126 commit 0a82a1e

File tree

6 files changed

+54
-20
lines changed

6 files changed

+54
-20
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Features
6+
7+
- Add `sent_at` to envelope header ([#1428](https://github.com/getsentry/sentry-dart/pull/1428))
8+
59
### Fixes
610

711
- Fix battery level conversion for iOS 16.4 ([#1433](https://github.com/getsentry/sentry-dart/pull/1433))

dart/lib/src/sentry_envelope_header.dart

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'protocol/sentry_id.dart';
22
import 'protocol/sdk_version.dart';
33
import 'sentry_trace_context_header.dart';
4+
import 'utils.dart';
45

56
/// Header containing `SentryId` and `SdkVersion`.
67
class SentryEnvelopeHeader {
@@ -9,12 +10,14 @@ class SentryEnvelopeHeader {
910
this.sdkVersion, {
1011
this.dsn,
1112
this.traceContext,
13+
this.sentAt,
1214
});
1315
SentryEnvelopeHeader.newEventId()
1416
: eventId = SentryId.newId(),
1517
sdkVersion = null,
1618
dsn = null,
17-
traceContext = null;
19+
traceContext = null,
20+
sentAt = null;
1821

1922
/// The identifier of encoded `SentryEvent`.
2023
final SentryId? eventId;
@@ -27,6 +30,8 @@ class SentryEnvelopeHeader {
2730
/// The `DSN` of the Sentry project.
2831
final String? dsn;
2932

33+
DateTime? sentAt;
34+
3035
/// Header encoded as JSON
3136
Map<String, dynamic> toJson() {
3237
final json = <String, dynamic>{};
@@ -49,6 +54,11 @@ class SentryEnvelopeHeader {
4954
if (dsn != null) {
5055
json['dsn'] = dsn;
5156
}
57+
58+
if (sentAt != null) {
59+
json['sent_at'] = formatDateAsIso8601WithMillisPrecision(sentAt!);
60+
}
61+
5262
return json;
5363
}
5464
}

dart/lib/src/transport/http_transport.dart

+5-14
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ class HttpTransport implements Transport {
4646
_credentialBuilder = _CredentialBuilder(
4747
_dsn,
4848
_options.sentryClientName,
49-
_options.clock,
5049
);
5150
}
5251

@@ -56,6 +55,7 @@ class HttpTransport implements Transport {
5655
if (filteredEnvelope == null) {
5756
return SentryId.empty();
5857
}
58+
filteredEnvelope.header.sentAt = _options.clock();
5959

6060
final streamedRequest = await _createStreamedRequest(filteredEnvelope);
6161
final response = await _options.httpClient
@@ -135,23 +135,16 @@ class HttpTransport implements Transport {
135135
class _CredentialBuilder {
136136
final String _authHeader;
137137

138-
final ClockProvider _clock;
138+
_CredentialBuilder._(String authHeader) : _authHeader = authHeader;
139139

140-
int get timestamp => _clock().millisecondsSinceEpoch;
141-
142-
_CredentialBuilder._(String authHeader, ClockProvider clock)
143-
: _authHeader = authHeader,
144-
_clock = clock;
145-
146-
factory _CredentialBuilder(
147-
Dsn dsn, String sdkIdentifier, ClockProvider clock) {
140+
factory _CredentialBuilder(Dsn dsn, String sdkIdentifier) {
148141
final authHeader = _buildAuthHeader(
149142
publicKey: dsn.publicKey,
150143
secretKey: dsn.secretKey,
151144
sdkIdentifier: sdkIdentifier,
152145
);
153146

154-
return _CredentialBuilder._(authHeader, clock);
147+
return _CredentialBuilder._(authHeader);
155148
}
156149

157150
static String _buildAuthHeader({
@@ -172,9 +165,7 @@ class _CredentialBuilder {
172165
Map<String, String> configure(Map<String, String> headers) {
173166
return headers
174167
..addAll(
175-
<String, String>{
176-
'X-Sentry-Auth': '$_authHeader, sentry_timestamp=$timestamp'
177-
},
168+
<String, String>{'X-Sentry-Auth': _authHeader},
178169
);
179170
}
180171
}

dart/test/sentry_envelope_header_test.dart

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:sentry/sentry.dart';
22
import 'package:sentry/src/sentry_envelope_header.dart';
3+
import 'package:sentry/src/utils.dart';
34
import 'package:test/test.dart';
45

56
import 'mocks.dart';
@@ -22,18 +23,21 @@ void main() {
2223
'trace_id': '${SentryId.newId()}',
2324
'public_key': '123',
2425
});
26+
final timestamp = DateTime.utc(2019);
2527
final sut = SentryEnvelopeHeader(
2628
eventId,
2729
sdkVersion,
2830
dsn: fakeDsn,
2931
traceContext: context,
32+
sentAt: timestamp,
3033
);
3134
final expextedSkd = sdkVersion.toJson();
3235
final expected = <String, dynamic>{
3336
'event_id': eventId.toString(),
3437
'sdk': expextedSkd,
3538
'trace': context.toJson(),
3639
'dsn': fakeDsn,
40+
'sent_at': formatDateAsIso8601WithMillisPrecision(timestamp),
3741
};
3842
expect(sut.toJson(), expected);
3943
});

dart/test/test_utils.dart

+2-5
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,14 @@ void testHeaders(
3030
'Content-Type': 'application/x-sentry-envelope',
3131
'X-Sentry-Auth': 'Sentry sentry_version=7, '
3232
'sentry_client=$sdkName/$sdkVersion, '
33-
'sentry_key=public, '
33+
'sentry_key=public'
3434
};
3535

3636
if (withSecret) {
3737
expectedHeaders['X-Sentry-Auth'] =
38-
'${expectedHeaders['X-Sentry-Auth']!}sentry_secret=secret, ';
38+
'${expectedHeaders['X-Sentry-Auth']!}, sentry_secret=secret';
3939
}
4040

41-
expectedHeaders['X-Sentry-Auth'] =
42-
'${expectedHeaders['X-Sentry-Auth']!}sentry_timestamp=${fakeClockProvider().millisecondsSinceEpoch}';
43-
4441
if (withUserAgent) {
4542
expectedHeaders['User-Agent'] = '$sdkName/$sdkVersion';
4643
}

dart/test/transport/http_transport_test.dart

+28
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,31 @@ void main() {
159159
});
160160
});
161161

162+
group('sent_at', () {
163+
late Fixture fixture;
164+
165+
setUp(() {
166+
fixture = Fixture();
167+
});
168+
169+
test('capture envelope sets sent_at in header', () async {
170+
final sentryEvent = SentryEvent();
171+
final envelope = SentryEnvelope.fromEvent(
172+
sentryEvent,
173+
fixture.options.sdk,
174+
dsn: fixture.options.dsn,
175+
);
176+
177+
final httpMock = MockClient((http.Request request) async {
178+
return http.Response('{}', 200);
179+
});
180+
final sut = fixture.getSut(httpMock, MockRateLimiter());
181+
await sut.send(envelope);
182+
183+
expect(envelope.header.sentAt, DateTime.utc(2019));
184+
});
185+
});
186+
162187
group('client reports', () {
163188
late Fixture fixture;
164189

@@ -232,6 +257,9 @@ class Fixture {
232257
HttpTransport getSut(http.Client client, RateLimiter rateLimiter) {
233258
options.httpClient = client;
234259
options.recorder = clientReportRecorder;
260+
options.clock = () {
261+
return DateTime.utc(2019);
262+
};
235263
return HttpTransport(options, rateLimiter);
236264
}
237265
}

0 commit comments

Comments
 (0)