···75#[component]
76pub fn AppLink(props: AppLinkProps) -> Element {
77 let link_mode = use_context::<LinkMode>();
78- tracing::info!(?link_mode, "AppLink: reading LinkMode context");
79 let class = props.class.clone().unwrap_or_default();
8081 match link_mode {
···75#[component]
76pub fn AppLink(props: AppLinkProps) -> Element {
77 let link_mode = use_context::<LinkMode>();
078 let class = props.class.clone().unwrap_or_default();
7980 match link_mode {
+85-50
crates/weaver-app/src/main.rs
···45 // Filter out noisy crates
46 // Use weaver_app=trace for detailed editor debugging
47 let filter = EnvFilter::new(
48- "debug,weaver_app=trace,loro_internal=warn,jacquard_identity=info,jacquard_common=info,iroh=info",
49 );
5051 let reg = Registry::default()
···56 let _ = set_global_default(reg);
57 }
58000000000059 #[cfg(feature = "server")]
60 std::panic::set_hook(Box::new(|panic_info| {
61 tracing::error!("PANIC: {:?}", panic_info);
···6364 // Run `serve()` on the server only
65 #[cfg(feature = "server")]
66- dioxus::serve(|| async move {
67- #[cfg(feature = "fullstack-server")]
68- use axum::middleware;
69- use axum::middleware::Next;
70- use axum::{Router, body::Body, extract::Request, response::Response, routing::get};
71- use axum_extra::extract::Host;
72- use jacquard::oauth::{client::OAuthClient, session::ClientData};
73- use std::convert::Infallible;
74- use weaver_app::auth::AuthStore;
75- use weaver_app::blobcache::BlobCache;
00000007677- #[cfg(not(feature = "fullstack-server"))]
78- let router = { Router::new().merge(dioxus::server::router(App)) };
007980- #[cfg(feature = "fullstack-server")]
81- let router = {
82- let fetcher = Arc::new(fetch::Fetcher::new(OAuthClient::new(
83- AuthStore::new(),
84- ClientData::new_public(CONFIG.oauth.clone()),
85- )));
08687- let blob_cache = Arc::new(BlobCache::new(fetcher.clone()));
88- axum::Router::new()
89- .route("/favicon.ico", get(weaver_app::favicon))
90- .serve_dioxus_application(ServeConfig::builder(), App)
91- // Host context resolution.
92- .layer(middleware::from_fn({
93- let fetcher = fetcher.clone();
94- move |req: Request, next: Next| {
95- let fetcher = fetcher.clone();
96- async move {
97- weaver_app::middleware::host_context_middleware(req, next, fetcher)
98- .await
99- }
100- }
101- }))
102- // Insert fetcher and blob cache into extensions.
103- .layer(middleware::from_fn({
104- let blob_cache = blob_cache.clone();
105- let fetcher = fetcher.clone();
106- move |mut req: Request, next: Next| {
107- let blob_cache = blob_cache.clone();
108- let fetcher = fetcher.clone();
109- async move {
110- req.extensions_mut().insert(blob_cache);
111- req.extensions_mut().insert(fetcher);
112- Ok::<_, Infallible>(next.run(req).await)
113- }
114- }
115- }))
116- };
117- Ok(router)
000000000000000118 });
119120 #[cfg(not(feature = "server"))]
···45 // Filter out noisy crates
46 // Use weaver_app=trace for detailed editor debugging
47 let filter = EnvFilter::new(
48+ "debug,weaver_app=trace,loro_internal=warn,jacquard_identity=info,jacquard_common=info,iroh=info,reqwest=warn",
49 );
5051 let reg = Registry::default()
···56 let _ = set_global_default(reg);
57 }
5859+ // Initialize telemetry (metrics + tracing) before server starts.
60+ // Loki task is spawned inside dioxus::serve where tokio runtime exists.
61+ // Wrapped in Arc<Mutex> so the FnMut closure can clone and take() on first call.
62+ #[cfg(feature = "server")]
63+ let loki_task = {
64+ use weaver_common::telemetry::{self, TelemetryConfig};
65+ let config = TelemetryConfig::from_env("weaver-app");
66+ std::sync::Arc::new(std::sync::Mutex::new(telemetry::init_sync(config)))
67+ };
68+69 #[cfg(feature = "server")]
70 std::panic::set_hook(Box::new(|panic_info| {
71 tracing::error!("PANIC: {:?}", panic_info);
···7374 // Run `serve()` on the server only
75 #[cfg(feature = "server")]
76+ dioxus::serve({
77+ let loki_task = loki_task.clone();
78+ move || {
79+ let loki_task = loki_task.clone();
80+ async move {
81+ #[cfg(feature = "fullstack-server")]
82+ use axum::middleware;
83+ use axum::middleware::Next;
84+ use axum::{
85+ Router, body::Body, extract::Request, response::Response, routing::get,
86+ };
87+ use axum_extra::extract::Host;
88+ use jacquard::oauth::{client::OAuthClient, session::ClientData};
89+ use std::convert::Infallible;
90+ use weaver_app::auth::AuthStore;
91+ use weaver_app::blobcache::BlobCache;
92+ use weaver_common::telemetry;
9394+ // Spawn the Loki background task now that we're in tokio runtime
95+ if let Some(task) = loki_task.lock().unwrap().take() {
96+ telemetry::spawn_loki_task(task);
97+ }
9899+ #[cfg(not(feature = "fullstack-server"))]
100+ let router = {
101+ Router::new()
102+ .merge(dioxus::server::router(App))
103+ .layer(middleware::from_fn(telemetry::http_metrics))
104+ .layer(tower_http::trace::TraceLayer::new_for_http())
105+ };
106107+ #[cfg(feature = "fullstack-server")]
108+ let router = {
109+ let fetcher = Arc::new(fetch::Fetcher::new(OAuthClient::new(
110+ AuthStore::new(),
111+ ClientData::new_public(CONFIG.oauth.clone()),
112+ )));
113+114+ let blob_cache = Arc::new(BlobCache::new(fetcher.clone()));
115+ axum::Router::new()
116+ .route("/favicon.ico", get(weaver_app::favicon))
117+ .route("/metrics", get(|| async { telemetry::render() }))
118+ .serve_dioxus_application(ServeConfig::builder(), App)
119+ // Host context resolution.
120+ .layer(middleware::from_fn({
121+ let fetcher = fetcher.clone();
122+ move |req: Request, next: Next| {
123+ let fetcher = fetcher.clone();
124+ async move {
125+ weaver_app::middleware::host_context_middleware(
126+ req, next, fetcher,
127+ )
128+ .await
129+ }
130+ }
131+ }))
132+ // Insert fetcher and blob cache into extensions.
133+ .layer(middleware::from_fn({
134+ let blob_cache = blob_cache.clone();
135+ let fetcher = fetcher.clone();
136+ move |mut req: Request, next: Next| {
137+ let blob_cache = blob_cache.clone();
138+ let fetcher = fetcher.clone();
139+ async move {
140+ req.extensions_mut().insert(blob_cache);
141+ req.extensions_mut().insert(fetcher);
142+ Ok::<_, Infallible>(next.run(req).await)
143+ }
144+ }
145+ }))
146+ // HTTP metrics (request count, duration)
147+ .layer(middleware::from_fn(telemetry::http_metrics))
148+ .layer(tower_http::trace::TraceLayer::new_for_http())
149+ };
150+ Ok(router)
151+ }
152+ }
153 });
154155 #[cfg(not(feature = "server"))]