wascc_logging/
lib.rs

1// Copyright 2015-2020 Capital One Services, LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#[macro_use]
16extern crate wascc_codec as codec;
17
18use codec::capabilities::{
19    CapabilityDescriptor, CapabilityProvider, Dispatcher, NullDispatcher, OperationDirection,
20    OP_GET_CAPABILITY_DESCRIPTOR,
21};
22use codec::core::{OP_BIND_ACTOR, OP_REMOVE_ACTOR};
23use codec::{
24    deserialize,
25    logging::{WriteLogRequest, OP_LOG},
26    serialize,
27};
28
29#[macro_use]
30extern crate log;
31
32use std::error::Error;
33use std::sync::RwLock;
34
35#[cfg(not(feature = "static_plugin"))]
36capability_provider!(LoggingProvider, LoggingProvider::new);
37
38const CAPABILITY_ID: &str = "wascc:logging";
39const SYSTEM_ACTOR: &str = "system";
40const VERSION: &str = env!("CARGO_PKG_VERSION");
41const REVISION: u32 = 2; // Increment for each crates publish
42
43const ERROR: u32 = 1;
44const WARN: u32 = 2;
45const INFO: u32 = 3;
46const DEBUG: u32 = 4;
47const TRACE: u32 = 5;
48
49/// Standard output logging implementation of the `wascc:logging` specification
50pub struct LoggingProvider {
51    dispatcher: RwLock<Box<dyn Dispatcher>>,
52}
53
54impl Default for LoggingProvider {
55    fn default() -> Self {
56        match env_logger::try_init() {
57            Ok(_) => {}
58            Err(_) => {}
59        }
60
61        LoggingProvider {
62            dispatcher: RwLock::new(Box::new(NullDispatcher::new())),
63        }
64    }
65}
66
67impl LoggingProvider {
68    /// Creates a new logging provider
69    pub fn new() -> Self {
70        Self::default()
71    }
72
73    fn get_descriptor(&self) -> Result<Vec<u8>, Box<dyn Error + Sync + Send>> {
74        Ok(serialize(
75            CapabilityDescriptor::builder()
76                .id(CAPABILITY_ID)
77                .name("waSCC Default Logging Provider (STDOUT)")
78                .long_description(
79                    "A simple logging capability provider that supports levels from error to trace",
80                )
81                .version(VERSION)
82                .revision(REVISION)
83                .with_operation(
84                    OP_LOG,
85                    OperationDirection::ToProvider,
86                    "Sends a log message to stdout",
87                )
88                .build(),
89        )?)
90    }
91
92    fn write_log(
93        &self,
94        actor: &str,
95        log_msg: WriteLogRequest,
96    ) -> Result<Vec<u8>, Box<dyn Error + Sync + Send>> {
97        match log_msg.level {
98            ERROR => error!("[{}] {}", actor, log_msg.body),
99            WARN => warn!("[{}] {}", actor, log_msg.body),
100            INFO => info!("[{}] {}", actor, log_msg.body),
101            DEBUG => debug!("[{}] {}", actor, log_msg.body),
102            TRACE => trace!("[{}] {}", actor, log_msg.body),
103            _ => error!("Unknown log level: {}", log_msg.level),
104        }
105        Ok(vec![])
106    }
107}
108
109impl CapabilityProvider for LoggingProvider {
110    // Invoked by the runtime host to give this provider plugin the ability to communicate
111    // with actors
112    fn configure_dispatch(
113        &self,
114        dispatcher: Box<dyn Dispatcher>,
115    ) -> Result<(), Box<dyn Error + Sync + Send>> {
116        let mut lock = self.dispatcher.write().unwrap();
117        *lock = dispatcher;
118
119        Ok(())
120    }
121
122    // Invoked by host runtime to allow an actor to make use of the capability
123    // All providers MUST handle the "configure" message, even if no work will be done
124    fn handle_call(
125        &self,
126        actor: &str,
127        op: &str,
128        msg: &[u8],
129    ) -> Result<Vec<u8>, Box<dyn Error + Sync + Send>> {
130        match op {
131            OP_BIND_ACTOR if actor == SYSTEM_ACTOR => Ok(vec![]),
132            OP_REMOVE_ACTOR if actor == SYSTEM_ACTOR => Ok(vec![]),
133            OP_GET_CAPABILITY_DESCRIPTOR if actor == SYSTEM_ACTOR => self.get_descriptor(),
134            OP_LOG => self.write_log(actor, deserialize(msg)?),
135            _ => Err(format!("Unknown operation: {}", op).into()),
136        }
137    }
138}