@@ -8,7 +8,7 @@ use anyhow::{Context, Result};
88use sentry:: protocol:: MetricType ;
99use sentry_core:: protocol:: { EnvelopeItem , ItemContainer } ;
1010use sentry_core:: test;
11- use sentry_core:: { ClientOptions , Hub } ;
11+ use sentry_core:: { ClientOptions , Hub , TransactionContext } ;
1212use sentry_types:: protocol:: v7:: Metric ;
1313
1414/// Test that metrics are sent when metrics are enabled.
@@ -204,6 +204,85 @@ fn test_metrics_batching_over_limit() {
204204 )
205205}
206206
207+ /// Test that metrics in the same scope share the same trace_id when no span is active.
208+ ///
209+ /// This tests that trace ID is set from the propagation context when there is no active span.
210+ #[ test]
211+ fn metrics_share_trace_id_without_active_span ( ) {
212+ let options = ClientOptions {
213+ enable_metrics : true ,
214+ ..Default :: default ( )
215+ } ;
216+
217+ let envelopes = test:: with_captured_envelopes_options (
218+ || {
219+ capture_test_metric ( "test-1" ) ;
220+ capture_test_metric ( "test-2" ) ;
221+ } ,
222+ options,
223+ ) ;
224+ let envelope = envelopes
225+ . try_into_only_item ( )
226+ . expect ( "expected one envelope" ) ;
227+ let item = envelope
228+ . into_items ( )
229+ . try_into_only_item ( )
230+ . expect ( "expected one item" ) ;
231+ let metrics = item. into_metrics ( ) . expect ( "expected metrics item" ) ;
232+
233+ let [ metric1, metric2] = metrics. as_slice ( ) else {
234+ panic ! ( "expected exactly two metrics" ) ;
235+ } ;
236+
237+ assert_eq ! (
238+ metric1. trace_id, metric2. trace_id,
239+ "metrics in the same scope should share the same trace_id"
240+ ) ;
241+
242+ assert ! ( metric1. span_id. is_none( ) ) ;
243+ assert ! ( metric2. span_id. is_none( ) ) ;
244+ }
245+
246+ /// Test that span_id is set from the active span when one is present.
247+ #[ test]
248+ fn metrics_span_id_from_active_span ( ) {
249+ let options = ClientOptions {
250+ enable_metrics : true ,
251+ ..Default :: default ( )
252+ } ;
253+
254+ let mut expected_span_id = None ;
255+ let envelopes = test:: with_captured_envelopes_options (
256+ || {
257+ let transaction_ctx = TransactionContext :: new ( "test transaction" , "test" ) ;
258+ expected_span_id = Some ( transaction_ctx. span_id ( ) ) ;
259+ let transaction = sentry_core:: start_transaction ( transaction_ctx) ;
260+ sentry_core:: configure_scope ( |scope| scope. set_span ( Some ( transaction. clone ( ) . into ( ) ) ) ) ;
261+ capture_test_metric ( "test" ) ;
262+ transaction. finish ( ) ;
263+ } ,
264+ options,
265+ ) ;
266+
267+ let expected_span_id = expected_span_id. expect ( "expected_span_id did not get set" ) ;
268+
269+ let envelope = envelopes
270+ . try_into_only_item ( )
271+ . expect ( "expected one envelope" ) ;
272+ let item = envelope
273+ . into_items ( )
274+ . try_into_only_item ( )
275+ . expect ( "expected one item" ) ;
276+ let mut metrics = item. into_metrics ( ) . expect ( "expected metrics item" ) ;
277+ let metric = metrics. pop ( ) . expect ( "expected one metric" ) ;
278+
279+ assert_eq ! (
280+ metric. span_id,
281+ Some ( expected_span_id) ,
282+ "span_id should be set from the active span"
283+ ) ;
284+ }
285+
207286/// Returns a [`Metric`] with [type `Counter`](MetricType),
208287/// the provided name, and a value of `1.0`.
209288fn test_metric < S > ( name : S ) -> Metric
0 commit comments