relay_event_schema/protocol/contexts/
runtime.rs

1use relay_protocol::{Annotated, Empty, FromValue, IntoValue, Object, Value};
2
3use crate::processor::ProcessValue;
4use crate::protocol::LenientString;
5
6/// Runtime information.
7///
8/// Runtime context describes a runtime in more detail. Typically, this context is present in
9/// `contexts` multiple times if multiple runtimes are involved (for instance, if you have a
10/// JavaScript application running on top of JVM).
11#[derive(Clone, Debug, Default, PartialEq, Empty, FromValue, IntoValue, ProcessValue)]
12pub struct RuntimeContext {
13    /// Computed field from `name` and `version`. Needed by the metrics extraction.
14    pub runtime: Annotated<String>,
15
16    /// Runtime name.
17    pub name: Annotated<String>,
18
19    /// Runtime version string.
20    pub version: Annotated<String>,
21
22    /// Application build string, if it is separate from the version.
23    #[metastructure(pii = "maybe")]
24    pub build: Annotated<LenientString>,
25
26    /// Unprocessed runtime info.
27    ///
28    /// An unprocessed description string obtained by the runtime. For some well-known runtimes,
29    /// Sentry will attempt to parse `name` and `version` from this string, if they are not
30    /// explicitly given.
31    #[metastructure(pii = "maybe")]
32    pub raw_description: Annotated<String>,
33
34    /// Additional arbitrary fields for forwards compatibility.
35    #[metastructure(additional_properties, retain = true, pii = "maybe")]
36    pub other: Object<Value>,
37}
38
39impl super::DefaultContext for RuntimeContext {
40    fn default_key() -> &'static str {
41        "runtime"
42    }
43
44    fn from_context(context: super::Context) -> Option<Self> {
45        match context {
46            super::Context::Runtime(c) => Some(*c),
47            _ => None,
48        }
49    }
50
51    fn cast(context: &super::Context) -> Option<&Self> {
52        match context {
53            super::Context::Runtime(c) => Some(c),
54            _ => None,
55        }
56    }
57
58    fn cast_mut(context: &mut super::Context) -> Option<&mut Self> {
59        match context {
60            super::Context::Runtime(c) => Some(c),
61            _ => None,
62        }
63    }
64
65    fn into_context(self) -> super::Context {
66        super::Context::Runtime(Box::new(self))
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73    use crate::protocol::Context;
74
75    #[test]
76    fn test_runtime_context_roundtrip() {
77        let json = r#"{
78  "runtime": "rustc 1.27.0",
79  "name": "rustc",
80  "version": "1.27.0",
81  "build": "stable",
82  "raw_description": "rustc 1.27.0 stable",
83  "other": "value",
84  "type": "runtime"
85}"#;
86        let context = Annotated::new(Context::Runtime(Box::new(RuntimeContext {
87            runtime: Annotated::new("rustc 1.27.0".to_string()),
88            name: Annotated::new("rustc".to_string()),
89            version: Annotated::new("1.27.0".to_string()),
90            build: Annotated::new(LenientString("stable".to_string())),
91            raw_description: Annotated::new("rustc 1.27.0 stable".to_string()),
92            other: {
93                let mut map = Object::new();
94                map.insert(
95                    "other".to_string(),
96                    Annotated::new(Value::String("value".to_string())),
97                );
98                map
99            },
100        })));
101
102        assert_eq!(context, Annotated::from_json(json).unwrap());
103        assert_eq!(json, context.to_json_pretty().unwrap());
104    }
105}