Skip to main content

Crate backbeat_macros

Crate backbeat_macros 

Source
Expand description

#[derive(Event)] for backbeat.

Annotate a #[repr(C)] struct to make it a traceable event. The derive reflects the struct’s fields into a const [EventSchema] (offsets via core::mem::offset_of!, widths via core::mem::size_of), computes a content-addressed [EventId] by hashing that whole schema, and implements [backbeat::Event] — whose zerocopy::IntoBytes bound makes recording a single memcpy and rejects padded layouts the reader can’t describe.

use backbeat::{Event, EventEnum};
use backbeat::zerocopy::{Immutable, IntoBytes};

/// Which way a frame is going.
#[derive(EventEnum, IntoBytes, Immutable, Clone, Copy)]
#[repr(u8)]
enum Direction { Incoming = 0, Outgoing = 1 }

/// A frame was queued for sending.
#[derive(Event, IntoBytes, Immutable)]
#[event(namespace = "my_crate::frame")]
#[repr(C)]
struct QueueData {
    #[event(key)]            packet_number: u64,
    /// Offset into the stream.
    #[event(unit = "bytes")] offset: u64,
    direction: Direction,    // a strongly-typed enum field
    is_fin: bool,
}

The generated code exposes QueueData::SCHEMA (an EventSchema), QueueData::ID (its EventId), and QueueData::QUALIFIED_NAME, and implements Event. Because the id hashes the whole schema, two builds whose layout or field metadata differ get distinct ids and never alias in a dump’s registry.

Container attributes (on the struct):

  • #[event(namespace = "…")] — required; the event’s namespace prefix.
  • #[event(span = enter)] / #[event(span = exit)] — mark this event as one half of a span, so the trace converter can pair begin/end records into a duration slice. A spanned event must carry exactly one #[event(span_id)] field.

Field attributes (mutually-exclusive roles — at most one per field):

  • #[event(key)] — promote this field to a top-level join/index column in the output table.
  • #[event(span_id)] — this u64 is the span’s own id (required on a span = enter|exit event; the enter and exit halves carry the same value so the converter pairs them).
  • #[event(parent_span_id)] — this u64 is the enclosing span’s id, linking this event under its parent. Allowed on any event, including plain (non-span) ones.

Other field attributes (combine with a role):

  • #[event(unit = "…")] — attach a unit hint ("bytes", "ns", …) carried into the output.
  • #[event(sentinel = <const>)] — declare an in-band “absent” marker for an integer field (e.g. sentinel = u64::MAX for an unassigned packet number, or sentinel = 0 for a dump_id only some events carry). The converter maps a field equal to its sentinel to SQL NULL, so the wire format needs no nulls yet WHERE x IS NULL works.
  • #[event(interned)] / #[event(interned(dynamic))] — the (u32) field is an intern id resolved against the dump’s intern table; dynamic marks runtime-built values.

Enum-typed fields use a separate #[derive(EventEnum)] on the (#[repr(uN)], fieldless) enum; the field then carries the strong type and the schema records its value→label map automatically.

Field and struct doc comments (///) are lifted verbatim into the schema’s description fields, so the embedded registry documents itself.

Derive Macros§

Event
Derives Event for a struct: its compile-time EventId, a reflected EventSchema, and an impl Event.
EventEnum
Derives EventEnum for a fieldless #[repr(u8|u16|u32|u64)] enum, so it can be a strongly-typed event field. Emits the variant→label map and the repr width.