Mercurial > lbo > hg > syslog
view src/rule.rs @ 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 | |
children | 071e6d446dbd |
line wrap: on
line source
#![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 } }