Coverage Report

Created: 2026-07-21 15:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/build/source/nativelink-util/src/origin_event.rs
Line
Count
Source
1
// Copyright 2024 The NativeLink Authors. All rights reserved.
2
//
3
// Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//    See LICENSE file for details
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
use std::sync::OnceLock;
16
17
use base64::Engine;
18
use base64::prelude::BASE64_STANDARD_NO_PAD;
19
use nativelink_error::Error;
20
use nativelink_proto::build::bazel::remote::execution::v2::RequestMetadata;
21
use nativelink_proto::com::github::trace_machina::nativelink::events::{
22
    Event, event, request_event, response_event, stream_event,
23
};
24
use prost::Message;
25
use rand::RngCore;
26
use serde::{Deserialize, Deserializer, Serialize, Serializer};
27
28
static NODE_ID: OnceLock<[u8; 6]> = OnceLock::new();
29
30
/// Custom OpenTelemetry baggage key used to carry Bazel `RequestMetadata`.
31
pub const BAZEL_METADATA_KEY: &str = "bazel.metadata";
32
33
#[must_use]
34
2
pub fn request_metadata_to_baggage(metadata: &RequestMetadata) -> String {
35
2
    BASE64_STANDARD_NO_PAD.encode(metadata.encode_to_vec())
36
2
}
37
38
2
pub fn request_metadata_from_baggage(value: &str) -> Result<RequestMetadata, Error> {
39
2
    let decoded = BASE64_STANDARD_NO_PAD
40
2
        .decode(value.as_bytes())
41
2
        .map_err(Error::from)
?0
;
42
2
    RequestMetadata::decode(&*decoded).map_err(Error::from)
43
2
}
44
45
/// Returns a unique ID for the given event.
46
/// This ID is used to identify the event type.
47
/// The max value that could be output is 0x0FFF,
48
/// meaning you may use the first nibble for other
49
/// purposes.
50
#[inline]
51
35
pub const fn get_id_for_event(event: &Event) -> [u8; 2] {
52
34
    match &event.event {
53
1
        None => [0x00, 0x00],
54
15
        Some(event::Event::Request(req)) => match 
req.event14
{
55
1
            None => [0x01, 0x00],
56
1
            Some(request_event::Event::GetCapabilitiesRequest(_)) => [0x01, 0x01],
57
1
            Some(request_event::Event::GetActionResultRequest(_)) => [0x01, 0x02],
58
1
            Some(request_event::Event::UpdateActionResultRequest(_)) => [0x01, 0x03],
59
1
            Some(request_event::Event::FindMissingBlobsRequest(_)) => [0x01, 0x04],
60
1
            Some(request_event::Event::BatchReadBlobsRequest(_)) => [0x01, 0x05],
61
1
            Some(request_event::Event::BatchUpdateBlobsRequest(_)) => [0x01, 0x06],
62
1
            Some(request_event::Event::GetTreeRequest(_)) => [0x01, 0x07],
63
1
            Some(request_event::Event::ReadRequest(_)) => [0x01, 0x08],
64
1
            Some(request_event::Event::WriteRequest(())) => [0x01, 0x09],
65
1
            Some(request_event::Event::QueryWriteStatusRequest(_)) => [0x01, 0x0A],
66
1
            Some(request_event::Event::ExecuteRequest(_)) => [0x01, 0x0B],
67
1
            Some(request_event::Event::WaitExecutionRequest(_)) => [0x01, 0x0C],
68
2
            Some(request_event::Event::SchedulerStartExecute(_)) => [0x01, 0x0D],
69
0
            Some(request_event::Event::FetchBlobRequest(_)) => [0x01, 0x0E],
70
0
            Some(request_event::Event::PushBlobRequest(_)) => [0x01, 0x0F],
71
        },
72
12
        Some(event::Event::Response(res)) => match 
res.event11
{
73
1
            None => [0x02, 0x00],
74
1
            Some(response_event::Event::Error(_)) => [0x02, 0x01],
75
1
            Some(response_event::Event::ServerCapabilities(_)) => [0x02, 0x02],
76
1
            Some(response_event::Event::ActionResult(_)) => [0x02, 0x03],
77
1
            Some(response_event::Event::FindMissingBlobsResponse(_)) => [0x02, 0x04],
78
1
            Some(response_event::Event::BatchReadBlobsResponse(_)) => [0x02, 0x05],
79
1
            Some(response_event::Event::BatchUpdateBlobsResponse(_)) => [0x02, 0x06],
80
1
            Some(response_event::Event::WriteResponse(_)) => [0x02, 0x07],
81
1
            Some(response_event::Event::QueryWriteStatusResponse(_)) => [0x02, 0x08],
82
1
            Some(response_event::Event::Empty(())) => [0x02, 0x09],
83
0
            Some(response_event::Event::FetchBlobResponse(_)) => [0x02, 0x0A],
84
0
            Some(response_event::Event::PushBlobResponse(_)) => [0x02, 0x0B],
85
2
            Some(response_event::Event::ActionResourceUsage(_)) => [0x02, 0x0C],
86
        },
87
7
        Some(event::Event::Stream(stream)) => match 
stream.event6
{
88
1
            None => [0x03, 0x00],
89
1
            Some(stream_event::Event::Error(_)) => [0x03, 0x01],
90
1
            Some(stream_event::Event::GetTreeResponse(_)) => [0x03, 0x02],
91
1
            Some(stream_event::Event::DataLength(_)) => [0x03, 0x03],
92
1
            Some(stream_event::Event::WriteRequest(_)) => [0x03, 0x04],
93
1
            Some(stream_event::Event::Operation(_)) => [0x03, 0x05],
94
1
            Some(stream_event::Event::Closed(())) => [0x03, 0x06], // Special case when stream has terminated.
95
        },
96
    }
97
35
}
98
99
/// Returns a unique node ID for this process.
100
2
pub fn get_node_id(event: Option<&Event>) -> [u8; 6] {
101
2
    let mut node_id = *NODE_ID.get_or_init(|| 
{1
102
1
        let mut out = [0; 6];
103
1
        rand::rng().fill_bytes(&mut out);
104
1
        out
105
1
    });
106
2
    let Some(event) = event else {
107
0
        return node_id;
108
    };
109
2
    let event_id = get_id_for_event(event);
110
2
    node_id[0] = (node_id[0] & 0xF0) | event_id[0];
111
2
    node_id[1] = event_id[1];
112
2
    node_id
113
2
}
114
115
0
fn serialize_request_metadata<S>(
116
0
    value: &Option<RequestMetadata>,
117
0
    serializer: S,
118
0
) -> Result<S::Ok, S::Error>
119
0
where
120
0
    S: Serializer,
