telemetry & metrics stuff
This commit is contained in:
parent
50b84a0025
commit
5dd01a5d4c
8 changed files with 314 additions and 71 deletions
218
Cargo.lock
generated
218
Cargo.lock
generated
|
@ -74,7 +74,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.11",
|
||||
"syn 2.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -375,6 +375,25 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
|
@ -409,7 +428,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn 2.0.11",
|
||||
"syn 2.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -426,7 +445,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.11",
|
||||
"syn 2.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -464,6 +483,19 @@ dependencies = [
|
|||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "5.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"hashbrown 0.12.3",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deunicode"
|
||||
version = "0.4.3"
|
||||
|
@ -538,9 +570,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.27"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549"
|
||||
checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
|
@ -552,9 +584,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.27"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac"
|
||||
checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
|
@ -562,35 +594,58 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.27"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd"
|
||||
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.27"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91"
|
||||
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.27"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2"
|
||||
checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.27"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879"
|
||||
checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.27"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab"
|
||||
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
|
@ -968,6 +1023,15 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||
dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
version = "0.7.0"
|
||||
|
@ -1071,6 +1135,52 @@ version = "1.17.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69d6c3d7288a106c0a363e4b0e8d308058d56902adefb16f4936f417ffef086e"
|
||||
dependencies = [
|
||||
"opentelemetry_api",
|
||||
"opentelemetry_sdk",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry_api"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c24f96e21e7acc813c7a8394ee94978929db2bcc46cf6b5014fc612bf7760c22"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"indexmap",
|
||||
"js-sys",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry_sdk"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ca41c4933371b61c2a2f214bf16931499af4ec90543604ec828f7a625c09113"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"crossbeam-channel",
|
||||
"dashmap",
|
||||
"fnv",
|
||||
"futures-channel",
|
||||
"futures-executor",
|
||||
"futures-util",
|
||||
"once_cell",
|
||||
"opentelemetry_api",
|
||||
"percent-encoding",
|
||||
"rand",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
|
@ -1123,9 +1233,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
|||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.5.6"
|
||||
version = "2.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cbd939b234e95d72bc393d51788aec68aeeb5d51e748ca08ff3aad58cb722f7"
|
||||
checksum = "7b1403e8401ad5dedea73c626b99758535b342502f8d1e361f4a2dd952749122"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
"ucd-trie",
|
||||
|
@ -1133,9 +1243,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pest_derive"
|
||||
version = "2.5.6"
|
||||
version = "2.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a81186863f3d0a27340815be8f2078dd8050b14cd71913db9fbda795e5f707d7"
|
||||
checksum = "be99c4c1d2fc2769b1d00239431d711d08f6efedcecb8b6e30707160aee99c15"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_generator",
|
||||
|
@ -1143,22 +1253,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.5.6"
|
||||
version = "2.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75a1ef20bf3193c15ac345acb32e26b3dc3223aff4d77ae4fc5359567683796b"
|
||||
checksum = "e56094789873daa36164de2e822b3888c6ae4b4f9da555a1103587658c805b1e"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.5.6"
|
||||
version = "2.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e3b284b1f13a20dc5ebc90aff59a51b8d7137c221131b52a7260c08cbc1cc80"
|
||||
checksum = "6733073c7cff3d8459fda0e42f13a047870242aed8b509fe98000928975f359e"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"pest",
|
||||
|
@ -1250,9 +1360,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.54"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534"
|
||||
checksum = "1d0dd4be24fcdcfeaa12a432d588dc59bbad6cad3510c67e74a2b6b2fc950564"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
@ -1364,6 +1474,15 @@ dependencies = [
|
|||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||
dependencies = [
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.29"
|
||||
|
@ -1440,7 +1559,7 @@ checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.11",
|
||||
"syn 2.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1572,9 +1691,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.11"
|
||||
version = "2.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21e3787bb71465627110e7d87ed4faaa36c1f61042ee67badb9e2ef173accc40"
|
||||
checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1636,7 +1755,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.11",
|
||||
"syn 2.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1686,7 +1805,7 @@ checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.11",
|
||||
"syn 2.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1855,18 +1974,49 @@ dependencies = [
|
|||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-opentelemetry"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21ebb87a95ea13271332df069020513ab70bdb5637ca42d6e492dc3bbbad48de"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"opentelemetry",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-serde"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
|
||||
dependencies = [
|
||||
"matchers",
|
||||
"nu-ansi-term",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
"tracing-serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2085,6 +2235,7 @@ dependencies = [
|
|||
"glob",
|
||||
"hyper",
|
||||
"lazy_static",
|
||||
"opentelemetry",
|
||||
"prometheus",
|
||||
"pulldown-cmark",
|
||||
"regex",
|
||||
|
@ -2097,6 +2248,7 @@ dependencies = [
|
|||
"tower",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
"tracing-opentelemetry",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ color-eyre = "0.6.1"
|
|||
glob = "0.3.0"
|
||||
hyper = { version = "0.14.19", features = ["full"] }
|
||||
lazy_static = "1.4.0"
|
||||
opentelemetry = { version = "0.18.0", features = ["metrics"] }
|
||||
prometheus = { version = "0.13.3", features = ["process"] }
|
||||
pulldown-cmark = "0.9.2"
|
||||
regex = "1.7.2"
|
||||
|
@ -25,4 +26,5 @@ toml = "0.7.3"
|
|||
tower = { version = "0.4.12", features = ["full"] }
|
||||
tower-http = { version = "0.4.0", features = ["full"] }
|
||||
tracing = "0.1.35"
|
||||
tracing-subscriber = { version = "0.3.11", features = ["fmt"] }
|
||||
tracing-opentelemetry = "0.18.0"
|
||||
tracing-subscriber = { version = "0.3.11", features = ["fmt", "env-filter", "json", "tracing-log"] }
|
||||
|
|
|
@ -2,7 +2,7 @@ use axum::{
|
|||
body,
|
||||
extract::State,
|
||||
middleware::Next,
|
||||
response::{Html, IntoResponse, Response},
|
||||
response::{Html, IntoResponse, Response, Redirect},
|
||||
routing::get,
|
||||
Router,
|
||||
};
|
||||
|
@ -10,7 +10,7 @@ use hyper::{header::CONTENT_TYPE, Request, StatusCode};
|
|||
use lazy_static::lazy_static;
|
||||
use prometheus::{opts, Encoder, IntCounterVec, TextEncoder};
|
||||
use std::sync::Arc;
|
||||
use tracing::{instrument, log::*};
|
||||
use tracing::{info_span, instrument, log::*, Instrument};
|
||||
|
||||
use crate::{AppState, WebsiteError};
|
||||
|
||||
|
@ -31,13 +31,14 @@ lazy_static! {
|
|||
pub fn routes(state: &Arc<AppState>) -> Router<Arc<AppState>> {
|
||||
Router::new()
|
||||
.route("/", get(index))
|
||||
.nest("/posts", posts::router())
|
||||
.nest("/tags", tags::router())
|
||||
.merge(posts::router())
|
||||
.merge(tags::router())
|
||||
.merge(posts::alias_router(state.posts.values()))
|
||||
.layer(axum::middleware::from_fn(metrics_middleware))
|
||||
.route("/healthcheck", get(healthcheck))
|
||||
.route("/metrics", get(metrics))
|
||||
.nest_service("/static", tower_http::services::ServeDir::new("./static"))
|
||||
.layer(axum::middleware::from_fn(metrics_middleware))
|
||||
.route_service("/posts/:slug/*path", tower_http::services::ServeDir::new("./"))
|
||||
.route_service("/static/*path", tower_http::services::ServeDir::new("./"))
|
||||
}
|
||||
|
||||
#[instrument(skip(state))]
|
||||
|
@ -127,8 +128,6 @@ mod tests {
|
|||
posts,
|
||||
});
|
||||
|
||||
super::routes(&state)
|
||||
.with_state(state)
|
||||
.into_make_service();
|
||||
super::routes(&state).with_state(state).into_make_service();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::sync::Arc;
|
|||
|
||||
use axum::{
|
||||
extract::{Path, State},
|
||||
response::{Html, Redirect},
|
||||
response::{Html, Redirect, IntoResponse},
|
||||
routing::get,
|
||||
Router,
|
||||
};
|
||||
|
@ -16,10 +16,11 @@ use crate::{
|
|||
|
||||
pub fn router() -> Router<Arc<AppState>> {
|
||||
Router::new()
|
||||
.route("/", get(index))
|
||||
.route("/:slug/", get(view))
|
||||
.route("/:slug/index.md", get(super::not_found))
|
||||
.fallback_service(tower_http::services::ServeDir::new("./posts"))
|
||||
.route("/posts", get(|| async { Redirect::permanent("/") }))
|
||||
.route("/posts/", get(index))
|
||||
.route("/posts/:slug", get(redirect))
|
||||
.route("/posts/:slug/", get(view))
|
||||
.route("/posts/:slug/index.md", get(super::not_found))
|
||||
}
|
||||
|
||||
pub fn alias_router<'a>(posts: impl IntoIterator<Item = &'a Post>) -> Router<Arc<AppState>> {
|
||||
|
@ -79,6 +80,19 @@ pub async fn view(
|
|||
Ok(Html(res))
|
||||
}
|
||||
|
||||
#[instrument(skip(state))]
|
||||
pub async fn redirect(
|
||||
Path(slug): Path<String>,
|
||||
State(state): State<Arc<AppState>>,
|
||||
) -> Result<Redirect, WebsiteError> {
|
||||
if state.posts.contains_key(&slug) {
|
||||
Ok(Redirect::permanent(&format!("/posts/{slug}/")))
|
||||
}
|
||||
else {
|
||||
Err(WebsiteError::NotFound)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use chrono::DateTime;
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use axum::{Router, response::Html, routing::get, extract::{State, Path}};
|
||||
use axum::{
|
||||
extract::{Path, State},
|
||||
response::{Html, Redirect},
|
||||
routing::get,
|
||||
Router,
|
||||
};
|
||||
use serde_derive::Serialize;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::{AppState, WebsiteError, post::Post};
|
||||
use crate::{post::Post, AppState, WebsiteError};
|
||||
|
||||
pub fn router() -> Router<Arc<AppState>> {
|
||||
Router::new()
|
||||
.route("/", get(index))
|
||||
.route("/:tag/", get(view))
|
||||
.route("/tags", get(|| async { Redirect::permanent("/") }))
|
||||
.route("/tags/", get(index))
|
||||
.route("/tags/:tag", get(redirect))
|
||||
.route("/tags/:tag/", get(view))
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
|
@ -19,7 +26,6 @@ struct PageContext<'a> {
|
|||
|
||||
#[instrument(skip(state))]
|
||||
pub async fn index(State(state): State<Arc<AppState>>) -> Result<Html<String>, WebsiteError> {
|
||||
|
||||
let tags: Vec<_> = state.tags.values().collect();
|
||||
let ctx = PageContext { title: "Tags" };
|
||||
|
||||
|
@ -33,8 +39,15 @@ pub async fn index(State(state): State<Arc<AppState>>) -> Result<Html<String>, W
|
|||
}
|
||||
|
||||
#[instrument(skip(state))]
|
||||
pub async fn view(Path(tag): Path<String>, State(state): State<Arc<AppState>>) -> Result<Html<String>, WebsiteError> {
|
||||
let mut posts: Vec<&Post> = state.posts.values().filter(|p| p.is_published() && p.tags.contains(&tag)).collect();
|
||||
pub async fn view(
|
||||
Path(tag): Path<String>,
|
||||
State(state): State<Arc<AppState>>,
|
||||
) -> Result<Html<String>, WebsiteError> {
|
||||
let mut posts: Vec<&Post> = state
|
||||
.posts
|
||||
.values()
|
||||
.filter(|p| p.is_published() && p.tags.contains(&tag))
|
||||
.collect();
|
||||
|
||||
posts.sort_by_key(|p| &p.date);
|
||||
posts.reverse();
|
||||
|
@ -50,4 +63,17 @@ pub async fn view(Path(tag): Path<String>, State(state): State<Arc<AppState>>) -
|
|||
let res = state.tera.render("tag.html", &c)?;
|
||||
|
||||
Ok(Html(res))
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(state))]
|
||||
pub async fn redirect(
|
||||
Path(slug): Path<String>,
|
||||
State(state): State<Arc<AppState>>,
|
||||
) -> Result<Redirect, WebsiteError> {
|
||||
if state.tags.contains_key(&slug) {
|
||||
Ok(Redirect::permanent(&format!("/tags/{slug}/")))
|
||||
}
|
||||
else {
|
||||
Err(WebsiteError::NotFound)
|
||||
}
|
||||
}
|
||||
|
|
58
src/main.rs
58
src/main.rs
|
@ -1,13 +1,16 @@
|
|||
use std::{collections::HashMap, sync::Arc};
|
||||
use std::{collections::HashMap, sync::Arc, time::Duration};
|
||||
|
||||
use axum::extract::MatchedPath;
|
||||
use color_eyre::eyre::{Error, Result};
|
||||
|
||||
use hyper::{Body, Request, Response};
|
||||
use post::Post;
|
||||
|
||||
use tag::Tag;
|
||||
use tera::Tera;
|
||||
use tower_http::{compression::CompressionLayer, trace::TraceLayer, cors::CorsLayer};
|
||||
use tracing::log::*;
|
||||
use tower_http::{compression::CompressionLayer, cors::CorsLayer};
|
||||
use tracing::{info_span, log::*, Span};
|
||||
use tracing_subscriber::{prelude::*, EnvFilter};
|
||||
|
||||
mod handlers;
|
||||
mod post;
|
||||
|
@ -22,7 +25,8 @@ pub struct AppState {
|
|||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
tracing_subscriber::fmt::init();
|
||||
init_tracing();
|
||||
|
||||
info!("Starting server...");
|
||||
|
||||
let tera = Tera::new("templates/**/*")?;
|
||||
|
@ -32,8 +36,10 @@ async fn main() -> Result<()> {
|
|||
|
||||
let app = handlers::routes(&state)
|
||||
.layer(CorsLayer::permissive())
|
||||
.layer(TraceLayer::new_for_http())
|
||||
.layer(CompressionLayer::new())
|
||||
.layer(tower_http::trace::TraceLayer::new_for_http()
|
||||
.make_span_with(make_span)
|
||||
.on_response(on_response))
|
||||
.with_state(state);
|
||||
|
||||
info!("Now listening at http://localhost:8180");
|
||||
|
@ -45,6 +51,48 @@ async fn main() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn init_tracing() {
|
||||
let filter = EnvFilter::builder()
|
||||
.with_default_directive("into".parse().unwrap())
|
||||
.from_env_lossy()
|
||||
.add_directive("otel=debug".parse().unwrap());
|
||||
|
||||
tracing_subscriber::registry()
|
||||
.with(filter)
|
||||
.with(tracing_subscriber::fmt::layer())
|
||||
.init();
|
||||
}
|
||||
|
||||
fn make_span(request: &Request<Body>) -> Span {
|
||||
let uri = request.uri();
|
||||
let route = request
|
||||
.extensions()
|
||||
.get::<MatchedPath>()
|
||||
.map(|mp| mp.as_str())
|
||||
.unwrap_or_default();
|
||||
let method = request.method().as_str();
|
||||
let target = uri
|
||||
.path_and_query()
|
||||
.map(|p| p.as_str())
|
||||
.unwrap_or_default();
|
||||
|
||||
let name = format!("{method} {route}");
|
||||
|
||||
use tracing::field::Empty;
|
||||
info_span!(
|
||||
"request",
|
||||
otel.name = %name,
|
||||
http.route = %route,
|
||||
http.method = %method,
|
||||
http.target = %target,
|
||||
http.status_code = Empty
|
||||
)
|
||||
}
|
||||
|
||||
fn on_response<B>(response: &Response<B>, _latency: Duration, span: &Span) {
|
||||
span.record("http.status_code", response.status().as_str());
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum WebsiteError {
|
||||
NotFound,
|
||||
|
|
|
@ -112,7 +112,7 @@ pub async fn load_post(slug: &str) -> color_eyre::eyre::Result<Post> {
|
|||
))
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
#[instrument(skip(src))]
|
||||
fn parse_frontmatter(
|
||||
src: String,
|
||||
) -> color_eyre::eyre::Result<(Option<TomlFrontMatter>, Option<String>)> {
|
||||
|
|
20
src/tag.rs
20
src/tag.rs
|
@ -11,20 +11,22 @@ pub struct Tag {
|
|||
pub posts: Vec<String>,
|
||||
}
|
||||
|
||||
pub fn get_tags<'a>(posts: impl IntoIterator<Item=&'a Post>) -> HashMap<String,Tag> {
|
||||
let mut tags: HashMap<String,Tag> = HashMap::new();
|
||||
pub fn get_tags<'a>(posts: impl IntoIterator<Item = &'a Post>) -> HashMap<String, Tag> {
|
||||
let mut tags: HashMap<String, Tag> = HashMap::new();
|
||||
|
||||
for post in posts.into_iter() {
|
||||
for key in &post.tags {
|
||||
if let Some(tag) = tags.get_mut(key) {
|
||||
tag.posts.push(post.slug.clone());
|
||||
}
|
||||
else {
|
||||
tags.insert(key.clone(), Tag {
|
||||
slug: key.clone(),
|
||||
absolute_path: format!("/tags/{key}/"),
|
||||
posts: vec![post.slug.clone()]
|
||||
});
|
||||
} else {
|
||||
tags.insert(
|
||||
key.clone(),
|
||||
Tag {
|
||||
slug: key.clone(),
|
||||
absolute_path: format!("/tags/{key}/"),
|
||||
posts: vec![post.slug.clone()],
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue