use std::borrow::Cow;
use crate::types::LogError;
use crate::{LogSettings, LoggerConfigHandle, init_log};
use candid::{CandidType, Decode, Encode};
use ic_stable_structures::Memory;
use ic_stable_structures::memory_manager::{MemoryId, MemoryManager, VirtualMemory};
use ic_stable_structures::storable::Bound;
use ic_stable_structures::{StableCell, Storable};
use serde::Deserialize;
impl Storable for LogSettings {
const BOUND: Bound = Bound::Unbounded;
fn to_bytes(&self) -> std::borrow::Cow<'_, [u8]> {
Cow::from(Encode!(&self).unwrap())
}
fn from_bytes(bytes: Cow<[u8]>) -> Self {
Decode!(&bytes, LogSettings).unwrap()
}
fn into_bytes(self) -> Vec<u8> {
Encode!(&self).unwrap()
}
}
const DEFAULT_IN_MEMORY_RECORDS: usize = 1024;
const DEFAULT_MAX_RECORD_LENGTH: usize = 1024;
#[derive(Default, Debug, Clone, CandidType, Deserialize, PartialEq, Eq)]
pub struct LogServiceSettings {
pub enable_console: Option<bool>,
pub in_memory_records: Option<usize>,
pub max_record_length: Option<usize>,
pub log_filter: Option<String>,
}
impl From<LogServiceSettings> for LogSettings {
fn from(settings: LogServiceSettings) -> Self {
Self {
enable_console: settings.enable_console.unwrap_or(false),
in_memory_records: settings
.in_memory_records
.unwrap_or(DEFAULT_IN_MEMORY_RECORDS),
max_record_length: settings
.max_record_length
.unwrap_or(DEFAULT_MAX_RECORD_LENGTH),
log_filter: settings.log_filter.unwrap_or("warn".to_string()),
}
}
}
pub struct LoggerConfigService<M: Memory> {
pub logger_config: Option<LoggerConfigHandle>,
pub log_settings: StableCell<LogSettings, VirtualMemory<M>>,
}
impl<M> LoggerConfigService<M>
where
M: Memory,
{
pub fn new(
memory_manager: &MemoryManager<M>,
logger_service_memory_id: MemoryId,
) -> Result<Self, LogError> {
let service = Self {
logger_config: None,
log_settings: StableCell::new(
memory_manager.get(logger_service_memory_id),
LogSettings {
enable_console: false,
in_memory_records: DEFAULT_IN_MEMORY_RECORDS,
max_record_length: DEFAULT_MAX_RECORD_LENGTH,
log_filter: "warn".to_string(),
},
),
};
Ok(service)
}
pub fn init(&mut self, log_settings: Option<LogServiceSettings>) -> Result<(), LogError> {
if self.logger_config.is_some() {
return Err(LogError::AlreadyInitialized);
}
if let Some(log_settings) = log_settings {
self.log_settings.set(log_settings.into());
}
self.logger_config = Some(init_log(self.log_settings.get())?);
Ok(())
}
pub fn set_logger_filter(&mut self, filter: &str) -> Result<(), LogError> {
self.update_log_settings(filter)?;
match self.logger_config.as_mut() {
Some(logger_config) => logger_config.update_filters(filter),
None => Err(LogError::NotInitialized),
}
}
pub fn get_logger_filter(&self) -> String {
self.log_settings.get().log_filter.clone()
}
fn update_log_settings(&mut self, filter: &str) -> Result<(), LogError> {
let mut log_settings = self.log_settings.get().clone();
log_settings.log_filter = filter.to_string();
self.log_settings.set(log_settings);
Ok(())
}
}