Mercurial > lbo > hg > syslog
changeset 23:2b5e442c8bbb draft
Move rule logic into dedicated module
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Sun, 04 Dec 2016 16:32:37 +0100 |
parents | 226f1c607612 |
children | ed9eb9cfeb83 |
files | src/config.rs src/rule.rs |
diffstat | 2 files changed, 173 insertions(+), 160 deletions(-) [+] |
line wrap: on
line diff
--- a/src/config.rs Sat Dec 03 16:27:07 2016 +0100 +++ b/src/config.rs Sun Dec 04 16:32:37 2016 +0100 @@ -13,6 +13,7 @@ use toml; use priority; +use rule::{self, Rule}; /// Parses strings like 0/1s/2m/3h/4d/5w and returns seconds. If no unit is there, seconds is /// assumed. @@ -183,7 +184,7 @@ Some(res) } -fn tomlerr<T>(s: String) -> Result<T, toml::Error> { +pub fn tomlerr<T>(s: String) -> Result<T, toml::Error> { Err(toml::Error::Custom(s)) } @@ -280,174 +281,17 @@ Ok(f) } -#[derive(Clone, Debug)] -pub enum FacPattern { - /// '*' - Wildcard, - Facility(priority::Facility), - MultiFacility(Vec<priority::Facility>), -} - -#[derive(Clone, Debug)] -pub enum LvlPattern { - Wildcard, - /// Matches that level, or any lower (more important) level - Level(priority::Level), - /// Matches only that level - ExactLevel(priority::Level), - MultiLevel(Vec<priority::Level>), -} - -impl Default for FacPattern { - fn default() -> FacPattern { - FacPattern::Wildcard - } -} - -impl Default for LvlPattern { - fn default() -> LvlPattern { - LvlPattern::Wildcard - } -} - -/// A Filter specifies one or more Facilities, and one or more Levels. -type Filter = (FacPattern, LvlPattern); -/// A Matcher is one or more Filters. -type Matcher = Vec<Filter>; - -/// a pattern for a rule matches syslog messages based on level and facility. Valid patterns -/// are: -/// -/// *.* -- match all -/// mail.* -- match all mail records -/// mail,news.* -- match all mail and news records -/// mail.warn,info -- match all mail records at warn or info -/// mail,news.info,warn -- match all mail or news records at warn or info. -/// mail.*;news,auth.info -- match all mail records and records for news or auth at info or higher -/// (!) => if only a single level is given, this means "this level or more important"; if you only want to -/// match that single level, use a rule like "mail.=info". -fn parse_matcher(s: &str) -> Result<Matcher, toml::Error> { - let mut matcher = Vec::with_capacity(3); - - for filter in s.trim().split(';') { - if filter.len() == 0 { - return Ok(matcher); - } - - match parse_filter(filter) { - Ok(f) => matcher.push(f), - Err(e) => return Err(e), - } - } - Ok(matcher) -} - -fn parse_filter(s: &str) -> Result<Filter, toml::Error> { - let mut parts = s.trim().split('.'); - - if let Some(facilities) = parts.next() { - if let Some(levels) = parts.next() { - return match (parse_facility_pattern(facilities), parse_level_pattern(levels)) { - (Ok(f), Ok(l)) => Ok((f, l)), - (Err(e), Err(f)) => tomlerr(format!("{} {}", e, f)), - (Ok(_), Err(e)) => tomlerr(format!("{}", e)), - (Err(e), Ok(_)) => tomlerr(format!("{}", e)), - }; - } - } - tomlerr(format!("Bad filter pattern: {}", s)) -} - -fn parse_facility_pattern(s: &str) -> Result<FacPattern, toml::Error> { - let list: Vec<String> = s.trim().split(',').map(String::from).collect(); - - if list.len() > 1 { - let mut facilities = Vec::with_capacity(list.len()); - - for f in list { - if let Some(fac) = priority::str_to_facility(f.trim()) { - facilities.push(fac); - } else { - return tomlerr(format!("Unrecognized facility: {}", f)); - } - } - Ok(FacPattern::MultiFacility(facilities)) - } else if list.len() == 1 { - let l = &list[0]; - - if l == "*" { - Ok(FacPattern::Wildcard) - } else if let Some(fac) = priority::str_to_facility(l) { - Ok(FacPattern::Facility(fac)) - } else { - tomlerr(format!("Unknown facility: {}", l)) - } - } else { - return tomlerr(format!("Level pattern can't be empty")); - } -} - -fn parse_level_pattern(s: &str) -> Result<LvlPattern, toml::Error> { - let list: Vec<String> = s.trim().split(',').map(String::from).collect(); - - if list.len() > 1 { - let mut levels = Vec::with_capacity(list.len()); - - for l in list { - if let Some(lvl) = priority::str_to_level(l.trim()) { - levels.push(lvl); - } else { - return tomlerr(format!("Unrecognized facility: {}", l)); - } - } - Ok(LvlPattern::MultiLevel(levels)) - } else if list.len() == 1 { - let l = &list[0]; - - // exact rule - if &l[0..1] == "=" { - if let Some(fac) = priority::str_to_level(&l[1..]) { - Ok(LvlPattern::ExactLevel(fac)) - } else { - tomlerr(format!("Unknown exact facility: {}", l)) - } - } else if &l[..] == "*" { - Ok(LvlPattern::Wildcard) - } else if let Some(lvl) = priority::str_to_level(l) { - Ok(LvlPattern::Level(lvl)) - } else { - tomlerr(format!("Unknown facility: {}", &list[0])) - } - } else { - return tomlerr(format!("Level pattern can't be empty")); - } -} - -#[derive(Clone, Debug, Default)] -pub struct Rule { - pattern: Matcher, - // refers to the file entry name, not the file name. - file: String, - remote_dest: String, - stop: bool, -} - /// Takes a "rule" table fn assemble_rule(t: &toml::Table) -> Result<Rule, toml::Error> { let pattern = get_string(t, "pattern", "".to_string()); - let matcher = try!(parse_matcher(&pattern)); + let matcher = try!(rule::parse_matcher(&pattern)); let file = get_string(t, "dest", "null".to_string()); let remote = get_string(t, "remote_dest", "".to_string()); let stop = get_bool(t, "stop", false); - Ok(Rule { - pattern: matcher, - file: file, - remote_dest: remote, - stop: stop, - }) + Ok(rule::new_rule(matcher, file, remote, stop)) } #[derive(Clone, Debug, Default)]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rule.rs Sun Dec 04 16:32:37 2016 +0100 @@ -0,0 +1,169 @@ +#![allow(dead_code)] + +use std::default::Default; + +use toml; + +use config::tomlerr; +use priority; + +#[derive(Clone, Debug)] +pub enum FacPattern { + /// '*' + Wildcard, + Facility(priority::Facility), + MultiFacility(Vec<priority::Facility>), +} + +#[derive(Clone, Debug)] +pub enum LvlPattern { + Wildcard, + /// Matches that level, or any lower (more important) level + Level(priority::Level), + /// Matches only that level + ExactLevel(priority::Level), + MultiLevel(Vec<priority::Level>), +} + +impl Default for FacPattern { + fn default() -> FacPattern { + FacPattern::Wildcard + } +} + +impl Default for LvlPattern { + fn default() -> LvlPattern { + LvlPattern::Wildcard + } +} + +/// A Filter specifies one or more Facilities, and one or more Levels. +type Filter = (FacPattern, LvlPattern); +/// A Matcher is one or more Filters. +type Matcher = Vec<Filter>; + +/// a pattern for a rule matches syslog messages based on level and facility. Valid patterns +/// are: +/// +/// *.* -- match all +/// mail.* -- match all mail records +/// mail,news.* -- match all mail and news records +/// mail.warn,info -- match all mail records at warn or info +/// mail,news.info,warn -- match all mail or news records at warn or info. +/// mail.*;news,auth.info -- match all mail records and records for news or auth at info or higher +/// (!) => if only a single level is given, this means "this level or more important"; if you only want to +/// match that single level, use a rule like "mail.=info". +pub fn parse_matcher(s: &str) -> Result<Matcher, toml::Error> { + let mut matcher = Vec::with_capacity(3); + + for filter in s.trim().split(';') { + if filter.len() == 0 { + return Ok(matcher); + } + + match parse_filter(filter) { + Ok(f) => matcher.push(f), + Err(e) => return Err(e), + } + } + Ok(matcher) +} + +fn parse_filter(s: &str) -> Result<Filter, toml::Error> { + let mut parts = s.trim().split('.'); + + if let Some(facilities) = parts.next() { + if let Some(levels) = parts.next() { + return match (parse_facility_pattern(facilities), parse_level_pattern(levels)) { + (Ok(f), Ok(l)) => Ok((f, l)), + (Err(e), Err(f)) => tomlerr(format!("{} {}", e, f)), + (Ok(_), Err(e)) => tomlerr(format!("{}", e)), + (Err(e), Ok(_)) => tomlerr(format!("{}", e)), + }; + } + } + tomlerr(format!("Bad filter pattern: {}", s)) +} + +fn parse_facility_pattern(s: &str) -> Result<FacPattern, toml::Error> { + let list: Vec<String> = s.trim().split(',').map(String::from).collect(); + + if list.len() > 1 { + let mut facilities = Vec::with_capacity(list.len()); + + for f in list { + if let Some(fac) = priority::str_to_facility(f.trim()) { + facilities.push(fac); + } else { + return tomlerr(format!("Unrecognized facility: {}", f)); + } + } + Ok(FacPattern::MultiFacility(facilities)) + } else if list.len() == 1 { + let l = &list[0]; + + if l == "*" { + Ok(FacPattern::Wildcard) + } else if let Some(fac) = priority::str_to_facility(l) { + Ok(FacPattern::Facility(fac)) + } else { + tomlerr(format!("Unknown facility: {}", l)) + } + } else { + return tomlerr(format!("Level pattern can't be empty")); + } +} + +fn parse_level_pattern(s: &str) -> Result<LvlPattern, toml::Error> { + let list: Vec<String> = s.trim().split(',').map(String::from).collect(); + + if list.len() > 1 { + let mut levels = Vec::with_capacity(list.len()); + + for l in list { + if let Some(lvl) = priority::str_to_level(l.trim()) { + levels.push(lvl); + } else { + return tomlerr(format!("Unrecognized facility: {}", l)); + } + } + Ok(LvlPattern::MultiLevel(levels)) + } else if list.len() == 1 { + let l = &list[0]; + + // exact rule + if &l[0..1] == "=" { + if let Some(fac) = priority::str_to_level(&l[1..]) { + Ok(LvlPattern::ExactLevel(fac)) + } else { + tomlerr(format!("Unknown exact facility: {}", l)) + } + } else if &l[..] == "*" { + Ok(LvlPattern::Wildcard) + } else if let Some(lvl) = priority::str_to_level(l) { + Ok(LvlPattern::Level(lvl)) + } else { + tomlerr(format!("Unknown facility: {}", &list[0])) + } + } else { + return tomlerr(format!("Level pattern can't be empty")); + } +} + +#[derive(Clone, Debug, Default)] +pub struct Rule { + pattern: Matcher, + // refers to the file entry name, not the file name. + file: String, + remote_dest: String, + stop: bool, +} + +pub fn new_rule(pattern: Matcher, file: String, remote_dest: String, stop: bool) -> Rule { + Rule { + pattern: pattern, + file: file, + remote_dest: remote_dest, + stop: stop + } +}