Skip to content
This repository has been archived by the owner on Feb 8, 2024. It is now read-only.

Commit

Permalink
Merge pull request #2 from PostHog/ellie/setup-producer-api
Browse files Browse the repository at this point in the history
Setup basic API
  • Loading branch information
ellie authored Dec 7, 2023
2 parents 123a3fa + 731ae14 commit a0072d1
Show file tree
Hide file tree
Showing 9 changed files with 844 additions and 30 deletions.
721 changes: 700 additions & 21 deletions Cargo.lock

Large diffs are not rendered by default.

13 changes: 12 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,15 @@ members = [
]

[workspace.dependencies]
sqlx = { version = "0.7", features = [ "runtime-tokio", "tls-native-tls", "postgres", "uuid", "json" ] }
chrono = { version = "0.4" }
serde = { version = "1.0" }
serde_derive = { version = "1.0" }
thiserror = { version = "1.0" }
sqlx = { version = "0.7", features = [ "runtime-tokio", "tls-native-tls", "postgres", "uuid", "json", "chrono" ] }
tokio = { version = "1.34.0", features = ["full"] }
eyre = "0.6.9"
tracing = "0.1.40"
tracing-subscriber = "0.3.18"
envconfig = "0.10.0"
metrics = "0.21.1"
metrics-exporter-prometheus = "0.12.1"
12 changes: 6 additions & 6 deletions hook-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
chrono = { version = "0.4" }
serde = { version = "1.0" }
serde_derive = { version = "1.0" }
sqlx = { version = "0.7", features = [ "runtime-tokio", "tls-native-tls", "postgres", "uuid", "json", "chrono" ] }
thiserror = { version = "1.0" }
chrono = { workspace = true}
serde = { workspace = true }
serde_derive = { workspace = true}
thiserror = { workspace = true }
sqlx = { workspace = true }

[dev-dependencies]
tokio = { version = "1.34", features = ["macros"] } # We need a runtime for async tests
tokio = { workspace = true } # We need a runtime for async tests
8 changes: 8 additions & 0 deletions hook-producer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,11 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
axum = { version="0.7.1", features=["http2"] }
tokio = { workspace = true }
eyre = {workspace = true }
tracing = {workspace = true}
tracing-subscriber = {workspace = true}
envconfig = { workspace = true }
metrics = { workspace = true }
metrics-exporter-prometheus = { workspace = true }
16 changes: 16 additions & 0 deletions hook-producer/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use envconfig::Envconfig;

#[derive(Envconfig)]
pub struct Config {
#[envconfig(from = "BIND_HOST", default = "0.0.0.0")]
pub host: String,

#[envconfig(from = "BIND_PORT", default = "8000")]
pub port: u16,
}

impl Config {
pub fn bind(&self) -> String {
format!("{}:{}", self.host, self.port)
}
}
3 changes: 3 additions & 0 deletions hook-producer/src/handlers/index.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub async fn get() -> &'static str {
"rusty hook"
}
15 changes: 15 additions & 0 deletions hook-producer/src/handlers/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use axum::{routing, Router};

mod index;

pub fn router() -> Router {
let recorder_handle = crate::metrics::setup_metrics_recorder();

Router::new()
.route("/", routing::get(index::get))
.route(
"/metrics",
routing::get(move || std::future::ready(recorder_handle.render())),
)
.layer(axum::middleware::from_fn(crate::metrics::track_metrics))
}
33 changes: 31 additions & 2 deletions hook-producer/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,32 @@
fn main() {
println!("Hello, world!");
use axum::Router;

use config::Config;
use envconfig::Envconfig;

use eyre::Result;

mod config;
mod handlers;
mod metrics;

async fn listen(app: Router, bind: String) -> Result<()> {
let listener = tokio::net::TcpListener::bind(bind).await?;

axum::serve(listener, app).await?;

Ok(())
}

#[tokio::main]
async fn main() {
tracing_subscriber::fmt::init();

let app = handlers::router();

let config = Config::init_from_env().expect("failed to load configuration from env");

match listen(app, config.bind()).await {
Ok(_) => {}
Err(e) => tracing::error!("failed to start hook-producer http server, {}", e),
}
}
53 changes: 53 additions & 0 deletions hook-producer/src/metrics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use std::time::Instant;

use axum::{
body::Body, extract::MatchedPath, http::Request, middleware::Next, response::IntoResponse,
};
use metrics_exporter_prometheus::{Matcher, PrometheusBuilder, PrometheusHandle};

pub fn setup_metrics_recorder() -> PrometheusHandle {
const EXPONENTIAL_SECONDS: &[f64] = &[
0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0,
];

PrometheusBuilder::new()
.set_buckets_for_metric(
Matcher::Full("http_requests_duration_seconds".to_string()),
EXPONENTIAL_SECONDS,
)
.unwrap()
.install_recorder()
.unwrap()
}

/// Middleware to record some common HTTP metrics
/// Someday tower-http might provide a metrics middleware: https://github.com/tower-rs/tower-http/issues/57
pub async fn track_metrics(req: Request<Body>, next: Next) -> impl IntoResponse {
let start = Instant::now();

let path = if let Some(matched_path) = req.extensions().get::<MatchedPath>() {
matched_path.as_str().to_owned()
} else {
req.uri().path().to_owned()
};

let method = req.method().clone();

// Run the rest of the request handling first, so we can measure it and get response
// codes.
let response = next.run(req).await;

let latency = start.elapsed().as_secs_f64();
let status = response.status().as_u16().to_string();

let labels = [
("method", method.to_string()),
("path", path),
("status", status),
];

metrics::increment_counter!("http_requests_total", &labels);
metrics::histogram!("http_requests_duration_seconds", latency, &labels);

response
}

0 comments on commit a0072d1

Please sign in to comment.