121
{
122
0
    match value {
123
0
        Some(msg) => serializer.serialize_some(&BASE64_STANDARD_NO_PAD.encode(msg.encode_to_vec())),
124
0
        None => serializer.serialize_none(),
125
    }
126
0
}
127
128
0
fn deserialize_request_metadata<'de, D>(
129
0
    deserializer: D,
130
0
) -> Result<Option<RequestMetadata>, D::Error>
131
0
where
132
0
    D: Deserializer<'de>,
133
{
134
0
    let opt = Option::<String>::deserialize(deserializer)?;
135
0
    match opt {
136
0
        Some(s) => {
137
0
            let decoded = BASE64_STANDARD_NO_PAD
138
0
                .decode(s.as_bytes())
139
0
                .map_err(serde::de::Error::custom)?;
140
0
            RequestMetadata::decode(&*decoded)
141
0
                .map_err(serde::de::Error::custom)
142
0
                .map(Some)
143
        }
144
0
        None => Ok(None),
145
    }
146
0
}
147
148
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
149
pub struct OriginMetadata {
150
    pub identity: String,
151
    #[serde(
152
        serialize_with = "serialize_request_metadata",
153
        deserialize_with = "deserialize_request_metadata"
154
    )]
155
    pub bazel_metadata: Option<RequestMetadata>,
156
}