Skip to main content

vox_types/
observer.rs

1use std::sync::Arc;
2use std::time::Duration;
3
4use crate::{ChannelDirection, ChannelId, ConnectionId, MethodId, RequestId};
5
6pub type VoxObserverHandle = Arc<dyn VoxObserver>;
7
8// r[impl rpc.observability.runtime]
9pub trait VoxObserver: Send + Sync + 'static {
10    fn rpc_event(&self, _event: RpcEvent) {}
11    fn channel_event(&self, _event: ChannelEvent) {}
12    fn transport_event(&self, _event: TransportEvent) {}
13    fn driver_event(&self, _event: DriverEvent) {}
14}
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub enum RpcSide {
18    Client,
19    Server,
20}
21
22#[derive(Clone, Copy, Debug, PartialEq, Eq)]
23pub enum RpcOutcome {
24    Ok,
25    Error,
26    Cancelled,
27    Dropped,
28    Closed,
29    SendFailed,
30    Indeterminate,
31}
32
33#[derive(Clone, Copy, Debug, PartialEq, Eq)]
34pub enum RpcEvent {
35    Started {
36        side: RpcSide,
37        service: Option<&'static str>,
38        method: Option<&'static str>,
39        method_id: MethodId,
40    },
41    Finished {
42        side: RpcSide,
43        service: Option<&'static str>,
44        method: Option<&'static str>,
45        method_id: MethodId,
46        outcome: RpcOutcome,
47        elapsed: Duration,
48    },
49}
50
51#[derive(Clone, Copy, Debug, PartialEq, Eq)]
52pub enum ChannelTrySendOutcome {
53    Sent,
54    FullCredit,
55    FullRuntimeQueue,
56    Unbound,
57    Closed,
58}
59
60#[derive(Clone, Copy, Debug, PartialEq, Eq)]
61pub enum ChannelSendOutcome {
62    Sent,
63    Closed,
64    TransportError,
65}
66
67#[derive(Clone, Copy, Debug, PartialEq, Eq)]
68pub enum ChannelCloseReason {
69    Local,
70    Remote,
71    Dropped,
72    ConnectionClosed,
73    ReceiverDropped,
74    Unknown,
75}
76
77#[derive(Clone, Copy, Debug, PartialEq, Eq)]
78pub enum ChannelResetReason {
79    Local,
80    Remote,
81    ReceiverDropped,
82    Protocol,
83    ConnectionClosed,
84    Unknown,
85}
86
87#[derive(Clone, Copy, Debug, PartialEq, Eq)]
88pub struct SourceLocation {
89    pub file: &'static str,
90    pub line: u32,
91    pub column: u32,
92}
93
94#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
95pub struct ChannelDebugContext {
96    pub label: Option<&'static str>,
97    pub type_name: Option<&'static str>,
98    pub source_location: Option<SourceLocation>,
99    pub service: Option<&'static str>,
100    pub method: Option<&'static str>,
101}
102
103impl ChannelDebugContext {
104    pub const fn is_empty(&self) -> bool {
105        self.label.is_none()
106            && self.type_name.is_none()
107            && self.source_location.is_none()
108            && self.service.is_none()
109            && self.method.is_none()
110    }
111
112    pub const fn into_option(self) -> Option<Self> {
113        if self.is_empty() { None } else { Some(self) }
114    }
115}
116
117#[derive(Clone, Copy, Debug, PartialEq, Eq)]
118pub struct ChannelEventContext {
119    pub connection_id: Option<ConnectionId>,
120    pub channel_id: ChannelId,
121    pub debug: Option<ChannelDebugContext>,
122}
123
124impl ChannelEventContext {
125    pub const fn new(channel_id: ChannelId) -> Self {
126        Self {
127            connection_id: None,
128            channel_id,
129            debug: None,
130        }
131    }
132}
133
134// r[impl rpc.observability.channel]
135// r[impl rpc.observability.channel.context]
136#[derive(Clone, Copy, Debug, PartialEq, Eq)]
137pub enum ChannelEvent {
138    Opened {
139        channel: ChannelEventContext,
140        direction: ChannelDirection,
141        initial_credit: u32,
142    },
143    SendStarted {
144        channel: ChannelEventContext,
145    },
146    SendWaitingForCredit {
147        channel: ChannelEventContext,
148    },
149    SendFinished {
150        channel: ChannelEventContext,
151        outcome: ChannelSendOutcome,
152        elapsed: Duration,
153    },
154    TrySend {
155        channel: ChannelEventContext,
156        outcome: ChannelTrySendOutcome,
157    },
158    CreditGranted {
159        channel: ChannelEventContext,
160        amount: u32,
161    },
162    ItemReceived {
163        channel: ChannelEventContext,
164    },
165    ItemConsumed {
166        channel: ChannelEventContext,
167    },
168    Closed {
169        channel: ChannelEventContext,
170        reason: ChannelCloseReason,
171    },
172    Reset {
173        channel: ChannelEventContext,
174        reason: ChannelResetReason,
175    },
176}
177
178#[derive(Clone, Copy, Debug, PartialEq, Eq)]
179pub enum ConnectionCloseReason {
180    Local,
181    Remote,
182    Protocol,
183    Transport,
184    SessionShutdown,
185    CallerDropped,
186    Unknown,
187}
188
189#[derive(Clone, Copy, Debug, PartialEq, Eq)]
190pub enum DecodeErrorKind {
191    Schema,
192    Payload,
193    Protocol,
194    Unknown,
195}
196
197#[derive(Clone, Copy, Debug, PartialEq, Eq)]
198pub enum EncodeErrorKind {
199    Schema,
200    Payload,
201    Transport,
202    Unknown,
203}
204
205#[derive(Clone, Copy, Debug, PartialEq, Eq)]
206pub enum ProtocolErrorKind {
207    InvalidConnection,
208    InvalidRequest,
209    InvalidChannel,
210    Schema,
211    FlowControl,
212    Unknown,
213}
214
215// r[impl rpc.observability.driver]
216#[derive(Clone, Copy, Debug, PartialEq, Eq)]
217pub enum DriverEvent {
218    ConnectionOpened {
219        connection_id: ConnectionId,
220    },
221    ConnectionClosed {
222        connection_id: ConnectionId,
223        reason: ConnectionCloseReason,
224    },
225    RequestStarted {
226        connection_id: ConnectionId,
227        request_id: RequestId,
228        method_id: MethodId,
229    },
230    RequestFinished {
231        connection_id: ConnectionId,
232        request_id: RequestId,
233        outcome: RpcOutcome,
234        elapsed: Duration,
235    },
236    OutboundQueueFull {
237        connection_id: ConnectionId,
238    },
239    OutboundQueueClosed {
240        connection_id: ConnectionId,
241    },
242    FrameRead {
243        connection_id: ConnectionId,
244        bytes: usize,
245    },
246    FrameWritten {
247        connection_id: ConnectionId,
248        bytes: usize,
249    },
250    DecodeError {
251        connection_id: ConnectionId,
252        kind: DecodeErrorKind,
253    },
254    EncodeError {
255        connection_id: ConnectionId,
256        kind: EncodeErrorKind,
257    },
258    ProtocolError {
259        connection_id: ConnectionId,
260        kind: ProtocolErrorKind,
261    },
262}
263
264#[derive(Clone, Copy, Debug, PartialEq, Eq)]
265pub enum TransportEvent {
266    FrameRead {
267        connection_id: Option<ConnectionId>,
268        bytes: usize,
269    },
270    FrameWritten {
271        connection_id: Option<ConnectionId>,
272        bytes: usize,
273    },
274    Closed {
275        connection_id: Option<ConnectionId>,
276        reason: ConnectionCloseReason,
277    },
278}