introduce and use new route framework
in this change: * new "concurrent map" API using RwLock<HashMap> optimized for frequent reads. * we no longer have a concurrent map of log handlers, we instead have a log handler containing a concurrent map from origins to circular buffers * we have a general concept of a "Limit" now which replaces AlertRule * A route consists of a filter, plus any number of limits, which can be per-origin limits or global limits * The set of routes is disjunctive, while the filters and limits are conjunctive * Limits can also apply per source location * Different types of rate limiters are unified under the "Limiter" abstraction * The log handler also has a set of overall limiters that can be applied at the end * This means we can relatively easily express disjunctions of conjunctions I think the route structure will also be relatively easy to express in toml
This commit is contained in:
@@ -156,6 +156,7 @@ async fn handle_tcp_connection(stream: TcpStream, gateway: &Gateway) -> std::io:
|
||||
/// A flexible JSON log message format compatible with logstash and similar systems.
|
||||
///
|
||||
/// Supports various field names and formats commonly used in logging systems.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct JsonLogMessage {
|
||||
/// The log message text - accepts "message" or "msg"
|
||||
@@ -163,7 +164,7 @@ pub struct JsonLogMessage {
|
||||
pub message: String,
|
||||
|
||||
/// Log level - accepts various formats (error, ERROR, err, etc.)
|
||||
#[serde(default, alias = "severity", deserialize_with = "deserialize_level")]
|
||||
#[serde(default, alias = "severity", deserialize_with = "deserialize_opt_level")]
|
||||
pub level: Option<Level>,
|
||||
|
||||
/// Timestamp - accepts Unix epoch seconds (int or string) or RFC3339 string
|
||||
@@ -228,29 +229,13 @@ impl JsonLogMessage {
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize a log level from various string formats
|
||||
fn deserialize_level<'de, D>(deserializer: D) -> Result<Option<Level>, D::Error>
|
||||
/// Deserialize an optional log level, returning None for unknown values.
|
||||
fn deserialize_opt_level<'de, D>(deserializer: D) -> Result<Option<Level>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let opt: Option<String> = Option::deserialize(deserializer)?;
|
||||
Ok(opt.and_then(|s| parse_level(&s)))
|
||||
}
|
||||
|
||||
/// Parse a level string into a Level enum
|
||||
fn parse_level(s: &str) -> Option<Level> {
|
||||
match s.to_lowercase().as_str() {
|
||||
"emergency" | "emerg" => Some(Level::EMERGENCY),
|
||||
"alert" => Some(Level::ALERT),
|
||||
"critical" | "crit" | "fatal" => Some(Level::CRITICAL),
|
||||
"error" | "err" => Some(Level::ERROR),
|
||||
"warning" | "warn" => Some(Level::WARNING),
|
||||
"notice" => Some(Level::NOTICE),
|
||||
"info" | "information" => Some(Level::INFO),
|
||||
"debug" => Some(Level::DEBUG),
|
||||
"trace" => Some(Level::TRACE),
|
||||
_ => None,
|
||||
}
|
||||
Ok(opt.and_then(|s| Level::from_str(&s)))
|
||||
}
|
||||
|
||||
/// Deserialize a timestamp from Unix epoch (int or string) or RFC3339 string
|
||||
|
||||
Reference in New Issue
Block a user