rlg/config/
log_rotation.rs1use super::ConfigError;
9use serde::{Deserialize, Serialize};
10use std::fmt;
11use std::num::NonZeroU64;
12use std::str::FromStr;
13
14#[derive(
16 Clone,
17 Copy,
18 Debug,
19 Deserialize,
20 Serialize,
21 Eq,
22 PartialEq,
23 Ord,
24 PartialOrd,
25 Hash,
26)]
27pub enum LogRotation {
28 Size(NonZeroU64),
30 Time(NonZeroU64),
32 Date,
34 Count(u32),
36}
37
38impl FromStr for LogRotation {
39 type Err = ConfigError;
40
41 fn from_str(s: &str) -> Result<Self, Self::Err> {
42 let trimmed = s.trim();
43 let (kind, value) = trimmed
44 .split_once(':')
45 .map_or((trimmed, None), |(k, v)| (k, Some(v)));
46 match kind.to_lowercase().as_str() {
47 "size" => rotation_amount(value, "size").map(Self::Size),
48 "time" => rotation_amount(value, "time").map(Self::Time),
49 "date" => Ok(Self::Date),
50 "count" => rotation_count(value).map(Self::Count),
51 _ => Err(ConfigError::ValidationError(format!(
52 "Invalid log rotation option: '{s}'"
53 ))),
54 }
55 }
56}
57
58fn rotation_amount(
61 value: Option<&str>,
62 what: &str,
63) -> Result<NonZeroU64, ConfigError> {
64 let invalid = |msg: String| ConfigError::ValidationError(msg);
65 let text = value.ok_or_else(|| {
66 invalid(format!("Missing {what} value for log rotation"))
67 })?;
68 let n = text.parse::<u64>().map_err(|_| {
69 invalid(format!(
70 "Invalid {what} value for log rotation: '{text}'"
71 ))
72 })?;
73 NonZeroU64::new(n).ok_or_else(|| {
74 invalid(format!("Log rotation {what} must be greater than 0"))
75 })
76}
77
78fn rotation_count(value: Option<&str>) -> Result<u32, ConfigError> {
80 let invalid = |msg: String| ConfigError::ValidationError(msg);
81 let text = value.ok_or_else(|| {
82 invalid("Missing count value for log rotation".to_string())
83 })?;
84 let n = text.parse::<usize>().map_err(|_| {
85 invalid(format!(
86 "Invalid count value for log rotation: '{text}'"
87 ))
88 })?;
89 if n == 0 {
90 return Err(invalid(
91 "Log rotation count must be greater than 0".to_string(),
92 ));
93 }
94 Ok(n.try_into().unwrap_or(u32::MAX))
95}
96
97impl fmt::Display for LogRotation {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 match self {
100 Self::Size(size) => write!(f, "Size: {size} bytes"),
101 Self::Time(seconds) => write!(f, "Time: {seconds} seconds"),
102 Self::Date => write!(f, "Date-based rotation"),
103 Self::Count(count) => write!(f, "Count: {count} logs"),
104 }
105 }
106}