welog_rs 
Rust port of the Go welog library. Provides structured logging to Elasticsearch with a file fallback plus Axum
middleware that logs requests/responses and target (HTTP client) calls.
Features
- Structured logger that ships JSON logs to Elasticsearch; falls back to
logs.txt(trimmed to 1GB). - Background worker thread for non-blocking log enqueueing.
- Axum middleware (
WelogLayer) that captures request/response payloads, headers, latency, client IP, and attaches a request ID. - Helper to record outbound/target HTTP calls (
log_axum_client) and include them in the same log entry. - Tonic gRPC helpers: interceptor + unary/stream wrappers +
log_grpc_client(mirrors the GoNewGRPCUnary/NewGRPCStream). - Environment-based configuration to match the Go library’s behavior.
Environment variables
The logger reads the following variables:
ELASTIC_INDEX__– index prefix (e.g.,welog)ELASTIC_URL__– Elasticsearch base URL (e.g.,http://localhost:9200)ELASTIC_USERNAME__– Elasticsearch usernameELASTIC_PASSWORD__– Elasticsearch passwordWELOG_QUEUE_CAPACITY__– max in-memory log queue size (default:10000)
If any are missing/empty, logs are written to logs.txt in the working directory.
Usage
Add the dependency
Add from crates.io:
[]
= "1"
= { = "1", = ["full"] }
= { = "0.8", = ["macros", "json"] }
# only for gRPC
= { = "0.14", = ["transport"] }
Or if you vendored the crate locally:
[]
= { = "." } # or use your crate source path
= { = "1", = ["full"] }
= { = "0.8", = ["macros", "json"] }
= { = "0.14", = ["transport"] }
Configure and start Axum
use ;
use ;
use json;
use ;
use ;
use Local;
async
async
async
Log arbitrary events (non-Axum/gRPC)
Logger::log mirrors logrus.WithFields(...).Info() in Go. The helper logger() gives you the global instance (same
shape as Go’s logger.Logger()), so you can emit structured logs from anywhere:
use json;
use logger;
use LogFields;
How it works
WelogLayerclones the request body, response body, headers, status, latency, and client IP, then sends a structured log to the background worker.- Logs are sent to Elasticsearch using
ureqwith a 5s global timeout. Non-2xx/3xx responses are treated as errors. - On error or missing config, logs are appended to
logs.txt, trimming the oldest lines when the file would exceed 1GB. - Request IDs are preserved from the
X-Request-IDheader or generated if missing; the value is added back to the response headers.
gRPC (tonic)
welog_rs now mirrors the Go gRPC interceptors via Tonic helpers:
WelogGrpcInterceptorinjects request ID + logger + client log into request extensions.with_grpc_unary_loggingwraps unary handlers and emits the same fields aslogGRPCUnaryin Go.with_grpc_stream_loggingwraps streaming handlers (logs when the handler future completes) and mirrorslogGRPCStream.log_grpc_clientappends outbound/target logs to the current context.
Integration example (per-service interceptor + handler wrapping):
use Arc;
use ;
use ;
use ;
// Generated by tonic from your proto
use ;
use ;
;
async
Development
- Build:
cargo build - Tests:
cargo test - Rust edition: 2024 (requires Rust 1.91+)
Notes
set_configusesstd::env::set_varand should be called before other threads start (mirrors Rust’s safety note for environment mutation).- Body capture uses
usize::MAXlimit; adjustBODY_READ_LIMITinaxum_middleware.rsif you need to cap memory for very large payloads.