feat: add request logging and source address tracking to server
Co-authored-by: aider (openai/andrew/openrouter/anthropic/claude-sonnet-4) <aider@aider.chat>
This commit is contained in:
@@ -1,13 +1,13 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Path, Query, State},
|
extract::{ConnectInfo, Path, Query, State},
|
||||||
http::{HeaderMap, StatusCode},
|
http::{HeaderMap, StatusCode},
|
||||||
response::{Html, Json},
|
response::{Html, Json},
|
||||||
routing::get,
|
routing::get,
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use clap::Command;
|
use clap::Command;
|
||||||
use log::{info, warn};
|
use log::{debug, info, warn};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -17,6 +17,8 @@ use std::str::FromStr;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use tower_http::cors::CorsLayer;
|
use tower_http::cors::CorsLayer;
|
||||||
|
use tower::ServiceBuilder;
|
||||||
|
use tower_http::trace::TraceLayer;
|
||||||
|
|
||||||
use crate::db;
|
use crate::db;
|
||||||
use crate::Args;
|
use crate::Args;
|
||||||
@@ -122,7 +124,11 @@ async fn run_server(
|
|||||||
.route("/content/:id", get(handle_get_content))
|
.route("/content/:id", get(handle_get_content))
|
||||||
.route("/openapi.json", get(handle_openapi))
|
.route("/openapi.json", get(handle_openapi))
|
||||||
.route("/swagger/", get(handle_swagger_ui))
|
.route("/swagger/", get(handle_swagger_ui))
|
||||||
.layer(CorsLayer::permissive())
|
.layer(
|
||||||
|
ServiceBuilder::new()
|
||||||
|
.layer(TraceLayer::new_for_http())
|
||||||
|
.layer(CorsLayer::permissive())
|
||||||
|
)
|
||||||
.with_state(state);
|
.with_state(state);
|
||||||
|
|
||||||
let addr: SocketAddr = if config.address.starts_with('/') || config.address.starts_with("./") {
|
let addr: SocketAddr = if config.address.starts_with('/') || config.address.starts_with("./") {
|
||||||
@@ -157,8 +163,11 @@ fn check_auth(headers: &HeaderMap, password: &Option<String>) -> bool {
|
|||||||
async fn handle_status(
|
async fn handle_status(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
||||||
) -> Result<Json<ApiResponse<StatusInfo>>, StatusCode> {
|
) -> Result<Json<ApiResponse<StatusInfo>>, StatusCode> {
|
||||||
|
debug!("GET /status from {}", addr);
|
||||||
if !check_auth(&headers, &state.password) {
|
if !check_auth(&headers, &state.password) {
|
||||||
|
warn!("Unauthorized request from {}", addr);
|
||||||
return Err(StatusCode::UNAUTHORIZED);
|
return Err(StatusCode::UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,8 +201,11 @@ async fn handle_list_items(
|
|||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Query(params): Query<TagsQuery>,
|
Query(params): Query<TagsQuery>,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
||||||
) -> Result<Json<ApiResponse<Vec<ItemInfo>>>, StatusCode> {
|
) -> Result<Json<ApiResponse<Vec<ItemInfo>>>, StatusCode> {
|
||||||
|
debug!("GET /item/ from {} with params: {:?}", addr, params);
|
||||||
if !check_auth(&headers, &state.password) {
|
if !check_auth(&headers, &state.password) {
|
||||||
|
warn!("Unauthorized request to /item/ from {}", addr);
|
||||||
return Err(StatusCode::UNAUTHORIZED);
|
return Err(StatusCode::UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,8 +267,11 @@ async fn handle_get_item(
|
|||||||
Path(item_id): Path<String>,
|
Path(item_id): Path<String>,
|
||||||
Query(params): Query<TagsQuery>,
|
Query(params): Query<TagsQuery>,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
||||||
) -> Result<Json<ApiResponse<ItemInfo>>, StatusCode> {
|
) -> Result<Json<ApiResponse<ItemInfo>>, StatusCode> {
|
||||||
|
debug!("GET /item/{} from {} with params: {:?}", item_id, addr, params);
|
||||||
if !check_auth(&headers, &state.password) {
|
if !check_auth(&headers, &state.password) {
|
||||||
|
warn!("Unauthorized request to /item/{} from {}", item_id, addr);
|
||||||
return Err(StatusCode::UNAUTHORIZED);
|
return Err(StatusCode::UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,8 +326,11 @@ async fn handle_get_item(
|
|||||||
async fn handle_put_item(
|
async fn handle_put_item(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
||||||
) -> Result<Json<ApiResponse<ItemInfo>>, StatusCode> {
|
) -> Result<Json<ApiResponse<ItemInfo>>, StatusCode> {
|
||||||
|
debug!("PUT /item/ from {}", addr);
|
||||||
if !check_auth(&headers, &state.password) {
|
if !check_auth(&headers, &state.password) {
|
||||||
|
warn!("Unauthorized request to PUT /item/ from {}", addr);
|
||||||
return Err(StatusCode::UNAUTHORIZED);
|
return Err(StatusCode::UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,8 +351,11 @@ async fn handle_delete_item(
|
|||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Path(item_id): Path<String>,
|
Path(item_id): Path<String>,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
||||||
) -> Result<Json<ApiResponse<()>>, StatusCode> {
|
) -> Result<Json<ApiResponse<()>>, StatusCode> {
|
||||||
|
debug!("DELETE /item/{} from {}", item_id, addr);
|
||||||
if !check_auth(&headers, &state.password) {
|
if !check_auth(&headers, &state.password) {
|
||||||
|
warn!("Unauthorized request to DELETE /item/{} from {}", item_id, addr);
|
||||||
return Err(StatusCode::UNAUTHORIZED);
|
return Err(StatusCode::UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,8 +383,11 @@ async fn handle_get_content_latest(
|
|||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Query(params): Query<TagsQuery>,
|
Query(params): Query<TagsQuery>,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
||||||
) -> Result<Json<ApiResponse<String>>, StatusCode> {
|
) -> Result<Json<ApiResponse<String>>, StatusCode> {
|
||||||
|
debug!("GET /content from {} with params: {:?}", addr, params);
|
||||||
if !check_auth(&headers, &state.password) {
|
if !check_auth(&headers, &state.password) {
|
||||||
|
warn!("Unauthorized request to /content from {}", addr);
|
||||||
return Err(StatusCode::UNAUTHORIZED);
|
return Err(StatusCode::UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,8 +419,11 @@ async fn handle_get_content(
|
|||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Path(item_id): Path<String>,
|
Path(item_id): Path<String>,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
||||||
) -> Result<Json<ApiResponse<String>>, StatusCode> {
|
) -> Result<Json<ApiResponse<String>>, StatusCode> {
|
||||||
|
debug!("GET /content/{} from {}", item_id, addr);
|
||||||
if !check_auth(&headers, &state.password) {
|
if !check_auth(&headers, &state.password) {
|
||||||
|
warn!("Unauthorized request to /content/{} from {}", item_id, addr);
|
||||||
return Err(StatusCode::UNAUTHORIZED);
|
return Err(StatusCode::UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user