1
0
Fork 0

Compare commits

...

2 commits

Author SHA1 Message Date
Adrian Hedqvist a855c0c63f jaeger tracing setup 2023-11-10 23:09:00 +01:00
Adrian Hedqvist e9549217ae cargo update 2023-11-10 19:34:00 +01:00
10 changed files with 818 additions and 443 deletions

1169
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -6,13 +6,14 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
axum = { version = "0.6.12", features = ["http2", "original-uri"] }
cached = "0.44.0"
chrono = { version = "0.4.24", features = ["serde"] }
axum = { version = "0.6.20", features = ["http2", "original-uri", "tracing"] }
cached = "0.46.1"
chrono = { version = "0.4.31", features = ["serde"] }
color-eyre = "0.6.1"
config = "0.13.3"
glob = "0.3.0"
opentelemetry = { version = "0.19.0", features = ["metrics"] }
opentelemetry = { version = "0.21.0", features = ["metrics"] }
opentelemetry-jaeger = { version = "0.20.0", features = ["collector_client", "isahc_collector_client"]}
prometheus = { version = "0.13.3", features = ["process"] }
pulldown-cmark = "0.9.2"
regex = "1.7.2"
@ -20,11 +21,11 @@ serde = "1.0.144"
serde_derive = "1.0.144"
serde_json = "1.0.85"
syntect = "5.0.0"
tera = { version = "1.17.0", features = ["builtins"] }
tokio = { version = "1.19.2", features = ["full"] }
toml = "0.7.3"
tower = { version = "0.4.12", features = ["full"] }
tower-http = { version = "0.4.0", features = ["full"] }
tera = { version = "1.19.1", features = ["builtins"] }
tokio = { version = "1.34.0", features = ["full", "tracing"] }
toml = "0.8.8"
tower = { version = "0.4.13", features = ["full"] }
tower-http = { version = "0.4.4", features = ["full"] }
tracing = "0.1.35"
tracing-opentelemetry = "0.19.0"
tracing-subscriber = { version = "0.3.11", features = ["fmt", "env-filter", "json", "tracing-log"] }
tracing-opentelemetry = "0.22.0"
tracing-subscriber = { version = "0.3.17", features = ["fmt", "env-filter", "json", "tracing-log"] }

View file

@ -1,3 +1,3 @@
base_url = "http://localhost:8080/"
bind_address = "0.0.0.0:8080"
logging = "info"
logging = "info,website=debug"

View file

