stuff
This commit is contained in:
parent
035bc89310
commit
63f474c7af
8 changed files with 31 additions and 27 deletions
|
@ -62,10 +62,10 @@ WORKDIR /app
|
||||||
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/website ./
|
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/website ./
|
||||||
COPY ./static ./static
|
COPY ./static ./static
|
||||||
COPY ./templates ./templates
|
COPY ./templates ./templates
|
||||||
COPY ./posts ./posts
|
COPY ./pages ./pages
|
||||||
COPY ./config.toml ./config.toml
|
COPY ./config.toml ./config.toml
|
||||||
|
|
||||||
EXPOSE 8180
|
EXPOSE 8080
|
||||||
|
|
||||||
# Use an unprivileged user.
|
# Use an unprivileged user.
|
||||||
USER website:website
|
USER website:website
|
||||||
|
|
|
@ -2,15 +2,17 @@ name: "tlxite"
|
||||||
services:
|
services:
|
||||||
web:
|
web:
|
||||||
build: .
|
build: .
|
||||||
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
depends_on:
|
depends_on:
|
||||||
- otel-collector
|
- otel-collector
|
||||||
environment:
|
environment:
|
||||||
TLX_OTLP_ENABLED: true
|
TLX_OTLP_ENABLED: true
|
||||||
|
TLX_LOG: debug
|
||||||
otel-collector:
|
otel-collector:
|
||||||
image: otel/opentelemetry-collector:latest
|
image: otel/opentelemetry-collector:latest
|
||||||
restart: always
|
restart: unless-stopped
|
||||||
command: ["--config=/etc/otel-collector-config.yaml", "${OTELCOL_ARGS}"]
|
command: ["--config=/etc/otel-collector-config.yaml", "${OTELCOL_ARGS}"]
|
||||||
volumes:
|
volumes:
|
||||||
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||||
|
|
|
@ -4,7 +4,7 @@ bind_address = "0.0.0.0:8080"
|
||||||
logging = "info,website=debug"
|
logging = "info,website=debug"
|
||||||
|
|
||||||
[otlp]
|
[otlp]
|
||||||
enabled = false
|
enabled = true
|
||||||
endpoint = "http://otel-collector:4317"
|
endpoint = "http://otel-collector:4317"
|
||||||
authorization = "Basic YWRyaWFuQHRvbGx5eC5uZXQ6N3VHVDU1NGpudGdxVE5LMg=="
|
authorization = "Basic YWRyaWFuQHRvbGx5eC5uZXQ6N3VHVDU1NGpudGdxVE5LMg=="
|
||||||
organization = "default"
|
organization = "default"
|
||||||
|
|
|
@ -18,8 +18,10 @@ anyway here's a new todo list:
|
||||||
- [x] docker from-scratch image (it's small!)
|
- [x] docker from-scratch image (it's small!)
|
||||||
- [x] opentelemetry (metrics, traces)
|
- [x] opentelemetry (metrics, traces)
|
||||||
- [ ] opentelemetry logs? (don't know if I'm gonna need it? can probably just make the collector grab them from the docker logs?)
|
- [ ] opentelemetry logs? (don't know if I'm gonna need it? can probably just make the collector grab them from the docker logs?)
|
||||||
- [ ] sections (currently the posts page is hardcoded, should be able to turn any page-subfolder into its own section)
|
- [ ] sections (currently the posts page is hardcoded, should be able to turn any page-subfolder into its own section) __👈 NEXT__
|
||||||
- [ ] file-watching (rebuild pages when they're changed, not only on startup)
|
- [ ] file-watching (rebuild pages when they're changed, not only on startup)
|
||||||
|
- [ ] live-reload (I guess it's done by some js and a websocket that sends a message to the browser to reload?)
|
||||||
|
- [ ] custom
|
||||||
- [ ] ~~sass/less compilation~~ (don't think I need it, will skip for now)
|
- [ ] ~~sass/less compilation~~ (don't think I need it, will skip for now)
|
||||||
- [ ] fancy css (but nothing too fancy, I like it [Simple And Clean](https://youtu.be/0nKizH5TV_g?t=42))
|
- [ ] fancy css (but nothing too fancy, I like it [Simple And Clean](https://youtu.be/0nKizH5TV_g?t=42))
|
||||||
- [ ] other pages (now I've got it set up so I can write any page in markdown!!!)
|
- [ ] other pages (now I've got it set up so I can write any page in markdown!!!)
|
||||||
|
|
|
@ -26,7 +26,9 @@ async fn record_hit(method: String, path: String) {
|
||||||
.get_or_init(|| async { global::meter("tlxite").u64_counter("page_hit_count").init() })
|
.get_or_init(|| async { global::meter("tlxite").u64_counter("page_hit_count").init() })
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
counter.add(1, &[KeyValue::new("path", format!("{method} {path}"))]);
|
counter.add(1, &[
|
||||||
|
KeyValue::new("path", format!("{method} {path}")),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn routes() -> Router<Arc<AppState>> {
|
pub fn routes() -> Router<Arc<AppState>> {
|
||||||
|
|
|
@ -178,6 +178,7 @@ pub async fn feed(
|
||||||
.into_response())
|
.into_response())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
async fn get_static_file(base_dir: &str, uri: Uri) -> Result<Response, WebsiteError> {
|
async fn get_static_file(base_dir: &str, uri: Uri) -> Result<Response, WebsiteError> {
|
||||||
let req = Request::builder().uri(uri).body(Body::empty()).unwrap();
|
let req = Request::builder().uri(uri).body(Body::empty()).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use syntect::{highlighting::ThemeSet, parsing::SyntaxSet};
|
use syntect::{highlighting::ThemeSet, parsing::SyntaxSet};
|
||||||
use tracing::{error, instrument};
|
use tracing::{error, instrument};
|
||||||
|
|
||||||
#[instrument(skip(content, lang, theme))]
|
#[instrument(skip(content))]
|
||||||
pub fn hilight(content: &str, lang: &str, theme: Option<&str>) -> anyhow::Result<String> {
|
pub fn hilight(content: &str, lang: &str, theme: Option<&str>) -> anyhow::Result<String> {
|
||||||
let ss = SyntaxSet::load_defaults_newlines();
|
let ss = SyntaxSet::load_defaults_newlines();
|
||||||
let s = ss
|
let s = ss
|
||||||
|
|
|
@ -3,16 +3,13 @@ use std::{borrow::Cow, net::SocketAddr, time::Duration};
|
||||||
use anyhow::{Error, Result};
|
use anyhow::{Error, Result};
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{ConnectInfo, MatchedPath, OriginalUri, Request},
|
extract::{ConnectInfo, MatchedPath, OriginalUri, Request},
|
||||||
http::{header, uri::PathAndQuery, HeaderMap},
|
http::{header, HeaderMap},
|
||||||
response::Response,
|
response::Response,
|
||||||
};
|
};
|
||||||
use opentelemetry::{global, KeyValue};
|
use opentelemetry::{global, KeyValue};
|
||||||
use opentelemetry_otlp::WithExportConfig;
|
use opentelemetry_otlp::WithExportConfig;
|
||||||
use opentelemetry_sdk::{
|
use opentelemetry_sdk::{
|
||||||
metrics::reader::{DefaultAggregationSelector, DefaultTemporalitySelector},
|
metrics::reader::{DefaultAggregationSelector, DefaultTemporalitySelector}, propagation::TraceContextPropagator, trace::{RandomIdGenerator, Sampler}, Resource
|
||||||
propagation::TraceContextPropagator,
|
|
||||||
trace::{RandomIdGenerator, Sampler},
|
|
||||||
Resource,
|
|
||||||
};
|
};
|
||||||
use tracing::{field::Empty, info_span, Span};
|
use tracing::{field::Empty, info_span, Span};
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
|
||||||
|
@ -21,6 +18,7 @@ use crate::settings::Settings;
|
||||||
|
|
||||||
pub fn init(cfg: &Settings) -> Result<(), Error> {
|
pub fn init(cfg: &Settings) -> Result<(), Error> {
|
||||||
let filter = EnvFilter::builder()
|
let filter = EnvFilter::builder()
|
||||||
|
.with_env_var("TLX_LOG")
|
||||||
.with_default_directive("info".parse()?)
|
.with_default_directive("info".parse()?)
|
||||||
.parse_lossy(&cfg.logging);
|
.parse_lossy(&cfg.logging);
|
||||||
|
|
||||||
|
@ -74,7 +72,8 @@ pub fn init(cfg: &Settings) -> Result<(), Error> {
|
||||||
.with(otel_tracer)
|
.with(otel_tracer)
|
||||||
.with(tracing_subscriber::fmt::layer().compact())
|
.with(tracing_subscriber::fmt::layer().compact())
|
||||||
.init();
|
.init();
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
tracing_subscriber::registry()
|
tracing_subscriber::registry()
|
||||||
.with(filter)
|
.with(filter)
|
||||||
.with(tracing_subscriber::fmt::layer().compact())
|
.with(tracing_subscriber::fmt::layer().compact())
|
||||||
|
@ -90,22 +89,19 @@ pub fn make_span(req: &Request) -> Span {
|
||||||
} else {
|
} else {
|
||||||
req.uri()
|
req.uri()
|
||||||
};
|
};
|
||||||
|
let path = uri.path();
|
||||||
let route = req
|
let route = req
|
||||||
.extensions()
|
.extensions()
|
||||||
.get::<MatchedPath>()
|
.get::<MatchedPath>()
|
||||||
.map_or(uri.path(), axum::extract::MatchedPath::as_str);
|
.map_or(path, axum::extract::MatchedPath::as_str);
|
||||||
let method = req.method().as_str();
|
let method = req.method().as_str();
|
||||||
let scheme = req.uri().scheme().map_or("HTTP", |s| s.as_str());
|
let scheme = req.uri().scheme().map_or("HTTP", |s| s.as_str());
|
||||||
let target = uri
|
|
||||||
.path_and_query()
|
|
||||||
.map_or(uri.path(), PathAndQuery::as_str);
|
|
||||||
|
|
||||||
let user_agent = req
|
let user_agent = req
|
||||||
.headers()
|
.headers()
|
||||||
.get(header::USER_AGENT)
|
.get(header::USER_AGENT)
|
||||||
.map_or("", |h| h.to_str().unwrap_or(""));
|
.map_or("", |h| h.to_str().unwrap_or(""));
|
||||||
|
|
||||||
let name = format!("{method} {route}");
|
|
||||||
|
|
||||||
let client_ip = parse_x_forwarded_for(req.headers())
|
let client_ip = parse_x_forwarded_for(req.headers())
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
|
@ -116,16 +112,17 @@ pub fn make_span(req: &Request) -> Span {
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
info_span!(
|
info_span!(
|
||||||
"request",
|
"http request",
|
||||||
otel.name = %name,
|
otel.name = %format!("{method} {route}"),
|
||||||
otel.kind = &"server",
|
otel.kind = &"server",
|
||||||
http.client_ip = %client_ip,
|
client.address = %client_ip,
|
||||||
http.route = %route,
|
http.route = %route,
|
||||||
http.method = %method,
|
http.request.method = %method,
|
||||||
http.target = %target,
|
url.scheme = %scheme,
|
||||||
http.scheme = %scheme,
|
url.path = %path,
|
||||||
http.user_agent = %user_agent,
|
url.query = %uri.query().unwrap_or_default(),
|
||||||
http.status_code = Empty,
|
user_agent.original = %user_agent,
|
||||||
|
http.response.status_code = Empty,
|
||||||
otel.status_code = Empty,
|
otel.status_code = Empty,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -138,7 +135,7 @@ fn parse_x_forwarded_for(headers: &HeaderMap) -> Option<Cow<'_, str>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_response(response: &Response, _latency: Duration, span: &Span) {
|
pub fn on_response(response: &Response, _latency: Duration, span: &Span) {
|
||||||
span.record("http.status_code", response.status().as_str());
|
span.record("http.response.status_code", response.status().as_str());
|
||||||
if response.status().is_server_error() {
|
if response.status().is_server_error() {
|
||||||
span.record(
|
span.record(
|
||||||
"otel.status_code",
|
"otel.status_code",
|
||||||
|
|
Loading…
Reference in a new issue