libbpf_cargo/
util.rs

1//! Utility functionality for working with generated skeletons.
2
3use std::error::Error;
4use std::fmt::Arguments;
5use std::fmt::Debug;
6use std::fmt::Result;
7
8use tracing::field::Field;
9use tracing::field::Visit;
10use tracing::Event;
11use tracing::Subscriber;
12use tracing_subscriber::fmt::format::FormatFields;
13use tracing_subscriber::fmt::format::Writer;
14use tracing_subscriber::fmt::FmtContext;
15use tracing_subscriber::fmt::FormatEvent;
16use tracing_subscriber::registry::LookupSpan;
17
18
19/// A visitor for "extracting" captured field values from a tracing
20/// span/event.
21#[derive(Debug)]
22struct Visitor<'w> {
23    writer: Writer<'w>,
24}
25
26impl<'w> Visitor<'w> {
27    fn new(writer: Writer<'w>) -> Self {
28        Self { writer }
29    }
30
31    fn record_value(&mut self, field: &Field, value: Arguments<'_>) {
32        let name = field.name();
33        // Special case the field "message", only printing the value and
34        // not the name.
35        if name == "message" {
36            let _result = writeln!(self.writer, "cargo:warning={value}");
37        } else {
38            let _result = writeln!(self.writer, "cargo:warning={name}={value}");
39        }
40    }
41}
42
43impl Visit for Visitor<'_> {
44    fn record_debug(&mut self, field: &Field, value: &dyn Debug) {
45        self.record_value(field, format_args!("{value:?}"))
46    }
47
48    fn record_f64(&mut self, field: &Field, value: f64) {
49        self.record_value(field, format_args!("{value}"))
50    }
51
52    fn record_i64(&mut self, field: &Field, value: i64) {
53        self.record_value(field, format_args!("{value}"))
54    }
55
56    fn record_u64(&mut self, field: &Field, value: u64) {
57        self.record_value(field, format_args!("{value}"))
58    }
59
60    fn record_i128(&mut self, field: &Field, value: i128) {
61        self.record_value(field, format_args!("{value}"))
62    }
63
64    fn record_u128(&mut self, field: &Field, value: u128) {
65        self.record_value(field, format_args!("{value}"))
66    }
67
68    fn record_bool(&mut self, field: &Field, value: bool) {
69        self.record_value(field, format_args!("{value}"))
70    }
71
72    fn record_str(&mut self, field: &Field, value: &str) {
73        self.record_value(field, format_args!("{value}"))
74    }
75
76    fn record_error(&mut self, field: &Field, value: &(dyn Error + 'static)) {
77        self.record_value(field, format_args!("{value}"))
78    }
79}
80
81
82/// A `tracing` formatter intended for surfacing compiler
83/// warnings/messages from within a build script.
84///
85/// ```no_run
86/// # use libbpf_cargo::SkeletonBuilder;
87/// # use libbpf_cargo::util::CargoWarningFormatter;
88/// let () = tracing_subscriber::fmt()
89///     .event_format(CargoWarningFormatter)
90///     .init();
91///
92/// // Generate and build the skeleton, which may emit compiler
93/// // warnings.
94/// SkeletonBuilder::new()
95///     // [...]
96///     .build()
97///     .unwrap();
98/// ```
99#[derive(Debug)]
100pub struct CargoWarningFormatter;
101
102impl<S, N> FormatEvent<S, N> for CargoWarningFormatter
103where
104    S: Subscriber + for<'a> LookupSpan<'a>,
105    N: for<'a> FormatFields<'a> + 'static,
106{
107    fn format_event(
108        &self,
109        _ctx: &FmtContext<'_, S, N>,
110        writer: Writer<'_>,
111        event: &Event<'_>,
112    ) -> Result {
113        let mut visitor = Visitor::new(writer);
114        let () = event.record(&mut visitor);
115        Ok(())
116    }
117}