v0.25.5
This commit is contained in:
1 parent
1dea7f55c8
commit
c819f0a335
151 files changed
+7610
-4264
No files matched your search
+98
-24
@@ -1,7 +1,12 @@
|
||||
impl IoWrite for RedactingWriter {
|
||||
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> { self.buffer.extend_from_slice(bytes); Ok(bytes.len()) }
|
||||
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
|
||||
self.buffer.extend_from_slice(bytes);
|
||||
Ok(bytes.len())
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
if self.buffer.is_empty() { return Ok(()); }
|
||||
if self.buffer.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let text = String::from_utf8_lossy(&self.buffer);
|
||||
let redacted = redact_text(&text);
|
||||
let mut stderr = io::stderr().lock();
|
||||
@@ -11,10 +16,18 @@ impl IoWrite for RedactingWriter {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Drop for RedactingWriter { fn drop(&mut self) { let _ = self.flush(); } }
|
||||
impl Drop for RedactingWriter {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.flush();
|
||||
}
|
||||
}
|
||||
impl<'a> tracing_subscriber::fmt::MakeWriter<'a> for RedactingStderr {
|
||||
type Writer = RedactingWriter;
|
||||
fn make_writer(&'a self) -> Self::Writer { RedactingWriter { buffer: Vec::with_capacity(512) } }
|
||||
fn make_writer(&'a self) -> Self::Writer {
|
||||
RedactingWriter {
|
||||
buffer: Vec::with_capacity(512),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn redact_regex(pattern: &'static str) -> &'static regex::Regex {
|
||||
@@ -55,17 +68,31 @@ fn is_secret_field(name: &str) -> bool {
|
||||
}
|
||||
|
||||
pub fn redact_text(input: &str) -> String {
|
||||
let mut value = redact_regex("pem").replace_all(input, "[REDACTED PRIVATE KEY]").into_owned();
|
||||
value = redact_regex("auth").replace_all(&value, "$1[REDACTED]").into_owned();
|
||||
value = redact_regex("query").replace_all(&value, "$1[REDACTED]").into_owned();
|
||||
value = redact_regex("json").replace_all(&value, "$1[REDACTED]$2").into_owned();
|
||||
redact_regex("kv").replace_all(&value, "$1[REDACTED]").into_owned()
|
||||
let mut value = redact_regex("pem")
|
||||
.replace_all(input, "[REDACTED PRIVATE KEY]")
|
||||
.into_owned();
|
||||
value = redact_regex("auth")
|
||||
.replace_all(&value, "$1[REDACTED]")
|
||||
.into_owned();
|
||||
value = redact_regex("query")
|
||||
.replace_all(&value, "$1[REDACTED]")
|
||||
.into_owned();
|
||||
value = redact_regex("json")
|
||||
.replace_all(&value, "$1[REDACTED]$2")
|
||||
.into_owned();
|
||||
redact_regex("kv")
|
||||
.replace_all(&value, "$1[REDACTED]")
|
||||
.into_owned()
|
||||
}
|
||||
|
||||
fn redact_value(value: &mut Value) {
|
||||
match value {
|
||||
Value::String(text) => *text = redact_text(text),
|
||||
Value::Array(items) => for item in items { redact_value(item); },
|
||||
Value::Array(items) => {
|
||||
for item in items {
|
||||
redact_value(item);
|
||||
}
|
||||
}
|
||||
Value::Object(items) => {
|
||||
for (key, item) in items {
|
||||
if is_secret_field(key) {
|
||||
@@ -80,7 +107,10 @@ fn redact_value(value: &mut Value) {
|
||||
}
|
||||
|
||||
fn rfc3339_now() -> String {
|
||||
let ms = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_millis() as i64;
|
||||
let ms = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_millis() as i64;
|
||||
let seconds = ms / 1000;
|
||||
let millis = ms % 1000;
|
||||
let days = seconds.div_euclid(86_400);
|
||||
@@ -94,7 +124,9 @@ fn rfc3339_now() -> String {
|
||||
let mp = (5 * doy + 2) / 153;
|
||||
let day = doy - (153 * mp + 2) / 5 + 1;
|
||||
let month = mp + if mp < 10 { 3 } else { -9 };
|
||||
if month <= 2 { year += 1; }
|
||||
if month <= 2 {
|
||||
year += 1;
|
||||
}
|
||||
let hour = day_seconds / 3600;
|
||||
let minute = (day_seconds % 3600) / 60;
|
||||
let second = day_seconds % 60;
|
||||
@@ -119,7 +151,9 @@ async fn open_error_file(path: PathBuf) -> Result<File> {
|
||||
file.set_permissions(std::fs::Permissions::from_mode(0o600))?;
|
||||
}
|
||||
Ok(file)
|
||||
}).await.map_err(|_| anyhow::anyhow!("error log open worker failed"))??;
|
||||
})
|
||||
.await
|
||||
.map_err(|_| anyhow::anyhow!("error log open worker failed"))??;
|
||||
Ok(File::from_std(file))
|
||||
}
|
||||
|
||||
@@ -223,7 +257,9 @@ async fn error_log_loop(
|
||||
}
|
||||
}
|
||||
}
|
||||
let Some(opened) = file.as_mut() else { continue; };
|
||||
let Some(opened) = file.as_mut() else {
|
||||
continue;
|
||||
};
|
||||
let line = format_error_event(&event, config.format);
|
||||
if let Err(error) = opened.write_all(&line).await {
|
||||
errors.fetch_add(1, Ordering::Relaxed);
|
||||
@@ -360,7 +396,14 @@ impl Logs {
|
||||
pub fn recent_limit(&self, limit: usize) -> Vec<LogEntry> {
|
||||
self.entries
|
||||
.lock()
|
||||
.map(|entries| entries.iter().rev().take(limit.min(HISTORY_CAPACITY)).cloned().collect())
|
||||
.map(|entries| {
|
||||
entries
|
||||
.iter()
|
||||
.rev()
|
||||
.take(limit.min(HISTORY_CAPACITY))
|
||||
.cloned()
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
pub fn stats(&self) -> SinkStats {
|
||||
@@ -406,15 +449,46 @@ fn value_for(entry: &LogEntry, name: &str) -> Value {
|
||||
"path" => json!(&entry.path),
|
||||
"http_version" => json!(entry.http_version),
|
||||
"transport" => json!(entry.transport),
|
||||
"websocket_bootstrap" => entry.websocket_bootstrap.map(|v| Value::String(v.into())).unwrap_or(Value::Null),
|
||||
"websocket_phase" => entry.websocket_phase.map(|v| Value::String(v.into())).unwrap_or(Value::Null),
|
||||
"websocket_error" => entry.websocket_error.map(|v| Value::String(v.into())).unwrap_or(Value::Null),
|
||||
"h3_reset_code" => entry.h3_reset_code.map(|v| Value::String(v.into())).unwrap_or(Value::Null),
|
||||
"upstream_status" => entry.upstream_status.map(|v| json!(v)).unwrap_or(Value::Null),
|
||||
"upstream_error" => entry.upstream_error.clone().map(Value::String).unwrap_or(Value::Null),
|
||||
"client_ip" => entry.client_ip.clone().map(Value::String).unwrap_or(Value::Null),
|
||||
"user_agent" => entry.user_agent.clone().map(Value::String).unwrap_or(Value::Null),
|
||||
"country" => entry.country.clone().map(Value::String).unwrap_or(Value::Null),
|
||||
"websocket_bootstrap" => entry
|
||||
.websocket_bootstrap
|
||||
.map(|v| Value::String(v.into()))
|
||||
.unwrap_or(Value::Null),
|
||||
"websocket_phase" => entry
|
||||
.websocket_phase
|
||||
.map(|v| Value::String(v.into()))
|
||||
.unwrap_or(Value::Null),
|
||||
"websocket_error" => entry
|
||||
.websocket_error
|
||||
.map(|v| Value::String(v.into()))
|
||||
.unwrap_or(Value::Null),
|
||||
"h3_reset_code" => entry
|
||||
.h3_reset_code
|
||||
.map(|v| Value::String(v.into()))
|
||||
.unwrap_or(Value::Null),
|
||||
"upstream_status" => entry
|
||||
.upstream_status
|
||||
.map(|v| json!(v))
|
||||
.unwrap_or(Value::Null),
|
||||
"upstream_error" => entry
|
||||
.upstream_error
|
||||
.clone()
|
||||
.map(Value::String)
|
||||
.unwrap_or(Value::Null),
|
||||
"client_ip" => entry
|
||||
.client_ip
|
||||
.clone()
|
||||
.map(Value::String)
|
||||
.unwrap_or(Value::Null),
|
||||
"user_agent" => entry
|
||||
.user_agent
|
||||
.clone()
|
||||
.map(Value::String)
|
||||
.unwrap_or(Value::Null),
|
||||
"country" => entry
|
||||
.country
|
||||
.clone()
|
||||
.map(Value::String)
|
||||
.unwrap_or(Value::Null),
|
||||
"status" => json!(entry.status),
|
||||
"duration_ms" => json!(entry.duration_ms),
|
||||
"request_bytes" => json!(entry.request_bytes),
|
||||
|
||||
Reference in new issue
Block a user