momento_functions_host/
logging.rs

1//! Host interfaces for working with host logging, allowing you to send
2//! logs to different destinations
3use momento_functions_wit::host::momento::host::logging;
4use thiserror::Error;
5
6/// Where do you want your logs to go?
7pub enum LogDestination {
8    /// Momento topic within the same cache as your function
9    Topic {
10        /// Name of the topic
11        topic: String,
12    },
13    /// AWS CloudWatch Log Group for your function's logs
14    CloudWatch {
15        /// ARN of the IAM role for Momento to assume
16        iam_role_arn: String,
17        /// ARN of the CloudWatch Log Group for Momento to publish your
18        /// function logs to
19        log_group_name: String,
20    },
21}
22
23impl LogDestination {
24    /// Creates a Topic destination
25    pub fn topic(name: impl Into<String>) -> Self {
26        Self::Topic { topic: name.into() }
27    }
28    /// Creates a CloudWatch destination.
29    /// Reach out to us at `support@momentohq.com` for details on how to properly
30    /// set up your log configuration.
31    pub fn cloudwatch(iam_role_arn: impl Into<String>, log_group_name: impl Into<String>) -> Self {
32        Self::CloudWatch {
33            iam_role_arn: iam_role_arn.into(),
34            log_group_name: log_group_name.into(),
35        }
36    }
37}
38
39/// A single configuration for a destination
40pub struct LogConfiguration {
41    /// At what level would you like your function's logs to be filtered into this destination?
42    log_level: log::LevelFilter,
43    /// At what level would you like Momento's system logs to be filtered into this destination?
44    system_log_level: log::LevelFilter,
45    /// The specific destination
46    destination: LogDestination,
47}
48
49impl LogConfiguration {
50    /// Constructs a single logging input with a desired destination. System logs will be at default level (INFO).
51    pub fn new(destination: LogDestination) -> Self {
52        Self {
53            log_level: log::LevelFilter::Info,
54            system_log_level: log::LevelFilter::Info,
55            destination,
56        }
57    }
58
59    /// Constructs a single logging input with a desired destination as well as a specified logs filter.
60    pub fn with_log_level(mut self, log_level: log::LevelFilter) -> Self {
61        self.log_level = log_level;
62        self
63    }
64
65    /// Constructs a single logging input with a desired destination as well as a specified system logs filter.
66    pub fn with_system_log_level(mut self, system_log_level: log::LevelFilter) -> Self {
67        self.system_log_level = system_log_level;
68        self
69    }
70}
71
72impl From<LogDestination> for LogConfiguration {
73    fn from(value: LogDestination) -> Self {
74        match value {
75            LogDestination::Topic { topic } => Self::new(LogDestination::topic(topic)),
76            LogDestination::CloudWatch {
77                iam_role_arn,
78                log_group_name,
79            } => Self::new(LogDestination::cloudwatch(iam_role_arn, log_group_name)),
80        }
81    }
82}
83
84/// Create a single `LogConfiguration` given a `LogDestination`.
85pub fn log_configuration(destination: LogDestination) -> LogConfiguration {
86    LogConfiguration::new(destination)
87}
88
89impl From<LogDestination> for logging::Destination {
90    fn from(value: LogDestination) -> Self {
91        match value {
92            LogDestination::Topic { topic } => {
93                momento_functions_wit::host::momento::host::logging::Destination::Topic(
94                    logging::TopicDestination { topic_name: topic },
95                )
96            }
97            LogDestination::CloudWatch {
98                iam_role_arn,
99                log_group_name,
100            } => momento_functions_wit::host::momento::host::logging::Destination::Cloudwatch(
101                logging::CloudwatchDestination {
102                    iam_role_arn,
103                    log_group_name,
104                },
105            ),
106        }
107    }
108}
109
110impl From<LogConfiguration> for logging::ConfigureLoggingInput {
111    fn from(value: LogConfiguration) -> Self {
112        Self {
113            log_level: match value.log_level {
114                log::LevelFilter::Off => logging::LogLevel::Off,
115                log::LevelFilter::Error => logging::LogLevel::Error,
116                log::LevelFilter::Warn => logging::LogLevel::Warn,
117                log::LevelFilter::Info => logging::LogLevel::Info,
118                log::LevelFilter::Debug => logging::LogLevel::Debug,
119                // Momento does not publish Trace logs
120                log::LevelFilter::Trace => logging::LogLevel::Debug,
121            },
122            system_logs_level: match value.system_log_level {
123                log::LevelFilter::Off => logging::LogLevel::Off,
124                log::LevelFilter::Error => logging::LogLevel::Error,
125                log::LevelFilter::Warn => logging::LogLevel::Warn,
126                log::LevelFilter::Info => logging::LogLevel::Info,
127                log::LevelFilter::Debug => logging::LogLevel::Debug,
128                // Momento does not publish Trace logs
129                log::LevelFilter::Trace => logging::LogLevel::Debug,
130            },
131            destination: value.destination.into(),
132        }
133    }
134}
135
136/// Captures any errors Momento has detected during log configuration
137#[derive(Debug, Error)]
138pub enum LogConfigurationError {
139    #[error("Invalid auth provided for configuration! {message}")]
140    /// Invalid auth was provided
141    Auth {
142        /// The error message bubbled back up
143        message: String,
144    },
145    #[error("Something went wrong while trying to configure logs! {message}")]
146    /// Something went wrong
147    Unknown {
148        /// The error message bubbled back up
149        message: String,
150    },
151}
152
153impl From<logging::LogConfigurationError> for LogConfigurationError {
154    fn from(value: logging::LogConfigurationError) -> Self {
155        match value {
156            logging::LogConfigurationError::Auth(e) => Self::Auth { message: e },
157        }
158    }
159}
160
161/// Configures logging via Momento host functions
162pub fn configure_host_logging(
163    configurations: impl IntoIterator<Item = LogConfiguration>,
164) -> Result<(), LogConfigurationError> {
165    let configurations = configurations
166        .into_iter()
167        .map(|configuration| configuration.into())
168        .collect::<Vec<logging::ConfigureLoggingInput>>();
169    Ok(logging::configure_logging(&configurations)?)
170}
171
172/// Logs a given string
173pub fn log(input: &str, level: log::Level) {
174    logging::log(
175        input,
176        match level {
177            log::Level::Error => logging::LogLevel::Error,
178            log::Level::Warn => logging::LogLevel::Warn,
179            log::Level::Info => logging::LogLevel::Info,
180            log::Level::Debug => logging::LogLevel::Debug,
181            // Momento does not publish Trace logs
182            log::Level::Trace => logging::LogLevel::Debug,
183        },
184    )
185}