Skip to content

Commit 8eb612e

Browse files
feat: extend performance API with explicit timings (#1093)
* Extended API to allow explicit timings * Add tests for timestamped API functions * re-add todos and comments that went missing in refactoring * update changelog * update docstrings for new API * apply refactoring suggestion from code review * change assert_timestamp to be more accurate * cleanup unnecessary includes
1 parent f051f4c commit 8eb612e

File tree

8 files changed

+235
-45
lines changed

8 files changed

+235
-45
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
**Features**:
66
- Add SOCKS5 proxy support for macOS and Linux. ([#1063](https://github.com/getsentry/sentry-native/pull/1063))
7+
- Extend performance API with explicit timings ([#1093](https://github.com/getsentry/sentry-native/pull/1093))
78

89
## 0.7.15
910

include/sentry.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,6 +1736,16 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_update_from_header_n(
17361736
*/
17371737
SENTRY_EXPERIMENTAL_API sentry_transaction_t *sentry_transaction_start(
17381738
sentry_transaction_context_t *tx_cxt, sentry_value_t sampling_ctx);
1739+
/**
1740+
* Also starts a transaction like the regular `sentry_transaction_start`
1741+
* function, but has an additional timestamp parameter to let the user provide
1742+
* explicit timings.
1743+
*
1744+
* The timestamp should be provided in microseconds since the Unix epoch.
1745+
*/
1746+
SENTRY_EXPERIMENTAL_API sentry_transaction_t *sentry_transaction_start_ts(
1747+
sentry_transaction_context_t *tx_cxt, sentry_value_t sampling_ctx,
1748+
uint64_t timestamp);
17391749

17401750
/**
17411751
* Finishes and sends a Transaction to sentry. The event ID of the Transaction
@@ -1748,6 +1758,15 @@ SENTRY_EXPERIMENTAL_API sentry_transaction_t *sentry_transaction_start(
17481758
*/
17491759
SENTRY_EXPERIMENTAL_API sentry_uuid_t sentry_transaction_finish(
17501760
sentry_transaction_t *tx);
1761+
/**
1762+
* Also finishes a transaction like the regular `sentry_transaction_finish`
1763+
* function, but has an additional timestamp parameter to let the user provide
1764+
* explicit timings.
1765+
*
1766+
* The timestamp should be provided in microseconds since the Unix epoch.
1767+
*/
1768+
SENTRY_EXPERIMENTAL_API sentry_uuid_t sentry_transaction_finish_ts(
1769+
sentry_transaction_t *tx, uint64_t timestamp);
17511770

17521771
/**
17531772
* Sets the Transaction so any Events sent while the Transaction
@@ -1816,6 +1835,19 @@ SENTRY_EXPERIMENTAL_API sentry_span_t *sentry_transaction_start_child(
18161835
SENTRY_EXPERIMENTAL_API sentry_span_t *sentry_transaction_start_child_n(
18171836
sentry_transaction_t *parent, const char *operation, size_t operation_len,
18181837
const char *description, size_t description_len);
1838+
/**
1839+
* Also starts a span like the regular `sentry_transaction_start_child_ts`
1840+
* functions, but has an additional timestamp parameter to let the user provide
1841+
* explicit timings.
1842+
*
1843+
* The timestamp should be provided in microseconds since the Unix epoch.
1844+
*/
1845+
SENTRY_EXPERIMENTAL_API sentry_span_t *sentry_transaction_start_child_ts(
1846+
sentry_transaction_t *parent, const char *operation,
1847+
const char *description, uint64_t timestamp);
1848+
SENTRY_EXPERIMENTAL_API sentry_span_t *sentry_transaction_start_child_ts_n(
1849+
sentry_transaction_t *parent, const char *operation, size_t operation_len,
1850+
const char *description, size_t description_len, uint64_t timestamp);
18191851

18201852
/**
18211853
* Starts a new Span.
@@ -1852,6 +1884,19 @@ SENTRY_EXPERIMENTAL_API sentry_span_t *sentry_span_start_child(
18521884
SENTRY_EXPERIMENTAL_API sentry_span_t *sentry_span_start_child_n(
18531885
sentry_span_t *parent, const char *operation, size_t operation_len,
18541886
const char *description, size_t description_len);
1887+
/**
1888+
* Also starts a span like the regular `sentry_span_start_child_ts` functions,
1889+
* but has an additional timestamp parameter to let the user provide explicit
1890+
* timings.
1891+
*
1892+
* The timestamp should be provided in microseconds since the Unix epoch.
1893+
*/
1894+
SENTRY_EXPERIMENTAL_API sentry_span_t *sentry_span_start_child_ts(
1895+
sentry_span_t *parent, const char *operation, const char *description,
1896+
uint64_t timestamp);
1897+
SENTRY_EXPERIMENTAL_API sentry_span_t *sentry_span_start_child_ts_n(
1898+
sentry_span_t *parent, const char *operation, size_t operation_len,
1899+
const char *description, size_t description_len, uint64_t timestamp);
18551900

18561901
/**
18571902
* Finishes a Span.
@@ -1864,6 +1909,14 @@ SENTRY_EXPERIMENTAL_API sentry_span_t *sentry_span_start_child_n(
18641909
* span.
18651910
*/
18661911
SENTRY_EXPERIMENTAL_API void sentry_span_finish(sentry_span_t *span);
1912+
/**
1913+
* Also finishes a span like the regular `sentry_span_finish` function, but has
1914+
* an additional timestamp parameter to let the user provide explicit timings.
1915+
*
1916+
* The timestamp should be provided in microseconds since the Unix epoch.
1917+
*/
1918+
SENTRY_EXPERIMENTAL_API void sentry_span_finish_ts(
1919+
sentry_span_t *span, uint64_t timestamp);
18671920

18681921
/**
18691922
* Sets a tag on a Transaction to the given string value.

src/sentry_core.c

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,14 @@ sentry_set_level(sentry_level_t level)
842842
sentry_transaction_t *
843843
sentry_transaction_start(
844844
sentry_transaction_context_t *opaque_tx_cxt, sentry_value_t sampling_ctx)
845+
{
846+
return sentry_transaction_start_ts(
847+
opaque_tx_cxt, sampling_ctx, sentry__usec_time());
848+
}
849+
850+
sentry_transaction_t *
851+
sentry_transaction_start_ts(sentry_transaction_context_t *opaque_tx_cxt,
852+
sentry_value_t sampling_ctx, uint64_t timestamp)
845853
{
846854
// Just free this immediately until we implement proper support for
847855
// traces_sampler.
@@ -874,14 +882,21 @@ sentry_transaction_start(
874882

875883
sentry_value_set_by_key(tx, "start_timestamp",
876884
sentry__value_new_string_owned(
877-
sentry__usec_time_to_iso8601(sentry__usec_time())));
885+
sentry__usec_time_to_iso8601(timestamp)));
878886

879887
sentry__transaction_context_free(opaque_tx_cxt);
880888
return sentry__transaction_new(tx);
881889
}
882890

883891
sentry_uuid_t
884892
sentry_transaction_finish(sentry_transaction_t *opaque_tx)
893+
{
894+
return sentry_transaction_finish_ts(opaque_tx, sentry__usec_time());
895+
}
896+
897+
sentry_uuid_t
898+
sentry_transaction_finish_ts(
899+
sentry_transaction_t *opaque_tx, uint64_t timestamp)
885900
{
886901
if (!opaque_tx || sentry_value_is_null(opaque_tx->inner)) {
887902
SENTRY_DEBUG("no transaction available to finish");
@@ -919,7 +934,7 @@ sentry_transaction_finish(sentry_transaction_t *opaque_tx)
919934
sentry_value_set_by_key(tx, "type", sentry_value_new_string("transaction"));
920935
sentry_value_set_by_key(tx, "timestamp",
921936
sentry__value_new_string_owned(
922-
sentry__usec_time_to_iso8601(sentry__usec_time())));
937+
sentry__usec_time_to_iso8601(timestamp)));
923938
// TODO: This might not actually be necessary. Revisit after talking to
924939
// the relay team about this.
925940
sentry_value_set_by_key(tx, "level", sentry_value_new_string("info"));
@@ -987,6 +1002,24 @@ sentry_span_t *
9871002
sentry_transaction_start_child_n(sentry_transaction_t *opaque_parent,
9881003
const char *operation, size_t operation_len, const char *description,
9891004
size_t description_len)
1005+
{
1006+
return sentry_transaction_start_child_ts_n(opaque_parent, operation,
1007+
operation_len, description, description_len, sentry__usec_time());
1008+
}
1009+
1010+
sentry_span_t *
1011+
sentry_transaction_start_child(sentry_transaction_t *opaque_parent,
1012+
const char *operation, const char *description)
1013+
{
1014+
return sentry_transaction_start_child_n(opaque_parent, operation,
1015+
sentry__guarded_strlen(operation), description,
1016+
sentry__guarded_strlen(description));
1017+
}
1018+
1019+
sentry_span_t *
1020+
sentry_transaction_start_child_ts_n(sentry_transaction_t *opaque_parent,
1021+
const char *operation, size_t operation_len, const char *description,
1022+
size_t description_len, const uint64_t timestamp)
9901023
{
9911024
if (!opaque_parent || sentry_value_is_null(opaque_parent->inner)) {
9921025
SENTRY_DEBUG("no transaction available to create a child under");
@@ -1003,22 +1036,40 @@ sentry_transaction_start_child_n(sentry_transaction_t *opaque_parent,
10031036

10041037
sentry_value_t span = sentry__value_span_new_n(max_spans, parent,
10051038
(sentry_slice_t) { operation, operation_len },
1006-
(sentry_slice_t) { description, description_len });
1039+
(sentry_slice_t) { description, description_len }, timestamp);
10071040
return sentry__span_new(opaque_parent, span);
10081041
}
10091042

10101043
sentry_span_t *
1011-
sentry_transaction_start_child(sentry_transaction_t *opaque_parent,
1012-
const char *operation, const char *description)
1044+
sentry_transaction_start_child_ts(sentry_transaction_t *opaque_parent,
1045+
const char *operation, const char *description, const uint64_t timestamp)
10131046
{
1014-
return sentry_transaction_start_child_n(opaque_parent, operation,
1047+
return sentry_transaction_start_child_ts_n(opaque_parent, operation,
10151048
sentry__guarded_strlen(operation), description,
1016-
sentry__guarded_strlen(description));
1049+
sentry__guarded_strlen(description), timestamp);
10171050
}
10181051

10191052
sentry_span_t *
10201053
sentry_span_start_child_n(sentry_span_t *opaque_parent, const char *operation,
10211054
size_t operation_len, const char *description, size_t description_len)
1055+
{
1056+
return sentry_span_start_child_ts_n(opaque_parent, operation, operation_len,
1057+
description, description_len, sentry__usec_time());
1058+
}
1059+
1060+
sentry_span_t *
1061+
sentry_span_start_child(sentry_span_t *opaque_parent, const char *operation,
1062+
const char *description)
1063+
{
1064+
return sentry_span_start_child_n(opaque_parent, operation,
1065+
sentry__guarded_strlen(operation), description,
1066+
sentry__guarded_strlen(description));
1067+
}
1068+
1069+
sentry_span_t *
1070+
sentry_span_start_child_ts_n(sentry_span_t *opaque_parent,
1071+
const char *operation, size_t operation_len, const char *description,
1072+
size_t description_len, uint64_t timestamp)
10221073
{
10231074
if (!opaque_parent || sentry_value_is_null(opaque_parent->inner)) {
10241075
SENTRY_DEBUG("no parent span available to create a child span under");
@@ -1039,22 +1090,28 @@ sentry_span_start_child_n(sentry_span_t *opaque_parent, const char *operation,
10391090

10401091
sentry_value_t span = sentry__value_span_new_n(max_spans, parent,
10411092
(sentry_slice_t) { operation, operation_len },
1042-
(sentry_slice_t) { description, description_len });
1093+
(sentry_slice_t) { description, description_len }, timestamp);
10431094

10441095
return sentry__span_new(opaque_parent->transaction, span);
10451096
}
10461097

10471098
sentry_span_t *
1048-
sentry_span_start_child(sentry_span_t *opaque_parent, const char *operation,
1049-
const char *description)
1099+
sentry_span_start_child_ts(sentry_span_t *opaque_parent, const char *operation,
1100+
const char *description, uint64_t timestamp)
10501101
{
1051-
return sentry_span_start_child_n(opaque_parent, operation,
1102+
return sentry_span_start_child_ts_n(opaque_parent, operation,
10521103
sentry__guarded_strlen(operation), description,
1053-
sentry__guarded_strlen(description));
1104+
sentry__guarded_strlen(description), timestamp);
10541105
}
10551106

10561107
void
10571108
sentry_span_finish(sentry_span_t *opaque_span)
1109+
{
1110+
sentry_span_finish_ts(opaque_span, sentry__usec_time());
1111+
}
1112+
1113+
void
1114+
sentry_span_finish_ts(sentry_span_t *opaque_span, uint64_t timestamp)
10581115
{
10591116
if (!opaque_span || sentry_value_is_null(opaque_span->inner)) {
10601117
SENTRY_DEBUG("no span to finish");
@@ -1118,7 +1175,7 @@ sentry_span_finish(sentry_span_t *opaque_span)
11181175

11191176
sentry_value_set_by_key(span, "timestamp",
11201177
sentry__value_new_string_owned(
1121-
sentry__usec_time_to_iso8601(sentry__usec_time())));
1178+
sentry__usec_time_to_iso8601(timestamp)));
11221179
sentry_value_remove_by_key(span, "sampled");
11231180

11241181
size_t max_spans = SENTRY_SPANS_MAX;

src/sentry_tracing.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ sentry__span_new(sentry_transaction_t *tx, sentry_value_t inner)
356356

357357
sentry_value_t
358358
sentry__value_span_new_n(size_t max_spans, sentry_value_t parent,
359-
sentry_slice_t operation, sentry_slice_t description)
359+
sentry_slice_t operation, sentry_slice_t description, uint64_t timestamp)
360360
{
361361
if (!sentry_value_is_null(sentry_value_get_by_key(parent, "timestamp"))) {
362362
SENTRY_DEBUG("span's parent is already finished, not creating span");
@@ -378,7 +378,7 @@ sentry__value_span_new_n(size_t max_spans, sentry_value_t parent,
378378
sentry_value_new_string_n(description.ptr, description.len));
379379
sentry_value_set_by_key(child, "start_timestamp",
380380
sentry__value_new_string_owned(
381-
sentry__usec_time_to_iso8601(sentry__usec_time())));
381+
sentry__usec_time_to_iso8601(timestamp)));
382382

383383
return child;
384384
fail:
@@ -387,10 +387,11 @@ sentry__value_span_new_n(size_t max_spans, sentry_value_t parent,
387387

388388
sentry_value_t
389389
sentry__value_span_new(size_t max_spans, sentry_value_t parent,
390-
const char *operation, const char *description)
390+
const char *operation, const char *description, uint64_t timestamp)
391391
{
392392
return sentry__value_span_new_n(max_spans, parent,
393-
sentry__slice_from_str(operation), sentry__slice_from_str(description));
393+
sentry__slice_from_str(operation), sentry__slice_from_str(description),
394+
timestamp);
394395
}
395396

396397
sentry_value_t

src/sentry_tracing.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ void sentry__span_incref(sentry_span_t *span);
3737
void sentry__span_decref(sentry_span_t *span);
3838

3939
sentry_value_t sentry__value_span_new(size_t max_spans, sentry_value_t parent,
40-
const char *operation, const char *description);
40+
const char *operation, const char *description, uint64_t timestamp);
4141
sentry_value_t sentry__value_span_new_n(size_t max_spans, sentry_value_t parent,
42-
sentry_slice_t operation, sentry_slice_t description);
42+
sentry_slice_t operation, sentry_slice_t description, uint64_t timestamp);
4343

4444
sentry_span_t *sentry__span_new(
4545
sentry_transaction_t *parent_tx, sentry_value_t inner);

tests/assertions.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,9 @@ def assert_minidump(envelope):
205205
assert minidump.payload.bytes.startswith(b"MDMP")
206206

207207

208-
def assert_timestamp(ts, now=datetime.now(UTC)):
209-
assert ts[:11] == now.isoformat()[:11]
208+
def assert_timestamp(ts):
209+
elapsed_time = datetime.now(UTC) - datetime.fromisoformat(ts)
210+
assert elapsed_time.total_seconds() < 10
210211

211212

212213
def assert_event(envelope, message="Hello World!"):

0 commit comments

Comments
 (0)