aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikolay Govorov <me@govorov.online>2026-01-14 01:57:57 +0000
committerNikolay Govorov <me@govorov.online>2026-01-14 02:01:07 +0000
commita24fcbc469afa7241ec9d7a058e0953794d9b4f4 (patch)
treea5d3fdbcbb8c9b1aeb8f3cd81200d5d71662cf23
parenta49e094d3e85b0b0fb10cf6c5b1a8a4f4259dfae (diff)
downloadtar
tar.gz
tar.bz2
tar.lz
tar.xz
tar.zst
zip
Add accept logging with context
Diffstat
-rw-r--r--Cargo.lock165+163 −2
-rw-r--r--Cargo.toml7+6 −1
-rw-r--r--src/controller_zig.rs1+0 −1
-rw-r--r--src/main.rs114+101 −13
4 files changed, 270 insertions, 17 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 62f2084..056f67e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -18,6 +18,21 @@ dependencies = [
]
[[package]]
+name = "alloc-no-stdlib"
+version = "2.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
+
+[[package]]
+name = "alloc-stdlib"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
+dependencies = [
+ "alloc-no-stdlib",
+]
+
+[[package]]
name = "allocator-api2"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -247,6 +262,27 @@ dependencies = [
]
[[package]]
+name = "brotli"
+version = "8.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560"
+dependencies = [
+ "alloc-no-stdlib",
+ "alloc-stdlib",
+ "brotli-decompressor",
+]
+
+[[package]]
+name = "brotli-decompressor"
+version = "5.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03"
+dependencies = [
+ "alloc-no-stdlib",
+ "alloc-stdlib",
+]
+
+[[package]]
name = "bstr"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -482,9 +518,12 @@ version = "0.4.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00828ba6fd27b45a448e57dbfe84f1029d4c9f26b368157e9a448a5f49a2ec2a"
dependencies = [
+ "brotli",
"compression-core",
"flate2",
"memchr",
+ "zstd",
+ "zstd-safe",
]
[[package]]
@@ -1911,6 +1950,12 @@ dependencies = [
]
[[package]]
+name = "http-range-header"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c"
+
+[[package]]
name = "httparse"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2352,6 +2397,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
+name = "matchers"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
+dependencies = [
+ "regex-automata",
+]
+
+[[package]]
name = "matchit"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2400,6 +2454,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
+name = "mime_guess"
+version = "2.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
+[[package]]
name = "minijinja"
version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3262,6 +3326,15 @@ dependencies = [
]
[[package]]
+name = "sharded-slab"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
name = "shell-words"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3767,6 +3840,15 @@ dependencies = [
]
[[package]]
+name = "thread_local"
+version = "1.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
name = "time"
version = "0.3.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3945,9 +4027,9 @@ checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607"
[[package]]
name = "tower"
-version = "0.5.2"
+version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
+checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
dependencies = [
"futures-core",
"futures-util",
@@ -3966,6 +4048,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
dependencies = [
"async-compression",
+ "base64",
"bitflags",
"bytes",
"futures-core",
@@ -3973,13 +4056,20 @@ dependencies = [
"http",
"http-body",
"http-body-util",
+ "http-range-header",
+ "httpdate",
"iri-string",
+ "mime",
+ "mime_guess",
+ "percent-encoding",
"pin-project-lite",
"tokio",
"tokio-util",
"tower",
"tower-layer",
"tower-service",
+ "tracing",
+ "uuid",
]
[[package]]
@@ -4024,6 +4114,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
dependencies = [
"once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
+dependencies = [
+ "log",
+ "once_cell",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-serde"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1"
+dependencies = [
+ "serde",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
+dependencies = [
+ "matchers",
+ "nu-ansi-term",
+ "once_cell",
+ "regex-automata",
+ "serde",
+ "serde_json",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+ "tracing-serde",
]
[[package]]
@@ -4045,6 +4178,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
[[package]]
+name = "unicase"
+version = "2.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
+
+[[package]]
name = "unicode-bidi"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4115,6 +4254,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
+name = "uuid"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
+dependencies = [
+ "getrandom 0.3.4",
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "valuable"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
+
+[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4797,6 +4953,11 @@ dependencies = [
"thiserror 2.0.17",
"tokio",
"toml",
+ "tower",
+ "tower-http",
+ "tracing",
+ "tracing-subscriber",
+ "uuid",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 5417587..17953b2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,12 +19,17 @@ hyper-tls = "0.6.0"
hyper-util = { version = "0.1.19", features = ["client", "http1", "http2", "tokio"] }
minijinja = "2.14.0"
semver = "1.0"
-sha2 = "0.10"
serde = { version = "1.0", features = ["derive"] }
+sha2 = "0.10"
sqlx = { version = "0.8.6", features = ["sqlite", "runtime-tokio", "macros", "derive", "chrono", "json"] }
thiserror = "2.0"
tokio = { version = "1.49.0", features = ["full"] }
toml = "0.9.8"
+tower-http = { version = "0.6.8", features = ["full"] }
+tracing = "0.1"
+tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
+tower = "0.5.3"
+uuid = { version = "1.19.0", features = ["v4"] }
[dev-dependencies]
cargo-deny = "0.19.0"
diff --git a/src/controller_zig.rs b/src/controller_zig.rs
index 7403998..ba33462 100644
--- a/src/controller_zig.rs
+++ b/src/controller_zig.rs
@@ -188,7 +188,6 @@ impl ZigController {
.upstream
.fetch(service_upstream::DownloadRequest { url })
.await?;
- // bytes: entry.bytes.clone(),
match controller.storage.put("zig", &filename, &entry.bytes).await {
Ok(()) => {}
diff --git a/src/main.rs b/src/main.rs
index 8edafe3..2c68dfb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,16 +1,22 @@
// SPDX-FileCopyrightText: 2026 Nikolay Govorov <me@govorov.online>
// SPDX-License-Identifier: AGPL-3.0-or-later
-use axum::Router;
use std::path::PathBuf;
use std::sync::Arc;
+use axum::{Router, http};
+use tower_http::{request_id, trace::TraceLayer};
+use tracing::{error, info};
+use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
+
mod controller_web;
mod controller_zig;
mod service_config;
mod service_storage;
mod service_upstream;
+static REQUEST_ID_HEADER: http::HeaderName = http::HeaderName::from_static("x-request-id");
+
const VERSION: &str = env!("CARGO_PKG_VERSION");
const HELP: &str = "\
Usage: zorian [--config=<path>]
@@ -38,25 +44,44 @@ async fn main() {
}
}
+ tracing_subscriber::registry()
+ .with({
+ #[cfg(debug_assertions)]
+ let fmt = tracing_subscriber::fmt::layer().pretty();
+ #[cfg(not(debug_assertions))]
+ let fmt = tracing_subscriber::fmt::layer().json();
+ fmt
+ })
+ .with(match std::env::var_os("ZORIAN_LOG") {
+ None => tracing_subscriber::EnvFilter::new("info,tower_http=info"),
+ Some(val) => tracing_subscriber::EnvFilter::try_new(val.to_string_lossy())
+ .expect("Invalid ZORIAN_LOG"),
+ })
+ .init();
+
let config = Arc::new(match config_path {
- Some(path) => service_config::ConfigService::from_file(&path).unwrap_or_else(|e| {
- eprintln!("error: {e}");
- std::process::exit(1);
- }),
- None => service_config::ConfigService::default(),
+ Some(path) => {
+ info!("use config file from {}", path.to_str().unwrap());
+
+ service_config::ConfigService::from_file(&path).unwrap_or_else(|e| {
+ error!("{e}");
+ std::process::exit(1);
+ })
+ }
+ None => {
+ info!("configuration file path not provided");
+ service_config::ConfigService::default()
+ }
});
config.validate().unwrap_or_else(|e| {
- eprintln!("config error: {e}");
+ error!("invalid config: {e}");
std::process::exit(1);
});
let storage = Arc::new(
service_storage::StorageService::new(config.clone())
.await
- .unwrap_or_else(|e| {
- eprintln!("storage error: {e}");
- std::process::exit(1);
- }),
+ .unwrap(),
);
let upstream = Arc::new(service_upstream::UpstreamService::new());
@@ -67,14 +92,77 @@ async fn main() {
upstream.clone(),
));
+ let accept_logger = TraceLayer::new_for_http()
+ .make_span_with(|req: &http::Request<_>| {
+ let request_id = req
+ .headers()
+ .get(&REQUEST_ID_HEADER)
+ .and_then(|v| v.to_str().ok())
+ .unwrap_or("<invalid>");
+
+ tracing::info_span!("http_request", request_id = %request_id)
+ })
+ .on_request(log_request)
+ .on_response(log_response);
+
let app = Router::new()
.merge(web_controller.router())
- .merge(zig_controller.router());
+ .merge(zig_controller.router())
+ .layer(accept_logger)
+ .layer(request_id::PropagateRequestIdLayer::new(
+ REQUEST_ID_HEADER.clone(),
+ ))
+ .layer(request_id::SetRequestIdLayer::new(
+ REQUEST_ID_HEADER.clone(),
+ request_id::MakeRequestUuid,
+ ));
let listener = tokio::net::TcpListener::bind(config.listen())
.await
.unwrap();
- println!("listening on {}", listener.local_addr().unwrap());
+ info!("listening on {}", listener.local_addr().unwrap());
axum::serve(listener, app).await.unwrap();
}
+
+fn log_request<B>(req: &http::Request<B>, _span: &tracing::Span) {
+ let headers = req.headers();
+
+ let client_ip = headers
+ .get("x-forwarded-for")
+ .or_else(|| headers.get("x-real-ip"))
+ .and_then(|v| v.to_str().ok());
+ let user_agent = headers
+ .get(http::header::USER_AGENT)
+ .and_then(|v| v.to_str().ok());
+ let referer = headers
+ .get(http::header::REFERER)
+ .and_then(|v| v.to_str().ok());
+
+ info!(
+ method = %req.method(),
+ uri = %req.uri(),
+ client_ip,
+ user_agent,
+ referer,
+ "request started"
+ );
+}
+
+fn log_response<B>(res: &http::Response<B>, latency: std::time::Duration, _span: &tracing::Span) {
+ let headers = res.headers();
+ let content_length = headers
+ .get(http::header::CONTENT_LENGTH)
+ .and_then(|v| v.to_str().ok());
+ let content_type = headers
+ .get(http::header::CONTENT_TYPE)
+ .and_then(|v| v.to_str().ok());
+
+ info!(
+ status = %res.status(),
+ latency = ?latency,
+ content_length,
+ content_type,
+ "request finished"
+ );
+}