munin_msbuild/jsonlog/schema.rs
1// Copyright (c) Michael Grier
2
3//! On-disk schema for `.jsonlog` files.
4//!
5//! See `D-JL-1` in the workspace `DESIGN-NOTES.md`. The schema is versioned
6//! by the top-level [`JsonlogFile::munin_jsonlog_version`] field; v1 is the
7//! only supported version today.
8
9use serde::{Deserialize, Serialize};
10
11use crate::header::BinlogHeader;
12
13/// Current schema version. Readers reject any other value.
14pub const MUNIN_JSONLOG_VERSION: u32 = 1;
15
16/// Root object of a `.jsonlog` file.
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct JsonlogFile {
19 /// Schema version. Must equal [`MUNIN_JSONLOG_VERSION`].
20 pub munin_jsonlog_version: u32,
21
22 /// Binlog header (format version and minimum reader version).
23 pub header: JsonlogHeader,
24
25 /// Deduplicated string table. Index into this array is what every
26 /// "dedup string" reference in event payloads points at.
27 pub strings: Vec<String>,
28
29 /// Name-value list table. Each entry is a list of `[key, value]` index
30 /// pairs into [`strings`](Self::strings).
31 pub name_value_lists: Vec<Vec<[u32; 2]>>,
32
33 /// Embedded archive blobs (e.g. project imports), in the order they were
34 /// encountered in the binlog stream.
35 pub archives: Vec<ArchiveB64>,
36
37 /// Event records in stream order.
38 pub events: Vec<JsonlogEvent>,
39}
40
41/// JSON-friendly mirror of [`BinlogHeader`].
42#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
43pub struct JsonlogHeader {
44 pub file_format_version: i32,
45 pub min_reader_version: i32,
46}
47
48impl From<BinlogHeader> for JsonlogHeader {
49 fn from(h: BinlogHeader) -> Self {
50 Self {
51 file_format_version: h.file_format_version,
52 min_reader_version: h.min_reader_version,
53 }
54 }
55}
56
57impl From<JsonlogHeader> for BinlogHeader {
58 fn from(h: JsonlogHeader) -> Self {
59 Self {
60 file_format_version: h.file_format_version,
61 min_reader_version: h.min_reader_version,
62 }
63 }
64}
65
66/// An embedded archive blob, base64-encoded.
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct ArchiveB64 {
69 /// Base64 (standard alphabet, with padding) of the archive bytes.
70 pub data_b64: String,
71}
72
73/// One event record.
74///
75/// `kind` is the record-kind name (matching [`crate::BinaryLogRecordKind`]
76/// debug formatting, e.g. `"BuildStarted"`). The body carries either a
77/// `decoded` JSON object (when the current decoder understands the kind) or
78/// an opaque `payload_b64` fallback for forward-compatibility.
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct JsonlogEvent {
81 /// Record kind name (e.g. `"BuildStarted"`, `"Message"`).
82 pub kind: String,
83
84 /// Byte offset of the record's kind byte in the original decompressed
85 /// stream. Diagnostic parity with [`crate::EventMeta::byte_offset`].
86 pub byte_offset: u64,
87
88 /// Event body.
89 #[serde(flatten)]
90 pub body: JsonlogEventBody,
91}
92
93/// Decoded-vs-opaque payload for a [`JsonlogEvent`].
94///
95/// Serialized as one of two shapes:
96///
97/// ```json
98/// { "decoded": { ... event-specific fields ... } }
99/// ```
100///
101/// or
102///
103/// ```json
104/// { "payload_b64": "...base64..." }
105/// ```
106#[derive(Debug, Clone, Serialize, Deserialize)]
107#[serde(rename_all = "snake_case")]
108pub enum JsonlogEventBody {
109 /// Decoded event payload, schema specific to the event kind.
110 /// Populated by JL-1.4 / JL-1.5 with typed variants; for now the
111 /// payload is carried as a raw JSON value.
112 Decoded(serde_json::Value),
113
114 /// Opaque payload — base64 (standard alphabet, with padding) of the
115 /// stored record payload bytes. Used when the current decoder does
116 /// not understand the record kind.
117 PayloadB64(String),
118}