From 4093178fc3cfbb136fd7fc83593036bec3ea9103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=9E=97=E5=86=9B?= Date: Wed, 27 May 2026 11:39:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0tracing=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E5=B9=B6=E9=87=8D=E6=9E=84=E6=9C=8D=E5=8A=A1=E5=99=A8=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 1 + Cargo.lock | 34 ++++++++++++++++++++++++++++++ Cargo.toml | 6 ++++++ src/components/admin_layout.rs | 14 ++++++------- src/components/footer.rs | 2 +- src/components/mod.rs | 1 - src/main.rs | 32 ++++++++++++++++++++++------ src/pages/admin/dashboard.rs | 2 +- src/pages/admin/mod.rs | 4 ++-- src/pages/admin/write.rs | 4 ++-- src/pages/archives.rs | 12 +++++------ src/pages/home.rs | 12 +++++------ src/pages/login.rs | 2 +- src/pages/register.rs | 2 +- src/pages/tags.rs | 24 ++++++++++----------- src/router.rs | 38 +++++++++++++++++----------------- 16 files changed, 124 insertions(+), 66 deletions(-) diff --git a/.env.example b/.env.example index 536f755..d283bad 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,2 @@ DATABASE_URL=postgres://postgres:postgres@localhost:5432/yggdrasil +RUST_LOG=info diff --git a/Cargo.lock b/Cargo.lock index 7e4ba90..bd2f603 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2436,6 +2436,15 @@ dependencies = [ "jni-sys 0.3.1", ] +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.60.2", +] + [[package]] name = "num-conv" version = "0.2.2" @@ -3724,6 +3733,7 @@ dependencies = [ "tower", "tower-layer", "tower-service", + "tracing", "url", ] @@ -3769,6 +3779,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", + "valuable", ] [[package]] @@ -3781,6 +3792,17 @@ dependencies = [ "tracing", ] +[[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-subscriber" version = "0.3.23" @@ -3788,12 +3810,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "matchers", + "nu-ansi-term", "once_cell", "regex-automata", "sharded-slab", + "smallvec", "thread_local", "tracing", "tracing-core", + "tracing-log", ] [[package]] @@ -3961,6 +3986,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "version_check" version = "0.9.5" @@ -4637,6 +4668,9 @@ dependencies = [ "serde", "tokio", "tokio-postgres", + "tower-http", + "tracing", + "tracing-subscriber", "uuid", "wasm-bindgen", "wasm-bindgen-futures", diff --git a/Cargo.toml b/Cargo.toml index f60a34d..ecf47de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,9 @@ chrono = { version = "0.4", features = ["serde"] } regex = "1.12" pulldown-cmark = "0.13" dotenvy = { version = "0.15", optional = true } +tracing = { version = "0.1", optional = true } +tracing-subscriber = { version = "0.3", optional = true } +tower-http = { version = "0.6", features = ["trace"], optional = true } rand = { version = "0.8", features = ["getrandom"] } getrandom = { version = "0.2", features = ["js"] } http = "1" @@ -42,4 +45,7 @@ server = [ "dep:tokio-postgres", "dep:deadpool-postgres", "dep:dotenvy", + "dep:tracing", + "dep:tracing-subscriber", + "dep:tower-http", ] diff --git a/src/components/admin_layout.rs b/src/components/admin_layout.rs index f8066b0..5b1e705 100644 --- a/src/components/admin_layout.rs +++ b/src/components/admin_layout.rs @@ -1,9 +1,9 @@ use dioxus::prelude::*; use crate::api::auth::{get_current_user, logout}; -use crate::components::header::{Header, NavItemConfig}; +use crate::components::admin_skeleton::AdminDashboardSkeleton; use crate::components::footer::Footer; -use crate::components::admin_skeleton::{AdminSkeleton, AdminDashboardSkeleton}; +use crate::components::header::{Header, NavItemConfig}; use crate::components::write_skeleton::WriteSkeleton; use crate::context::UserContext; use crate::router::Route; @@ -39,12 +39,12 @@ pub fn AdminLayout() -> Element { NavItemConfig { href: "/admin", label: "仪表盘", - is_active: matches!(route, Route::AdminPage {}), + is_active: matches!(route, Route::Admin {}), }, NavItemConfig { href: "/admin/write", label: "写文章", - is_active: matches!(route, Route::WritePage {}), + is_active: matches!(route, Route::Write {}), }, NavItemConfig { href: "/", @@ -53,15 +53,13 @@ pub fn AdminLayout() -> Element { }, ]; - let nav = navigator.clone(); let logout_button = rsx! { button { class: "text-sm text-gray-600 dark:text-[#9b9c9d] hover:text-gray-900 dark:hover:text-[#dadadb] transition-colors", onclick: move |_| { - let nav = nav.clone(); spawn(async move { let _ = logout().await; - let _ = nav.push("/login"); + let _ = navigator.push("/login"); }); }, "登出" @@ -94,7 +92,7 @@ pub fn AdminLayout() -> Element { Header { nav_items: admin_nav_items, right_content: logout_button } main { class: "flex-1 w-full max-w-5xl mx-auto px-6 py-8", {match route { - Route::WritePage {} => rsx! { WriteSkeleton {} }, + Route::Write {} => rsx! { WriteSkeleton {} }, _ => rsx! { AdminDashboardSkeleton {} }, }} } diff --git a/src/components/footer.rs b/src/components/footer.rs index 9c5f712..061a16e 100644 --- a/src/components/footer.rs +++ b/src/components/footer.rs @@ -2,7 +2,7 @@ use dioxus::prelude::*; #[component] pub fn Footer() -> Element { - let mut visible = use_signal(|| false); + let visible = use_signal(|| false); use_effect(move || { #[cfg(target_arch = "wasm32")] diff --git a/src/components/mod.rs b/src/components/mod.rs index 43d6b6a..638aff9 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -2,5 +2,4 @@ pub mod header; pub mod footer; pub mod admin_layout; pub mod admin_skeleton; -pub use admin_skeleton::{AdminSkeleton, AdminDashboardSkeleton}; pub mod write_skeleton; diff --git a/src/main.rs b/src/main.rs index 1a156ec..90aafa6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,17 +9,37 @@ mod router; mod tasks; mod theme; -use router::AppRouter; - fn main() { #[cfg(feature = "server")] { dotenvy::dotenv().ok(); - std::thread::spawn(|| { - let rt = tokio::runtime::Runtime::new().expect("Failed to create Tokio runtime"); - rt.block_on(tasks::session_cleanup::run_cleanup()); + tracing_subscriber::fmt() + .with_env_filter( + tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")), + ) + .init(); + + dioxus::server::serve(|| async move { + use dioxus::server::{axum, DioxusRouterExt, ServeConfig}; + use tower_http::trace::TraceLayer; + + tokio::spawn(async { + tasks::session_cleanup::run_cleanup().await; + }); + + let config = ServeConfig::new(); + let router = axum::Router::new() + .layer(TraceLayer::new_for_http()) + .serve_dioxus_application(config, router::AppRouter); + + Ok(router) }); } - dioxus::launch(AppRouter); + #[cfg(not(feature = "server"))] + { + use router::AppRouter; + dioxus::launch(AppRouter); + } } diff --git a/src/pages/admin/dashboard.rs b/src/pages/admin/dashboard.rs index 51640f7..7f6d43d 100644 --- a/src/pages/admin/dashboard.rs +++ b/src/pages/admin/dashboard.rs @@ -3,7 +3,7 @@ use dioxus::prelude::*; use crate::pages::home::{Post, POSTS}; #[component] -pub fn AdminPage() -> Element { +pub fn Admin() -> Element { rsx! { div { class: "space-y-8", // 统计卡片 diff --git a/src/pages/admin/mod.rs b/src/pages/admin/mod.rs index 7971da7..a907d2d 100644 --- a/src/pages/admin/mod.rs +++ b/src/pages/admin/mod.rs @@ -1,5 +1,5 @@ pub mod dashboard; pub mod write; -pub use dashboard::AdminPage; -pub use write::WritePage; +pub use dashboard::Admin; +pub use write::Write; diff --git a/src/pages/admin/write.rs b/src/pages/admin/write.rs index 6bd597b..a4a4b72 100644 --- a/src/pages/admin/write.rs +++ b/src/pages/admin/write.rs @@ -6,9 +6,9 @@ use wasm_bindgen::JsCast; use crate::components::write_skeleton::WriteSkeleton; #[component] -pub fn WritePage() -> Element { +pub fn Write() -> Element { let mut title = use_signal(|| "".to_string()); - let mut content = use_signal(|| "".to_string()); + let content = use_signal(|| "".to_string()); let mut loading = use_signal(|| true); // 初始化 Tiptap 编辑器 diff --git a/src/pages/archives.rs b/src/pages/archives.rs index 82ea2db..1d55f62 100644 --- a/src/pages/archives.rs +++ b/src/pages/archives.rs @@ -114,14 +114,14 @@ fn group_posts(posts: &[Post]) -> Vec { } #[component] -pub fn ArchivesPage() -> Element { +pub fn Archives() -> Element { let route = use_route::(); let nav_items = vec![ - NavItemConfig { href: "/", label: "首页", is_active: matches!(route, Route::HomePage {}) }, - NavItemConfig { href: "/archives", label: "归档", is_active: matches!(route, Route::ArchivesPage {}) }, - NavItemConfig { href: "/tags", label: "标签", is_active: matches!(route, Route::TagsPage {}) || matches!(route, Route::TagDetailPage { .. }) }, - NavItemConfig { href: "/search", label: "搜索", is_active: matches!(route, Route::SearchPage {}) }, - NavItemConfig { href: "/about", label: "关于", is_active: matches!(route, Route::AboutPage {}) }, + NavItemConfig { href: "/", label: "首页", is_active: matches!(route, Route::Home {}) }, + NavItemConfig { href: "/archives", label: "归档", is_active: matches!(route, Route::Archives {}) }, + NavItemConfig { href: "/tags", label: "标签", is_active: matches!(route, Route::Tags {}) || matches!(route, Route::TagDetail { .. }) }, + NavItemConfig { href: "/search", label: "搜索", is_active: matches!(route, Route::Search {}) }, + NavItemConfig { href: "/about", label: "关于", is_active: matches!(route, Route::About {}) }, ]; let grouped = group_posts(POSTS); diff --git a/src/pages/home.rs b/src/pages/home.rs index 5148c71..e3bc281 100644 --- a/src/pages/home.rs +++ b/src/pages/home.rs @@ -60,14 +60,14 @@ pub const POSTS: &[Post] = &[ ]; #[component] -pub fn HomePage() -> Element { +pub fn Home() -> Element { let route = use_route::(); let nav_items = vec![ - NavItemConfig { href: "/", label: "首页", is_active: matches!(route, Route::HomePage {}) }, - NavItemConfig { href: "/archives", label: "归档", is_active: matches!(route, Route::ArchivesPage {}) }, - NavItemConfig { href: "/tags", label: "标签", is_active: matches!(route, Route::TagsPage {}) || matches!(route, Route::TagDetailPage { .. }) }, - NavItemConfig { href: "/search", label: "搜索", is_active: matches!(route, Route::SearchPage {}) }, - NavItemConfig { href: "/about", label: "关于", is_active: matches!(route, Route::AboutPage {}) }, + NavItemConfig { href: "/", label: "首页", is_active: matches!(route, Route::Home {}) }, + NavItemConfig { href: "/archives", label: "归档", is_active: matches!(route, Route::Archives {}) }, + NavItemConfig { href: "/tags", label: "标签", is_active: matches!(route, Route::Tags {}) || matches!(route, Route::TagDetail { .. }) }, + NavItemConfig { href: "/search", label: "搜索", is_active: matches!(route, Route::Search {}) }, + NavItemConfig { href: "/about", label: "关于", is_active: matches!(route, Route::About {}) }, ]; rsx! { diff --git a/src/pages/login.rs b/src/pages/login.rs index 9d3a89d..e7526b8 100644 --- a/src/pages/login.rs +++ b/src/pages/login.rs @@ -3,7 +3,7 @@ use dioxus::prelude::*; use crate::api::auth::{login, AuthResponse}; #[component] -pub fn LoginPage() -> Element { +pub fn Login() -> Element { let mut username = use_signal(|| "".to_string()); let mut password = use_signal(|| "".to_string()); let mut error = use_signal(|| None::); diff --git a/src/pages/register.rs b/src/pages/register.rs index b77d66a..70d9b37 100644 --- a/src/pages/register.rs +++ b/src/pages/register.rs @@ -3,7 +3,7 @@ use dioxus::prelude::*; use crate::api::auth::{register, AuthResponse}; #[component] -pub fn RegisterPage() -> Element { +pub fn Register() -> Element { let mut username = use_signal(|| "".to_string()); let mut email = use_signal(|| "".to_string()); let mut password = use_signal(|| "".to_string()); diff --git a/src/pages/tags.rs b/src/pages/tags.rs index f47f356..fc63aec 100644 --- a/src/pages/tags.rs +++ b/src/pages/tags.rs @@ -40,14 +40,14 @@ fn posts_for_tag(tag: &str) -> Vec { } #[component] -pub fn TagsPage() -> Element { +pub fn Tags() -> Element { let route = use_route::(); let nav_items = vec![ - NavItemConfig { href: "/", label: "首页", is_active: matches!(route, Route::HomePage {}) }, - NavItemConfig { href: "/archives", label: "归档", is_active: matches!(route, Route::ArchivesPage {}) }, - NavItemConfig { href: "/tags", label: "标签", is_active: matches!(route, Route::TagsPage {}) || matches!(route, Route::TagDetailPage { .. }) }, - NavItemConfig { href: "/search", label: "搜索", is_active: matches!(route, Route::SearchPage {}) }, - NavItemConfig { href: "/about", label: "关于", is_active: matches!(route, Route::AboutPage {}) }, + NavItemConfig { href: "/", label: "首页", is_active: matches!(route, Route::Home {}) }, + NavItemConfig { href: "/archives", label: "归档", is_active: matches!(route, Route::Archives {}) }, + NavItemConfig { href: "/tags", label: "标签", is_active: matches!(route, Route::Tags {}) || matches!(route, Route::TagDetail { .. }) }, + NavItemConfig { href: "/search", label: "搜索", is_active: matches!(route, Route::Search {}) }, + NavItemConfig { href: "/about", label: "关于", is_active: matches!(route, Route::About {}) }, ]; let tags = collect_tags(); @@ -92,14 +92,14 @@ pub fn TagsPage() -> Element { } #[component] -pub fn TagDetailPage(tag: String) -> Element { +pub fn TagDetail(tag: String) -> Element { let route = use_route::(); let nav_items = vec![ - NavItemConfig { href: "/", label: "首页", is_active: matches!(route, Route::HomePage {}) }, - NavItemConfig { href: "/archives", label: "归档", is_active: matches!(route, Route::ArchivesPage {}) }, - NavItemConfig { href: "/tags", label: "标签", is_active: matches!(route, Route::TagsPage {}) || matches!(route, Route::TagDetailPage { .. }) }, - NavItemConfig { href: "/search", label: "搜索", is_active: matches!(route, Route::SearchPage {}) }, - NavItemConfig { href: "/about", label: "关于", is_active: matches!(route, Route::AboutPage {}) }, + NavItemConfig { href: "/", label: "首页", is_active: matches!(route, Route::Home {}) }, + NavItemConfig { href: "/archives", label: "归档", is_active: matches!(route, Route::Archives {}) }, + NavItemConfig { href: "/tags", label: "标签", is_active: matches!(route, Route::Tags {}) || matches!(route, Route::TagDetail { .. }) }, + NavItemConfig { href: "/search", label: "搜索", is_active: matches!(route, Route::Search {}) }, + NavItemConfig { href: "/about", label: "关于", is_active: matches!(route, Route::About {}) }, ]; let posts = posts_for_tag(&tag); diff --git a/src/router.rs b/src/router.rs index 4259077..adddd91 100644 --- a/src/router.rs +++ b/src/router.rs @@ -3,43 +3,43 @@ use std::sync::Arc; use crate::components::admin_layout::AdminLayout; use crate::context::UserContext; -use crate::pages::admin::{AdminPage, WritePage}; -use crate::pages::archives::ArchivesPage; -use crate::pages::home::HomePage; -use crate::pages::login::LoginPage; -use crate::pages::register::RegisterPage; -use crate::pages::tags::{TagsPage, TagDetailPage}; -use crate::theme::{Theme, ThemePreload, use_theme_provider}; +use crate::pages::admin::{Admin, Write}; +use crate::pages::archives::Archives; +use crate::pages::home::Home; +use crate::pages::login::Login; +use crate::pages::register::Register; +use crate::pages::tags::{TagDetail, Tags}; +use crate::theme::{use_theme_provider, Theme, ThemePreload}; #[derive(Clone, Routable, Debug, PartialEq)] #[rustfmt::skip] pub enum Route { #[route("/")] - HomePage {}, + Home {}, #[route("/login")] - LoginPage {}, + Login {}, #[route("/register")] - RegisterPage {}, + Register {}, #[nest("/admin")] #[layout(AdminLayout)] #[route("/")] - AdminPage {}, + Admin {}, #[route("/write")] - WritePage {}, + Write {}, #[end_layout] #[end_nest] #[route("/archives")] - ArchivesPage {}, + Archives {}, #[route("/tags")] - TagsPage {}, + Tags {}, #[route("/tags/:tag")] - TagDetailPage { tag: String }, + TagDetail { tag: String }, #[route("/search")] - SearchPage {}, + Search {}, #[route("/about")] - AboutPage {}, + About {}, } #[component] @@ -64,11 +64,11 @@ pub fn AppRouter() -> Element { } #[component] -pub fn SearchPage() -> Element { +pub fn Search() -> Element { rsx! { "Search" } } #[component] -pub fn AboutPage() -> Element { +pub fn About() -> Element { rsx! { "About" } }