添加tracing日志并重构服务器启动逻辑

This commit is contained in:
李林军 2026-05-27 11:39:09 +08:00
parent 9c834ba1df
commit 4093178fc3
16 changed files with 124 additions and 66 deletions

View File

@ -1 +1,2 @@
DATABASE_URL=postgres://postgres:postgres@localhost:5432/yggdrasil
RUST_LOG=info

34
Cargo.lock generated
View File

@ -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",

View File

@ -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",
]

View File

@ -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 {} },
}}
}

View File

@ -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")]

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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",
// 统计卡片

View File

@ -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;

View File

@ -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 编辑器

View File

@ -114,14 +114,14 @@ fn group_posts(posts: &[Post]) -> Vec<YearGroup> {
}
#[component]
pub fn ArchivesPage() -> Element {
pub fn Archives() -> Element {
let route = use_route::<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);

View File

@ -60,14 +60,14 @@ pub const POSTS: &[Post] = &[
];
#[component]
pub fn HomePage() -> Element {
pub fn Home() -> Element {
let route = use_route::<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! {

View File

@ -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::<String>);

View File

@ -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());

View File

@ -40,14 +40,14 @@ fn posts_for_tag(tag: &str) -> Vec<Post> {
}
#[component]
pub fn TagsPage() -> Element {
pub fn Tags() -> Element {
let route = use_route::<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::<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);

View File

@ -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" }
}