Skip to main content

hyperlight_common/flatbuffer_wrappers/
guest_log_data.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025 The Hyperlight Authors.
3
4use alloc::string::{String, ToString};
5use alloc::vec::Vec;
6
7use anyhow::{Error, Result, anyhow};
8use flatbuffers::size_prefixed_root;
9#[cfg(feature = "tracing")]
10use tracing::{Span, instrument};
11
12use super::guest_log_level::LogLevel;
13use crate::flatbuffers::hyperlight::generated::{
14    GuestLogData as FbGuestLogData, GuestLogDataArgs as FbGuestLogDataArgs, LogLevel as FbLogLevel,
15};
16
17/// The guest log data for a VM sandbox
18#[derive(Eq, PartialEq, Debug, Clone)]
19#[allow(missing_docs)]
20pub struct GuestLogData {
21    pub message: String,
22    pub source: String,
23    pub level: LogLevel,
24    pub caller: String,
25    pub source_file: String,
26    pub line: u32,
27}
28
29impl GuestLogData {
30    #[cfg_attr(feature = "tracing", instrument(skip_all, parent = Span::current(), level= "Trace"))]
31    pub fn new(
32        message: String,
33        source: String,
34        level: LogLevel,
35        caller: String,
36        source_file: String,
37        line: u32,
38    ) -> Self {
39        Self {
40            message,
41            source,
42            level,
43            caller,
44            source_file,
45            line,
46        }
47    }
48}
49
50impl TryFrom<&[u8]> for GuestLogData {
51    type Error = Error;
52    #[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
53    fn try_from(raw_bytes: &[u8]) -> Result<Self> {
54        let gld_gen = size_prefixed_root::<FbGuestLogData>(raw_bytes)
55            .map_err(|e| anyhow!("Error while reading GuestLogData: {:?}", e))?;
56        let message = convert_generated_option("message", gld_gen.message())?;
57        let source = convert_generated_option("source", gld_gen.source())?;
58        let level = LogLevel::try_from(&gld_gen.level())?;
59        let caller = convert_generated_option("caller", gld_gen.caller())?;
60        let source_file = convert_generated_option("source file", gld_gen.source_file())?;
61        let line = gld_gen.line();
62
63        Ok(GuestLogData {
64            message,
65            source,
66            level,
67            caller,
68            source_file,
69            line,
70        })
71    }
72}
73
74impl TryFrom<&GuestLogData> for Vec<u8> {
75    type Error = Error;
76    #[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
77    fn try_from(value: &GuestLogData) -> Result<Vec<u8>> {
78        let mut builder = flatbuffers::FlatBufferBuilder::new();
79        let message = builder.create_string(&value.message);
80        let source = builder.create_string(&value.source);
81        let caller = builder.create_string(&value.caller);
82        let source_file = builder.create_string(&value.source_file);
83        let level = FbLogLevel::from(&value.level);
84
85        let guest_log_data_fb = FbGuestLogData::create(
86            &mut builder,
87            &FbGuestLogDataArgs {
88                message: Some(message),
89                source: Some(source),
90                level,
91                caller: Some(caller),
92                source_file: Some(source_file),
93                line: value.line,
94            },
95        );
96        builder.finish_size_prefixed(guest_log_data_fb, None);
97        let res = builder.finished_data().to_vec();
98
99        Ok(res)
100    }
101}
102
103impl TryFrom<GuestLogData> for Vec<u8> {
104    type Error = Error;
105    #[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
106    fn try_from(value: GuestLogData) -> Result<Vec<u8>> {
107        (&value).try_into()
108    }
109}
110
111#[cfg_attr(feature = "tracing", instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace"))]
112fn convert_generated_option(field_name: &str, opt: Option<&str>) -> Result<String> {
113    opt.map(|s| s.to_string())
114        .ok_or_else(|| anyhow!("Missing field: {}", field_name))
115}