tracing
This commit is contained in:
Generated
+243
-309
File diff suppressed because it is too large
Load Diff
+3
-1
@@ -24,7 +24,9 @@ tokio = { version = "1", features = [
|
||||
"io-util",
|
||||
"macros",
|
||||
] }
|
||||
tower-http = { version = "0", features = ["fs"] }
|
||||
tower-http = { version = "0", features = ["fs", "trace"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
|
||||
urlencoding = "2"
|
||||
wakey-core = { path = "wakey-core" }
|
||||
wakey-linux = { path = "wakey-linux" }
|
||||
|
||||
@@ -64,6 +64,29 @@ The long-term direction is:
|
||||
- keep HTTP as an adapter, not the architecture
|
||||
- eventually move toward an agent + control-plane model
|
||||
|
||||
## Future direction
|
||||
|
||||
The likely next large step is splitting the current temporary HTTP/web hosting
|
||||
role away from the main `wakey` binary.
|
||||
|
||||
The intended shape is roughly:
|
||||
|
||||
- `wakey`
|
||||
- stable service layer and operator CLI
|
||||
- `wakey-agent`
|
||||
- router-side daemon exposing a network API over the service layer
|
||||
- control-center app
|
||||
- remote UI or control plane that talks to one or more agents
|
||||
|
||||
That future agent layer will likely need:
|
||||
|
||||
- explicit registration/authentication
|
||||
- a stable remote API
|
||||
- a small deployment/bootstrap story on the router
|
||||
|
||||
The current CLI and compatibility HTTP adapter are being kept small on purpose
|
||||
so that split can happen later without moving the real product logic again.
|
||||
|
||||
## CLI
|
||||
|
||||
`wakey` is usable as a local/operator CLI.
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
//! Compatibility types and mappers for the legacy HTTP/static client.
|
||||
//!
|
||||
//! These types intentionally preserve old JSON shapes expected by `/static`
|
||||
//! while the core and service layers evolve underneath them. They do not define
|
||||
//! the long-term domain model of the project.
|
||||
|
||||
use serde::Serialize;
|
||||
use wakey_core::parse::mac;
|
||||
use wakey_core::{
|
||||
@@ -49,6 +55,8 @@ pub struct LegacyWakeResultRow {
|
||||
}
|
||||
|
||||
/// Map legacy-style status rows into the old response shape.
|
||||
///
|
||||
/// This helper exists for compatibility with the original frontend contract.
|
||||
pub fn legacy_status_from_domain(status: Status<NeighborEntry>) -> LegacyStatusResponse {
|
||||
LegacyStatusResponse {
|
||||
name: status.name,
|
||||
|
||||
+18
-2
@@ -1,3 +1,9 @@
|
||||
//! Temporary HTTP adapter for the legacy web/static surface.
|
||||
//!
|
||||
//! This module exists to keep the old `/api` routes and `/static` frontend
|
||||
//! working while the project is migrated toward a service-first architecture.
|
||||
//! New product logic should live in [`crate::service`], not here.
|
||||
|
||||
pub mod compat;
|
||||
pub mod route;
|
||||
|
||||
@@ -5,12 +11,17 @@ use std::{io, net::SocketAddr};
|
||||
|
||||
use axum::Router;
|
||||
use tokio::net::TcpListener;
|
||||
use tower_http::services::ServeDir;
|
||||
use tower_http::{services::ServeDir, trace::TraceLayer};
|
||||
use tracing::info;
|
||||
|
||||
/// Build the temporary HTTP app that serves the legacy API and static frontend.
|
||||
///
|
||||
/// This is a compatibility surface. It should stay thin and delegate actual
|
||||
/// product behavior to the service layer.
|
||||
pub fn http_app(static_root: std::path::PathBuf) -> Router {
|
||||
Router::new()
|
||||
.nest("/api", route::api_router())
|
||||
.layer(TraceLayer::new_for_http())
|
||||
.fallback_service(axum::routing::get_service(
|
||||
ServeDir::new(static_root)
|
||||
.append_index_html_on_directories(true)
|
||||
@@ -22,12 +33,17 @@ pub fn http_app(static_root: std::path::PathBuf) -> Router {
|
||||
}
|
||||
|
||||
/// Serve the temporary HTTP app on the provided socket address.
|
||||
///
|
||||
/// This is intended for transition and compatibility, not as the long-term
|
||||
/// architecture boundary of the project.
|
||||
pub async fn serve_http(addr: SocketAddr, static_root: std::path::PathBuf) -> io::Result<()> {
|
||||
info!(%addr, static_root = %static_root.display(), "starting legacy http adapter");
|
||||
let listener = TcpListener::bind(addr).await?;
|
||||
axum::serve(listener, http_app(static_root).into_make_service()).await
|
||||
}
|
||||
|
||||
/// Serve the HTTP app using the `static/` directory next to the current executable.
|
||||
/// Serve the HTTP app using the `static/` directory next to the current
|
||||
/// executable.
|
||||
pub async fn serve_http_from_current_exe(addr: SocketAddr) -> io::Result<()> {
|
||||
let exe = std::env::current_exe()?;
|
||||
let root = exe
|
||||
|
||||
@@ -1,2 +1,8 @@
|
||||
//! Transitional compatibility wrappers preserved during the migration.
|
||||
//!
|
||||
//! Items in this module exist so the codebase can keep working while older
|
||||
//! parsing paths and adapter surfaces are being retired or replaced. New logic
|
||||
//! should prefer the service layer and the dedicated crate boundaries instead.
|
||||
|
||||
pub mod arpparse;
|
||||
pub mod dhcpparse;
|
||||
|
||||
+66
-2
@@ -2,7 +2,8 @@ mod cli_table;
|
||||
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
use clap::{ArgAction, Args, Parser, Subcommand};
|
||||
use tracing::{debug, info};
|
||||
use wakey_core::{DeviceFilters, DeviceQuery, InterfaceSummary, WakeResult};
|
||||
|
||||
#[derive(Parser)]
|
||||
@@ -12,6 +13,10 @@ use wakey_core::{DeviceFilters, DeviceQuery, InterfaceSummary, WakeResult};
|
||||
long_about = "Wakey can run as a local/operator CLI or serve the legacy HTTP/static interface during the migration to a service-first architecture."
|
||||
)]
|
||||
struct Cli {
|
||||
/// Increase log verbosity. Use `-v` for debug and `-vv` for trace.
|
||||
#[arg(short = 'v', long = "verbose", action = ArgAction::Count, global = true)]
|
||||
verbose: u8,
|
||||
|
||||
#[command(subcommand)]
|
||||
command: Command,
|
||||
}
|
||||
@@ -200,14 +205,17 @@ fn main() -> anyhow::Result<()> {
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let cli = Cli::parse();
|
||||
init_tracing(cli.verbose);
|
||||
match cli.command {
|
||||
Command::Http(args) => {
|
||||
let addr = SocketAddr::new(args.host, args.port);
|
||||
info!(%addr, "dispatching http command");
|
||||
wakey::serve_http_from_current_exe(addr).await?;
|
||||
}
|
||||
Command::Status(args) => {
|
||||
let as_json = args.json;
|
||||
let query = status_args_to_query(args);
|
||||
debug!(?query, json = as_json, "dispatching status command");
|
||||
let status = if query.name.is_some()
|
||||
&& query.filter.ips.is_empty()
|
||||
&& query.filter.devs.is_empty()
|
||||
@@ -228,6 +236,11 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
}
|
||||
Command::Leases(args) => {
|
||||
debug!(
|
||||
include_state = args.include_state,
|
||||
json = args.json,
|
||||
"dispatching leases command"
|
||||
);
|
||||
let leases = wakey::get_leases(wakey_core::LeaseQuery {
|
||||
include_state: args.include_state,
|
||||
})
|
||||
@@ -240,6 +253,13 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
Command::Wake(args) => {
|
||||
let as_json = args.json;
|
||||
debug!(
|
||||
has_query = args.query.is_some(),
|
||||
has_mac = args.mac.is_some(),
|
||||
has_ip = args.ip.is_some(),
|
||||
json = as_json,
|
||||
"dispatching wake command"
|
||||
);
|
||||
let result = run_wake(args).await?;
|
||||
if as_json {
|
||||
println!("{}", serde_json::to_string_pretty(&result)?);
|
||||
@@ -248,6 +268,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
}
|
||||
Command::Devs(args) => {
|
||||
debug!(dev = ?args.dev, up = args.up, json = args.json, "dispatching devs command");
|
||||
let devs = if let Some(name) = &args.dev {
|
||||
wakey::get_interface_summary(name)
|
||||
.await?
|
||||
@@ -267,9 +288,32 @@ async fn main() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn init_tracing(verbose: u8) {
|
||||
use tracing_subscriber::{EnvFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
let filter = EnvFilter::try_from_default_env()
|
||||
.or_else(|_| EnvFilter::try_new(default_filter_for_verbosity(verbose)))
|
||||
.expect("static tracing filter should parse");
|
||||
|
||||
tracing_subscriber::registry()
|
||||
.with(filter)
|
||||
.with(fmt::layer())
|
||||
.init();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn default_filter_for_verbosity(verbose: u8) -> &'static str {
|
||||
match verbose {
|
||||
0 => "wakey=info,tower_http=info",
|
||||
1 => "wakey=debug,tower_http=debug",
|
||||
_ => "wakey=trace,tower_http=trace",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::WakeArgs;
|
||||
use super::{WakeArgs, default_filter_for_verbosity};
|
||||
|
||||
#[test]
|
||||
fn wake_rejects_ip_without_mac() {
|
||||
@@ -318,4 +362,24 @@ mod tests {
|
||||
})
|
||||
.expect("manual mac mode should be accepted");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verbosity_maps_to_expected_default_filters() {
|
||||
assert_eq!(
|
||||
default_filter_for_verbosity(0),
|
||||
"wakey=info,tower_http=info"
|
||||
);
|
||||
assert_eq!(
|
||||
default_filter_for_verbosity(1),
|
||||
"wakey=debug,tower_http=debug"
|
||||
);
|
||||
assert_eq!(
|
||||
default_filter_for_verbosity(2),
|
||||
"wakey=trace,tower_http=trace"
|
||||
);
|
||||
assert_eq!(
|
||||
default_filter_for_verbosity(9),
|
||||
"wakey=trace,tower_http=trace"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -122,7 +122,10 @@ mod tests {
|
||||
let err = broadcast_wake_targets_from_interfaces(&interfaces, mac)
|
||||
.expect_err("should error without broadcast-capable interfaces");
|
||||
|
||||
assert!(err.to_string().contains("no broadcast-capable interfaces found"));
|
||||
assert!(
|
||||
err.to_string()
|
||||
.contains("no broadcast-capable interfaces found")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -72,7 +72,9 @@ async fn broadcast_wake_targets_real_router_resolve_from_interfaces() -> anyhow:
|
||||
"all broadcast targets should preserve the requested MAC"
|
||||
);
|
||||
assert!(
|
||||
targets.iter().all(|target| matches!(target.ip, Some(IpAddr::V4(_)))),
|
||||
targets
|
||||
.iter()
|
||||
.all(|target| matches!(target.ip, Some(IpAddr::V4(_)))),
|
||||
"broadcast targets should be IPv4 broadcast destinations"
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user