/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 | | } |