This commit is contained in:
2025-04-29 02:53:21 -04:00
parent 8a7da4a75a
commit 6a7ff0b019
3 changed files with 298 additions and 0 deletions
Generated
+186
View File
@@ -0,0 +1,186 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "colored"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
dependencies = [
"windows-sys",
]
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "nginx-log-fmt"
version = "0.1.0"
dependencies = [
"colored",
"serde",
"serde_json",
"tap",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "serde"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "2.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+10
View File
@@ -0,0 +1,10 @@
[package]
name = "nginx-log-fmt"
version = "0.1.0"
edition = "2024"
[dependencies]
colored = "3.0.0"
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"
tap = "1.0.1"
+102
View File
@@ -0,0 +1,102 @@
use serde::Deserialize;
use std::io::{self, BufRead};
use colored::*;
use tap::Tap;
#[derive(Deserialize)]
struct LogEntry {
t: String,
m: String,
p: String,
s: u16,
u: String,
ip: String,
ic: String,
ua: String,
sz: Option<u64>,
rf: Option<String>,
}
fn main() {
let stdin = io::stdin();
for line in stdin.lock().lines() {
if let Ok(line) = line {
if line.trim().is_empty() {
continue;
}
match serde_json::from_str::<LogEntry>(&line) {
Ok(entry) => {
print_entry(entry);
}
Err(e) => {
eprintln!("Failed to parse line: {}\nError: {}", line, e);
}
}
}
}
}
fn exactly_n(s: &str, n: usize) -> String {
if s.chars().count() > n {
s.chars().take(n).collect()
} else {
s.to_string().tap_mut(|x| x.push_str(&" ".repeat(n - s.chars().count())))
}
}
fn fmt_size(size: u64) -> String {
let size = size as f64;
let units = [" ", "K", "M", "G", "T"];
let mut i = 0;
let mut size = size;
while size >= 1024.0 && i < units.len() - 1 {
size /= 1024.0;
i += 1;
}
format!("{:3.0}{}", size, units[i])
}
fn print_entry(log: LogEntry) {
let timestamp = &log.t[5..19].replace('T', " ");
let proto = log.p.splitn(2, '/').nth(1).unwrap_or("").to_string();
let ip = if !log.ic.is_empty() { log.ic } else { log.ip };
// Parse URL for domain and path
let prefix = format!("{}://", log.u.splitn(2, "://").next().unwrap_or(""));
let tmp_url = log.u.splitn(2, "://").nth(1).unwrap_or("");
let (domain, path) = match tmp_url.find('/') {
Some(pos) => (&tmp_url[..pos], &tmp_url[pos..]),
None => (tmp_url, "/"),
};
// Status color
let status = if (200..400).contains(&log.s) {
log.s.to_string().blue()
} else {
log.s.to_string().red()
};
// Print
print!(
"{} {} {} {} {} {} {}{}{} {}",
timestamp.dimmed(),
exactly_n(&log.m, 4).yellow(),
proto.yellow(),
status,
fmt_size(log.sz.unwrap_or(0)).dimmed(),
exactly_n(&ip, 15).yellow(),
prefix.dimmed(),
domain.blue(),
path.dimmed(),
log.ua.truecolor(255, 165, 0),
);
// Print referrer if present
if let Some(refer) = log.rf.filter(|r| !r.is_empty()) {
print!(" {} {}", "from".dimmed(), refer.truecolor(255, 165, 0));
}
println!();
}