nextest_runner/
usdt.rs

1// Copyright (c) The nextest Contributors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! [USDT](usdt) probes for nextest.
5//!
6//! This module acts as documentation for USDT (Userland Statically Defined
7//! Tracing) probes defined by nextest.
8//!
9//! USDT probes are supported:
10//!
11//! * On x86_64: Linux, via [bpftrace](https://bpftrace.org/)
12//! * On aarch64: macOS, via [DTrace](https://dtrace.org/)
13//! * On x86_64 and aarch64: illumos and other Solaris derivatives, and FreeBSD, via [DTrace](https://dtrace.org/)
14//!
15//! The probes and their contents are not part of nextest's stability guarantees.
16//!
17//! For more information and examples, see the [nextest documentation](https://nexte.st/docs/integrations/usdt).
18
19use nextest_metadata::RustBinaryId;
20use quick_junit::ReportUuid;
21use serde::Serialize;
22
23/// Register USDT probes on supported platforms.
24#[cfg(any(
25    all(
26        target_arch = "x86_64",
27        any(target_os = "linux", target_os = "freebsd", target_os = "illumos")
28    ),
29    all(
30        target_arch = "aarch64",
31        any(target_os = "macos", target_os = "freebsd", target_os = "illumos")
32    )
33))]
34pub fn register_probes() -> Result<(), usdt::Error> {
35    usdt::register_probes()
36}
37
38/// No-op for unsupported platforms.
39#[cfg(not(any(
40    all(
41        target_arch = "x86_64",
42        any(target_os = "linux", target_os = "freebsd", target_os = "illumos")
43    ),
44    all(
45        target_arch = "aarch64",
46        any(target_os = "macos", target_os = "freebsd", target_os = "illumos")
47    )
48)))]
49pub fn register_probes() -> Result<(), std::convert::Infallible> {
50    Ok(())
51}
52
53#[cfg(any(
54    all(
55        target_arch = "x86_64",
56        any(target_os = "linux", target_os = "freebsd", target_os = "illumos")
57    ),
58    all(
59        target_arch = "aarch64",
60        any(target_os = "macos", target_os = "freebsd", target_os = "illumos")
61    )
62))]
63#[usdt::provider(provider = "nextest")]
64pub mod usdt_probes {
65    use crate::usdt::*;
66
67    pub fn test__attempt__start(
68        attempt: &UsdtTestAttemptStart,
69        attempt_id: &str,
70        binary_id: &str,
71        test_name: &str,
72        pid: u32,
73    ) {
74    }
75    pub fn test__attempt__done(
76        attempt: &UsdtTestAttemptDone,
77        attempt_id: &str,
78        binary_id: &str,
79        test_name: &str,
80        result: &str,
81        duration_nanos: u64,
82    ) {
83    }
84    pub fn test__attempt__slow(
85        slow: &UsdtTestAttemptSlow,
86        attempt_id: &str,
87        binary_id: &str,
88        test_name: &str,
89        elapsed_nanos: u64,
90    ) {
91    }
92    pub fn setup__script__start(
93        script: &UsdtSetupScriptStart,
94        id: &str,
95        script_id: &str,
96        pid: u32,
97    ) {
98    }
99    pub fn setup__script__slow(
100        script: &UsdtSetupScriptSlow,
101        id: &str,
102        script_id: &str,
103        elapsed_nanos: u64,
104    ) {
105    }
106    pub fn setup__script__done(
107        script: &UsdtSetupScriptDone,
108        id: &str,
109        script_id: &str,
110        result: &str,
111        duration_nanos: u64,
112    ) {
113    }
114    pub fn run__start(run: &UsdtRunStart, run_id: ReportUuid) {}
115    pub fn run__done(run: &UsdtRunDone, run_id: ReportUuid) {}
116    pub fn stress__sub__run__start(
117        sub_run: &UsdtStressSubRunStart,
118        stress_sub_run_id: &str,
119        stress_current: u32,
120    ) {
121    }
122    pub fn stress__sub__run__done(
123        sub_run: &UsdtStressSubRunDone,
124        stress_sub_run_id: &str,
125        stress_current: u32,
126    ) {
127    }
128}
129
130/// Fires a USDT probe on supported platforms.
131#[cfg(any(
132    all(
133        target_arch = "x86_64",
134        any(target_os = "linux", target_os = "freebsd", target_os = "illumos")
135    ),
136    all(
137        target_arch = "aarch64",
138        any(target_os = "macos", target_os = "freebsd", target_os = "illumos")
139    )
140))]
141#[macro_export]
142macro_rules! fire_usdt {
143    (UsdtTestAttemptStart { $($tt:tt)* }) => {{
144        $crate::usdt::usdt_probes::test__attempt__start!(|| {
145            let probe = $crate::usdt::UsdtTestAttemptStart { $($tt)* };
146            let attempt_id = probe.attempt_id.clone();
147            let binary_id = probe.binary_id.to_string();
148            let test_name = probe.test_name.clone();
149            let pid = probe.pid;
150            (probe, attempt_id, binary_id, test_name, pid)
151        })
152    }};
153    (UsdtTestAttemptDone { $($tt:tt)* }) => {{
154        $crate::usdt::usdt_probes::test__attempt__done!(|| {
155            let probe = $crate::usdt::UsdtTestAttemptDone { $($tt)* };
156            let attempt_id = probe.attempt_id.clone();
157            let binary_id = probe.binary_id.to_string();
158            let test_name = probe.test_name.clone();
159            let result = probe.result;
160            let duration_nanos = probe.duration_nanos;
161            (
162                probe,
163                attempt_id,
164                binary_id,
165                test_name,
166                result,
167                duration_nanos,
168            )
169        })
170    }};
171    (UsdtTestAttemptSlow { $($tt:tt)* }) => {{
172        $crate::usdt::usdt_probes::test__attempt__slow!(|| {
173            let probe = $crate::usdt::UsdtTestAttemptSlow { $($tt)* };
174            let attempt_id = probe.attempt_id.clone();
175            let binary_id = probe.binary_id.to_string();
176            let test_name = probe.test_name.clone();
177            let elapsed_nanos = probe.elapsed_nanos;
178            (probe, attempt_id, binary_id, test_name, elapsed_nanos)
179        })
180    }};
181    (UsdtSetupScriptStart { $($tt:tt)* }) => {{
182        $crate::usdt::usdt_probes::setup__script__start!(|| {
183            let probe = $crate::usdt::UsdtSetupScriptStart { $($tt)* };
184            let id = probe.id.clone();
185            let script_id = probe.script_id.clone();
186            let pid = probe.pid;
187            (probe, id, script_id, pid)
188        })
189    }};
190    (UsdtSetupScriptSlow { $($tt:tt)* }) => {{
191        $crate::usdt::usdt_probes::setup__script__slow!(|| {
192            let probe = $crate::usdt::UsdtSetupScriptSlow { $($tt)* };
193            let id = probe.id.clone();
194            let script_id = probe.script_id.clone();
195            let elapsed_nanos = probe.elapsed_nanos;
196            (probe, id, script_id, elapsed_nanos)
197        })
198    }};
199    (UsdtSetupScriptDone { $($tt:tt)* }) => {{
200        $crate::usdt::usdt_probes::setup__script__done!(|| {
201            let probe = $crate::usdt::UsdtSetupScriptDone { $($tt)* };
202            let id = probe.id.clone();
203            let script_id = probe.script_id.clone();
204            let result = probe.result;
205            let duration_nanos = probe.duration_nanos;
206            (probe, id, script_id, result, duration_nanos)
207        })
208    }};
209    (UsdtRunStart { $($tt:tt)* }) => {{
210        $crate::usdt::usdt_probes::run__start!(|| {
211            let probe = $crate::usdt::UsdtRunStart { $($tt)* };
212            let run_id = probe.run_id;
213            (probe, run_id)
214        })
215    }};
216    (UsdtRunDone { $($tt:tt)* }) => {{
217        $crate::usdt::usdt_probes::run__done!(|| {
218            let probe = $crate::usdt::UsdtRunDone { $($tt)* };
219            let run_id = probe.run_id;
220            (probe, run_id)
221        })
222    }};
223    (UsdtStressSubRunStart { $($tt:tt)* }) => {{
224        $crate::usdt::usdt_probes::stress__sub__run__start!(|| {
225            let probe = $crate::usdt::UsdtStressSubRunStart { $($tt)* };
226            let stress_sub_run_id = probe.stress_sub_run_id.clone();
227            let stress_current = probe.stress_current;
228            (probe, stress_sub_run_id, stress_current)
229        })
230    }};
231    (UsdtStressSubRunDone { $($tt:tt)* }) => {{
232        $crate::usdt::usdt_probes::stress__sub__run__done!(|| {
233            let probe = $crate::usdt::UsdtStressSubRunDone { $($tt)* };
234            let stress_sub_run_id = probe.stress_sub_run_id.clone();
235            let stress_current = probe.stress_current;
236            (probe, stress_sub_run_id, stress_current)
237        })
238    }};
239}
240
241/// No-op version of fire_usdt for unsupported platforms.
242#[cfg(not(any(
243    all(
244        target_arch = "x86_64",
245        any(target_os = "linux", target_os = "freebsd", target_os = "illumos")
246    ),
247    all(
248        target_arch = "aarch64",
249        any(target_os = "macos", target_os = "freebsd", target_os = "illumos")
250    )
251)))]
252#[macro_export]
253macro_rules! fire_usdt {
254    ($($tt:tt)*) => {
255        let _ = $crate::usdt::$($tt)*;
256    };
257}
258
259/// Data associated with the `test-attempt-start` probe.
260///
261/// This data is JSON-encoded as `arg0`.
262#[derive(Clone, Debug, Serialize)]
263pub struct UsdtTestAttemptStart {
264    /// A unique identifier for this test attempt, comprised of the run ID, the
265    /// binary ID, the test name, the attempt number, and the stress index.
266    ///
267    /// Also available as `arg1`.
268    pub attempt_id: String,
269
270    /// The nextest run ID, unique for each run.
271    pub run_id: ReportUuid,
272
273    /// The binary ID.
274    ///
275    /// Also available as `arg2`.
276    pub binary_id: RustBinaryId,
277
278    /// The name of the test.
279    ///
280    /// Also available as `arg3`.
281    pub test_name: String,
282
283    /// The process ID of the test.
284    ///
285    /// Also available as `arg4`.
286    pub pid: u32,
287
288    /// The program to run.
289    pub program: String,
290
291    /// The arguments to pass to the program.
292    pub args: Vec<String>,
293
294    /// The attempt number, starting at 1 and <= `total_attempts`.
295    pub attempt: u32,
296
297    /// The total number of attempts.
298    pub total_attempts: u32,
299
300    /// The 0-indexed stress run index, if running stress tests.
301    pub stress_current: Option<u32>,
302
303    /// The total number of stress runs, if available.
304    pub stress_total: Option<u32>,
305
306    /// The global slot number (0-indexed).
307    pub global_slot: u64,
308
309    /// The group slot number (0-indexed), if the test is in a custom test group.
310    pub group_slot: Option<u64>,
311
312    /// The test group name, if the test is in a custom test group.
313    pub test_group: Option<String>,
314}
315
316/// Data associated with the `test-attempt-done` probe.
317///
318/// This data is JSON-encoded as `arg0`.
319#[derive(Clone, Debug, Serialize)]
320pub struct UsdtTestAttemptDone {
321    /// A unique identifier for this test attempt, comprised of the run ID, the
322    /// binary ID, the test name, the attempt number, and the stress index.
323    ///
324    /// Also available as `arg1`.
325    pub attempt_id: String,
326
327    /// The nextest run ID, unique for each run.
328    pub run_id: ReportUuid,
329
330    /// The binary ID.
331    ///
332    /// Also available as `arg2`.
333    pub binary_id: RustBinaryId,
334
335    /// The name of the test.
336    ///
337    /// Also available as `arg3`.
338    pub test_name: String,
339
340    /// The attempt number, starting at 1 and <= `total_attempts`.
341    pub attempt: u32,
342
343    /// The total number of attempts.
344    pub total_attempts: u32,
345
346    /// The test result as a string (e.g., "pass", "fail", "timeout", "exec-fail").
347    ///
348    /// Also available as `arg4`.
349    pub result: &'static str,
350
351    /// The exit code of the test process, if available.
352    pub exit_code: Option<i32>,
353
354    /// The duration of the test in nanoseconds.
355    ///
356    /// Also available as `arg5`.
357    pub duration_nanos: u64,
358
359    /// Whether file descriptors were leaked.
360    pub leaked: bool,
361
362    /// Time taken for the standard output and standard error file descriptors
363    /// to close, in nanoseconds. None if they didn't close (timed out).
364    pub time_to_close_fds_nanos: Option<u64>,
365
366    /// The 0-indexed stress run index, if running stress tests.
367    pub stress_current: Option<u32>,
368
369    /// The total number of stress runs, if available.
370    pub stress_total: Option<u32>,
371
372    /// The length of stdout in bytes, if captured.
373    pub stdout_len: Option<u64>,
374
375    /// The length of stderr in bytes, if captured.
376    pub stderr_len: Option<u64>,
377}
378
379/// Data associated with the `test-attempt-slow` probe.
380///
381/// This data is JSON-encoded as `arg0`.
382#[derive(Clone, Debug, Serialize)]
383pub struct UsdtTestAttemptSlow {
384    /// A unique identifier for this test attempt, comprised of the run ID, the
385    /// binary ID, the test name, the attempt number, and the stress index.
386    ///
387    /// Also available as `arg1`.
388    pub attempt_id: String,
389
390    /// The nextest run ID, unique for each run.
391    pub run_id: ReportUuid,
392
393    /// The binary ID. Also available as `arg2`.
394    pub binary_id: RustBinaryId,
395
396    /// The name of the test. Also available as `arg3`.
397    pub test_name: String,
398
399    /// The attempt number, starting at 1 and <= `total_attempts`.
400    pub attempt: u32,
401
402    /// The total number of attempts.
403    pub total_attempts: u32,
404
405    /// The time elapsed since the test started, in nanoseconds.
406    ///
407    /// Also available as `arg4`.
408    pub elapsed_nanos: u64,
409
410    /// Whether the test is about to be terminated due to timeout.
411    pub will_terminate: bool,
412
413    /// The 0-indexed stress run index, if running stress tests.
414    pub stress_current: Option<u32>,
415
416    /// The total number of stress runs, if available.
417    pub stress_total: Option<u32>,
418}
419
420/// Data associated with the `setup-script-start` probe.
421///
422/// This data is JSON-encoded as `arg0`.
423#[derive(Clone, Debug, Serialize)]
424pub struct UsdtSetupScriptStart {
425    /// A unique identifier for this script run, comprised of the run ID, the
426    /// script ID, and the stress index if relevant.
427    ///
428    /// Also available as `arg1`.
429    pub id: String,
430
431    /// The nextest run ID, unique for each run.
432    pub run_id: ReportUuid,
433
434    /// The script ID.
435    ///
436    /// Also available as `arg2`.
437    pub script_id: String,
438
439    /// The process ID of the script.
440    ///
441    /// Also available as `arg3`.
442    pub pid: u32,
443
444    /// The program to run.
445    pub program: String,
446
447    /// The arguments to pass to the program.
448    pub args: Vec<String>,
449
450    /// The 0-indexed stress run index, if running stress tests.
451    pub stress_current: Option<u32>,
452
453    /// The total number of stress runs, if available.
454    pub stress_total: Option<u32>,
455}
456
457/// Data associated with the `setup-script-slow` probe.
458///
459/// This data is JSON-encoded as `arg0`.
460#[derive(Clone, Debug, Serialize)]
461pub struct UsdtSetupScriptSlow {
462    /// A unique identifier for this script run, comprised of the run ID, the
463    /// script ID, and the stress index if relevant.
464    ///
465    /// Also available as `arg1`.
466    pub id: String,
467
468    /// The nextest run ID, unique for each run.
469    pub run_id: ReportUuid,
470
471    /// The script ID.
472    ///
473    /// Also available as `arg2`.
474    pub script_id: String,
475
476    /// The program to run.
477    pub program: String,
478
479    /// The arguments to pass to the program.
480    pub args: Vec<String>,
481
482    /// The time elapsed since the script started, in nanoseconds.
483    ///
484    /// Also available as `arg3`.
485    pub elapsed_nanos: u64,
486
487    /// Whether the script is about to be terminated due to timeout.
488    pub will_terminate: bool,
489
490    /// The 0-indexed stress run index, if running stress tests.
491    pub stress_current: Option<u32>,
492
493    /// The total number of stress runs, if available.
494    pub stress_total: Option<u32>,
495}
496
497/// Data associated with the `setup-script-done` probe.
498///
499/// This data is JSON-encoded as `arg0`.
500#[derive(Clone, Debug, Serialize)]
501pub struct UsdtSetupScriptDone {
502    /// A unique identifier for this script run, comprised of the run ID, the
503    /// script ID, and the stress index if relevant.
504    ///
505    /// Also available as `arg1`.
506    pub id: String,
507
508    /// The nextest run ID, unique for each run.
509    pub run_id: ReportUuid,
510
511    /// The script ID.
512    ///
513    /// Also available as `arg2`.
514    pub script_id: String,
515
516    /// The program to run.
517    pub program: String,
518
519    /// The arguments to pass to the program.
520    pub args: Vec<String>,
521
522    /// The script result as a string (e.g., "pass", "fail", "timeout",
523    /// "exec-fail").
524    ///
525    /// Also available as `arg3`.
526    pub result: &'static str,
527
528    /// The exit code of the script process, if available.
529    pub exit_code: Option<i32>,
530
531    /// The duration of the script execution in nanoseconds.
532    ///
533    /// Also available as `arg4`.
534    pub duration_nanos: u64,
535
536    /// The 0-indexed stress run index, if running stress tests.
537    pub stress_current: Option<u32>,
538
539    /// The total number of stress runs, if available.
540    pub stress_total: Option<u32>,
541
542    /// The length of stdout in bytes, if captured.
543    pub stdout_len: Option<u64>,
544
545    /// The length of stderr in bytes, if captured.
546    pub stderr_len: Option<u64>,
547}
548
549/// Data associated with the `run-start` probe.
550///
551/// This data is JSON-encoded as `arg0`.
552#[derive(Clone, Debug, Serialize)]
553pub struct UsdtRunStart {
554    /// The nextest run ID, unique for each run.
555    ///
556    /// Also available as `arg1`.
557    pub run_id: ReportUuid,
558
559    /// The profile name (e.g., "default", "ci").
560    pub profile_name: String,
561
562    /// Total number of tests in the test list.
563    pub total_tests: usize,
564
565    /// Number of tests after filtering.
566    pub filter_count: usize,
567
568    /// Number of test threads.
569    pub test_threads: usize,
570
571    /// If this is a count-based stress run with a finite number of runs, the
572    /// number of stress runs.
573    pub stress_count: Option<u32>,
574
575    /// True if this is a count-based stress run with an infinite number of
576    /// runs.
577    pub stress_infinite: bool,
578
579    /// If this is a duration-based stress run, how long we're going to run for.
580    pub stress_duration_nanos: Option<u64>,
581}
582
583/// Data associated with the `run-done` probe.
584///
585/// This data is JSON-encoded as `arg0`.
586#[derive(Clone, Debug, Serialize)]
587pub struct UsdtRunDone {
588    /// The nextest run ID, unique for each run.
589    ///
590    /// Also available as `arg1`.
591    pub run_id: ReportUuid,
592
593    /// The profile name (e.g., "default", "ci").
594    pub profile_name: String,
595
596    /// Total number of tests that were run.
597    ///
598    /// For stress runs, this consists of the last run's total test count.
599    pub total_tests: usize,
600
601    /// Number of tests that passed.
602    ///
603    /// For stress runs, this consists of the last run's passed test count.
604    pub passed: usize,
605
606    /// Number of tests that failed.
607    ///
608    /// For stress runs, this consists of the last run's failed test count.
609    pub failed: usize,
610
611    /// Number of tests that were skipped.
612    ///
613    /// For stress runs, this consists of the last run's skipped test count.
614    pub skipped: usize,
615
616    /// Total active duration of the run in nanoseconds, not including paused
617    /// time.
618    ///
619    /// For stress runs, this adds up the duration across all sub-runs.
620    pub duration_nanos: u64,
621
622    /// The number of nanoseconds the run was paused.
623    ///
624    /// For stress runs, this adds up the paused duration across all sub-runs.
625    pub paused_nanos: u64,
626
627    /// The number of stress runs completed, if this is a stress run.
628    pub stress_completed: Option<u32>,
629
630    /// The number of stress runs that succeeded, if this is a stress run.
631    pub stress_success: Option<u32>,
632
633    /// The number of stress runs that failed, if this is a stress run.
634    pub stress_failed: Option<u32>,
635}
636
637/// Data associated with the `stress-sub-run-start` probe.
638///
639/// This data is JSON-encoded as `arg0`.
640#[derive(Clone, Debug, Serialize)]
641pub struct UsdtStressSubRunStart {
642    /// A unique identifier for this stress sub-run, of the form
643    /// `{run_id}:@stress-{stress_current}`.
644    ///
645    /// Also available as `arg1`.
646    pub stress_sub_run_id: String,
647
648    /// The nextest run ID, unique for each run.
649    pub run_id: ReportUuid,
650
651    /// The profile name (e.g., "default", "ci").
652    pub profile_name: String,
653
654    /// The 0-indexed current stress run number.
655    ///
656    /// Also available as `arg2`.
657    pub stress_current: u32,
658
659    /// The total number of stress runs, if available (None for infinite or
660    /// duration-based runs).
661    pub stress_total: Option<u32>,
662
663    /// The total elapsed time since the overall stress run started, in
664    /// nanoseconds.
665    pub elapsed_nanos: u64,
666}
667
668/// Data associated with the `stress-sub-run-done` probe.
669///
670/// This data is JSON-encoded as `arg0`.
671#[derive(Clone, Debug, Serialize)]
672pub struct UsdtStressSubRunDone {
673    /// A unique identifier for this stress sub-run, of the form
674    /// `{run_id}:@stress-{stress_current}`.
675    ///
676    /// Also available as `arg1`.
677    pub stress_sub_run_id: String,
678
679    /// The nextest run ID, unique for each run.
680    pub run_id: ReportUuid,
681
682    /// The profile name (e.g., "default", "ci").
683    pub profile_name: String,
684
685    /// The 0-indexed current stress run number.
686    ///
687    /// Also available as `arg2`.
688    pub stress_current: u32,
689
690    /// The total number of stress runs, if available (None for infinite or
691    /// duration-based runs).
692    pub stress_total: Option<u32>,
693
694    /// The total elapsed time since the overall stress run started, in
695    /// nanoseconds.
696    pub elapsed_nanos: u64,
697
698    /// The duration of this sub-run in nanoseconds.
699    pub sub_run_duration_nanos: u64,
700
701    /// Total number of tests that were run in this sub-run.
702    pub total_tests: usize,
703
704    /// Number of tests that passed in this sub-run.
705    pub passed: usize,
706
707    /// Number of tests that failed in this sub-run.
708    pub failed: usize,
709
710    /// Number of tests that were skipped in this sub-run.
711    pub skipped: usize,
712}