wasmcloud_logging/
lib.rs

1use actor::HealthCheckResponse;
2use log::{debug, error, info, trace, warn};
3use std::error::Error;
4use std::sync::{Arc, RwLock};
5use wasmcloud_actor_core as actor;
6use wasmcloud_actor_logging::{WriteLogArgs, OP_LOG};
7use wasmcloud_provider_core::{
8    capabilities::{CapabilityProvider, Dispatcher, NullDispatcher},
9    capability_provider,
10    core::{OP_BIND_ACTOR, OP_HEALTH_REQUEST, OP_REMOVE_ACTOR},
11    deserialize, serialize,
12};
13
14#[cfg(not(feature = "static_plugin"))]
15capability_provider!(LoggingProvider, LoggingProvider::new);
16
17#[allow(unused)]
18const CAPABILITY_ID: &str = "wasmcloud:logging";
19const SYSTEM_ACTOR: &str = "system";
20
21const ERROR: &str = "error";
22const WARN: &str = "warn";
23const INFO: &str = "info";
24const DEBUG: &str = "debug";
25const TRACE: &str = "trace";
26
27/// Standard output logging implementation of the `wasmcloud:logging` specification
28#[derive(Clone)]
29pub struct LoggingProvider {
30    dispatcher: Arc<RwLock<Box<dyn Dispatcher>>>,
31}
32
33impl Default for LoggingProvider {
34    fn default() -> Self {
35        if env_logger::try_init().is_err() {}
36
37        LoggingProvider {
38            dispatcher: Arc::new(RwLock::new(Box::new(NullDispatcher::new()))),
39        }
40    }
41}
42
43impl LoggingProvider {
44    /// Creates a new logging provider
45    pub fn new() -> Self {
46        Self::default()
47    }
48
49    fn write_log(
50        &self,
51        actor: &str,
52        log_msg: WriteLogArgs,
53    ) -> Result<Vec<u8>, Box<dyn Error + Sync + Send>> {
54        match &*log_msg.level {
55            ERROR => error!(target: &log_msg.target, "[{}] {}", actor, log_msg.text),
56            WARN => warn!(target: &log_msg.target, "[{}] {}", actor, log_msg.text),
57            INFO => info!(target: &log_msg.target, "[{}] {}", actor, log_msg.text),
58            DEBUG => debug!(target: &log_msg.target, "[{}] {}", actor, log_msg.text),
59            TRACE => trace!(target: &log_msg.target, "[{}] {}", actor, log_msg.text),
60            _ => error!("Unknown log level: {}", log_msg.level),
61        }
62        Ok(vec![])
63    }
64}
65
66impl CapabilityProvider for LoggingProvider {
67    // Invoked by the runtime host to give this provider plugin the ability to communicate
68    // with actors
69    fn configure_dispatch(
70        &self,
71        dispatcher: Box<dyn Dispatcher>,
72    ) -> Result<(), Box<dyn Error + Sync + Send>> {
73        info!("Dispatcher configured.");
74        let mut lock = self.dispatcher.write().unwrap();
75        *lock = dispatcher;
76
77        Ok(())
78    }
79
80    // Invoked by host runtime to allow an actor to make use of the capability
81    // All providers MUST handle the "configure" message, even if no work will be done
82    fn handle_call(
83        &self,
84        actor: &str,
85        op: &str,
86        msg: &[u8],
87    ) -> Result<Vec<u8>, Box<dyn Error + Sync + Send>> {
88        trace!("Handling operation `{}` from `{}`", op, actor);
89        match op {
90            OP_BIND_ACTOR if actor == SYSTEM_ACTOR => Ok(vec![]),
91            OP_REMOVE_ACTOR if actor == SYSTEM_ACTOR => Ok(vec![]),
92            OP_HEALTH_REQUEST if actor == SYSTEM_ACTOR => Ok(serialize(HealthCheckResponse {
93                healthy: true,
94                message: "".to_string(),
95            })?),
96            OP_LOG => self.write_log(actor, deserialize(msg)?),
97            _ => Err(format!("Unknown operation: {}", op).into()),
98        }
99    }
100
101    // No cleanup needed on stop
102    fn stop(&self) {}
103}