@ -37,9 +37,7 @@ pub fn routes(state: &Arc<AppState>) -> Router<Arc<AppState>> {
.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))
.route_service(
"/posts/:slug/*path",
ServeDir::new("./"),
@ -48,6 +46,8 @@ pub fn routes(state: &Arc<AppState>) -> Router<Arc<AppState>> {
"/static/*path",
ServeDir::new("./"),
)
.layer(axum::middleware::from_fn(metrics_middleware))
.route("/metrics", get(metrics))
}
#[instrument(skip(state))]
@ -76,6 +76,7 @@ async fn healthcheck() -> &'static str {
"OK"
}
#[instrument]
async fn metrics() -> impl IntoResponse {
let encoder = TextEncoder::new();
let metric_families = prometheus::gather();
@ -93,6 +94,7 @@ pub async fn not_found() -> impl IntoResponse {
(StatusCode::NOT_FOUND, ())
}
#[instrument(skip(request, next))]
pub async fn metrics_middleware<B>(request: Request<B>, next: Next<B>) -> Response {
let path = request.uri().path().to_string();
let method = request.method().clone();

View file

@ -76,18 +76,13 @@ pub async fn index(
let res = state.tera.render("posts_index.html", &c)?;
let mut headers = vec![];
if let Some(date) = last_changed {
headers.push((header::LAST_MODIFIED, date.to_rfc2822()));
}
Ok((
StatusCode::OK,
[(
header::LAST_MODIFIED,
last_changed.map_or_else(
|| chrono::offset::Utc::now().to_rfc2822(),
|| state.startup_time.to_rfc2822(),
|d| d.to_rfc2822(),
),
)],
@ -122,7 +117,7 @@ pub async fn view(
[(
header::LAST_MODIFIED,
last_changed.map_or_else(
|| chrono::offset::Utc::now().to_rfc2822(),
|| state.startup_time.to_rfc2822(),
|d| d.to_rfc2822(),
),
)],
@ -131,6 +126,7 @@ pub async fn view(
.into_response())
}
#[instrument(skip(state))]
pub async fn feed(
State(state): State<Arc<AppState>>,
headers: HeaderMap,
@ -154,7 +150,7 @@ pub async fn feed(
(
header::LAST_MODIFIED,
&last_changed.map_or_else(
|| chrono::offset::Utc::now().to_rfc2822(),
|| state.startup_time.to_rfc2822(),
|d| d.to_rfc2822(),
),
),

View file

@ -74,6 +74,7 @@ pub async fn view(
let ctx = TagContext { title: &title };
let mut c = tera::Context::new();
c.insert("base_url", &state.base_url.to_string());
c.insert("tag_slug", &tag);
c.insert("page", &ctx);
c.insert("posts", &posts);
@ -94,6 +95,7 @@ pub async fn view(
.into_response())
}
#[instrument(skip(state))]
pub async fn feed(
Path(slug): Path<String>,
State(state): State<Arc<AppState>>,

View file

@ -1,6 +1,7 @@
use syntect::{highlighting::ThemeSet, parsing::SyntaxSet};
use tracing::error;
use tracing::{error, instrument};
#[instrument(skip(content, lang, theme))]
pub fn hilight(content: &str, lang: &str, theme: Option<&str>) -> color_eyre::Result<String> {
let ss = SyntaxSet::load_defaults_newlines();
let s = ss

View file

@ -17,7 +17,7 @@ use post::Post;
use tag::Tag;
use tera::Tera;
use tower_http::{compression::CompressionLayer, cors::CorsLayer};
use tracing::{field::Empty, info_span, log::info, Span};
use tracing::{field::Empty, info_span, log::info, Span, instrument};
use tracing_subscriber::{prelude::*, EnvFilter};
@ -40,16 +40,25 @@ pub struct AppState {
#[tokio::main]
async fn main() -> Result<()> {
color_eyre::install()?;
let cfg = Config::builder()
.add_source(config::File::with_name("config.toml"))
.add_source(config::Environment::with_prefix("APP"))
.add_source(config::Environment::with_prefix("WEBSITE"))
.build()?;
color_eyre::install()?;
init_tracing(&cfg);
info!("Starting server...");
let app = init_app(&cfg).await?;
axum::Server::bind(&cfg.get_string("bind_address")?.parse().unwrap())
.serve(app.into_make_service())
.await?;
Ok(())
}
#[instrument]
async fn init_app(cfg: &Config) -> Result<axum::routing::Router> {
let base_url: Uri = cfg.get_string("base_url")?
.parse()
.unwrap();
@ -68,7 +77,8 @@ async fn main() -> Result<()> {
state.tags = tags;
let state = Arc::new(state);
let app = handlers::routes(&state)
info!("Listening at {}", state.base_url);
Ok(handlers::routes(&state)
.layer(CorsLayer::permissive())
.layer(CompressionLayer::new())
.layer(
@ -76,15 +86,7 @@ async fn main() -> Result<()> {
.make_span_with(make_span)
.on_response(on_response),
)
.with_state(state.clone());
info!("Now listening at {}", state.base_url);
axum::Server::bind(&cfg.get_string("bind_address")?.parse().unwrap())
.serve(app.into_make_service())
.await?;
Ok(())
.with_state(state.clone()))
}
fn init_tracing(cfg: &Config) {
@ -98,12 +100,22 @@ fn init_tracing(cfg: &Config) {
.from_env_lossy()
};
opentelemetry::global::set_text_map_propagator(opentelemetry_jaeger::Propagator::new());
let tracer = opentelemetry_jaeger::new_agent_pipeline()
.with_service_name("website")
.install_simple().unwrap();
let otel = tracing_opentelemetry::layer().with_tracer(tracer);
tracing_subscriber::registry()
.with(filter)
.with(otel)
.with(tracing_subscriber::fmt::layer())
.init();
}
fn make_span(request: &Request<Body>) -> Span {
let uri = if let Some(OriginalUri(uri)) = request.extensions().get::<OriginalUri>() {
uri

View file

@ -6,10 +6,12 @@ use pulldown_cmark::Event;
use pulldown_cmark::Tag;
use pulldown_cmark::{Options, Parser};
use regex::Regex;
use tracing::instrument;
static STARTS_WITH_SCHEMA_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^\w+:").unwrap());
static EMAIL_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^.+?@\w+(\.\w+)*$").unwrap());
#[instrument(skip(markdown))]
pub fn render_markdown_to_html(base_uri: Option<&Uri>, markdown: &str) -> String {
let mut opt = Options::empty();
opt.insert(Options::ENABLE_FOOTNOTES);

View file

@ -1,6 +1,7 @@
use std::collections::HashMap;
use serde_derive::Serialize;
use tracing::instrument;
use crate::post::Post;
@ -11,6 +12,7 @@ pub struct Tag {
pub posts: Vec<String>,
}
#[instrument(skip(posts))]
pub fn get_tags<'a>(posts: impl IntoIterator<Item = &'a Post>) -> HashMap<String, Tag> {
let mut tags: HashMap<String, Tag> = HashMap::new();