diff --git a/Cargo.toml b/Cargo.toml index d385067..eef8e8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ derivative = "1.0.3" dnsstamps = "0.1.1" env_logger = { version="0.7.0", default-features = false, features = ["humantime"]} failure = "0.1.5" -futures-preview = { version = "=0.3.0-alpha.19", features = ["async-await", "unstable", "cfg-target-has-atomic"] } +futures-preview = { version = "=0.3.0-alpha.18", features = ["async-await", "nightly", "cfg-target-has-atomic"] } jemallocator = "0.3.2" libsodium-sys-stable="1.18.1" log = { version = "0.4.8", features = ["std", "release_max_level_debug"] } @@ -33,10 +33,24 @@ serde = "1.0.101" serde_derive = "1.0.101" serde-big-array = "0.1.5" siphasher = "0.3.1" -tokio = "=0.2.0-alpha.6" -tokio-net = "=0.2.0-alpha.6" +tokio = "=0.2.0-alpha.5" +tokio-net = "=0.2.0-alpha.5" toml = "0.5.3" +[dependencies.hyper] +optional = true +version = "0.13.0-alpha.2" +default_features = false + +[dependencies.prometheus] +optional = true +version = "0.7.0" +default_features = false + +[features] +default = ["metrics"] +metrics = ["hyper", "prometheus"] + [profile.release] codegen-units = 1 incremental = false diff --git a/src/main.rs b/src/main.rs index 09ab497..0552f14 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,9 @@ extern crate log; extern crate serde_derive; #[macro_use] extern crate serde_big_array; +#[cfg(feature = "metrics")] +#[macro_use] +extern crate prometheus; mod blacklist; mod cache; @@ -28,7 +31,11 @@ mod dnscrypt; mod dnscrypt_certs; mod errors; mod globals; +#[cfg(feature = "metrics")] +mod metrics; mod resolver; +#[cfg(feature = "metrics")] +mod varz; use blacklist::*; use cache::*; @@ -572,7 +579,8 @@ fn main() -> Result<(), Error> { }) .map(|_| ()), ); + #[cfg(feature = "metrics")] + runtime.spawn(metrics::prometheus_service(runtime.clone()).map(|_| ())); runtime.block_on(updater.run()); - Ok(()) } diff --git a/src/metrics.rs b/src/metrics.rs new file mode 100644 index 0000000..43c4a3e --- /dev/null +++ b/src/metrics.rs @@ -0,0 +1,24 @@ +use crate::errors::*; + +use futures::FutureExt; +use hyper::server::conn::Http; +use hyper::service::service_fn; +use hyper::{Body, Request, Response}; +use std::sync::Arc; +use tokio::net::TcpListener; +use tokio::runtime::Runtime; + +async fn handle_client_connection(_req: Request) -> Result, Error> { + let res = Response::new(Body::from("OK\n")); + Ok(res) +} + +pub async fn prometheus_service(runtime: Arc) -> Result<(), Error> { + let mut stream = TcpListener::bind("0.0.0.0:8000").await?; + loop { + let (client, _client_addr) = stream.accept().await?; + let service = service_fn(handle_client_connection); + let connection = Http::new().serve_connection(client, service); + runtime.spawn(connection.map(|_| {})); + } +} diff --git a/src/varz.rs b/src/varz.rs new file mode 100644 index 0000000..e2aac0c --- /dev/null +++ b/src/varz.rs @@ -0,0 +1,184 @@ +use coarsetime::Instant; +use prometheus::{Counter, Gauge, Histogram}; +use std::sync::Arc; + +pub struct StartInstant(pub Instant); + +pub struct Inner { + pub start_instant: StartInstant, + pub uptime: Gauge, + pub cache_frequent_len: Gauge, + pub cache_recent_len: Gauge, + pub cache_test_len: Gauge, + pub cache_inserted: Gauge, + pub cache_evicted: Gauge, + pub client_queries: Gauge, + pub client_queries_udp: Counter, + pub client_queries_tcp: Counter, + pub client_queries_cached: Counter, + pub client_queries_expired: Counter, + pub client_queries_offline: Counter, + pub client_queries_errors: Counter, + pub inflight_udp_queries: Gauge, + pub inflight_tcp_queries: Gauge, + pub upstream_errors: Counter, + pub upstream_sent: Counter, + pub upstream_received: Counter, + pub upstream_timeout: Counter, + pub upstream_response_sizes: Histogram, +} + +pub type Varz = Arc; + +pub fn new() -> Varz { + Arc::new(Inner::new()) +} + +impl Inner { + pub fn new() -> Inner { + Inner { + start_instant: StartInstant::default(), + uptime: register_gauge!(opts!( + "encrypted_dns_uptime", + "Uptime", + labels! {"handler" => "all",} + )) + .unwrap(), + cache_frequent_len: register_gauge!(opts!( + "encrypted_dns_cache_frequent_len", + "Number of entries in the cached set of \ + frequent items", + labels! {"handler" => "all",} + )) + .unwrap(), + cache_recent_len: register_gauge!(opts!( + "encrypted_dns_cache_recent_len", + "Number of entries in the cached set of \ + recent items", + labels! {"handler" => "all",} + )) + .unwrap(), + cache_test_len: register_gauge!(opts!( + "encrypted_dns_cache_test_len", + "Number of entries in the cached set of \ + staged items", + labels! {"handler" => "all",} + )) + .unwrap(), + cache_inserted: register_gauge!(opts!( + "encrypted_dns_cache_inserted", + "Number of entries added to the cache", + labels! {"handler" => "all",} + )) + .unwrap(), + cache_evicted: register_gauge!(opts!( + "encrypted_dns_cache_evicted", + "Number of entries evicted from the cache", + labels! {"handler" => "all",} + )) + .unwrap(), + client_queries: register_gauge!(opts!( + "encrypted_dns_client_queries", + "Number of client queries received", + labels! {"handler" => "all",} + )) + .unwrap(), + client_queries_udp: register_counter!(opts!( + "encrypted_dns_client_queries_udp", + "Number of client queries received \ + using UDP", + labels! {"handler" => "all",} + )) + .unwrap(), + client_queries_tcp: register_counter!(opts!( + "encrypted_dns_client_queries_tcp", + "Number of client queries received \ + using TCP", + labels! {"handler" => "all",} + )) + .unwrap(), + client_queries_cached: register_counter!(opts!( + "encrypted_dns_client_queries_cached", + "Number of client queries sent from \ + the cache", + labels! {"handler" => "all",} + )) + .unwrap(), + client_queries_expired: register_counter!(opts!( + "encrypted_dns_client_queries_expired", + "Number of expired client queries", + labels! {"handler" => "all",} + )) + .unwrap(), + client_queries_offline: register_counter!(opts!( + "encrypted_dns_client_queries_offline", + "Number of client queries answered \ + while upstream resolvers are \ + unresponsive", + labels! {"handler" => "all",} + )) + .unwrap(), + client_queries_errors: register_counter!(opts!( + "encrypted_dns_client_queries_errors", + "Number of bogus client queries", + labels! {"handler" => "all",} + )) + .unwrap(), + inflight_udp_queries: register_gauge!(opts!( + "encrypted_dns_inflight_udp_queries", + "Number of UDP queries currently waiting for a response", + labels! {"handler" => "all",} + )) + .unwrap(), + inflight_tcp_queries: register_gauge!(opts!( + "encrypted_dns_inflight_tcp_queries", + "Number of TCP queries currently waiting for a response", + labels! {"handler" => "all",} + )) + .unwrap(), + upstream_errors: register_counter!(opts!( + "encrypted_dns_upstream_errors", + "Number of bogus upstream servers responses", + labels! {"handler" => "all",} + )) + .unwrap(), + upstream_sent: register_counter!(opts!( + "encrypted_dns_upstream_sent", + "Number of upstream servers queries sent", + labels! {"handler" => "all",} + )) + .unwrap(), + upstream_received: register_counter!(opts!( + "encrypted_dns_upstream_received", + "Number of upstream servers responses received", + labels! {"handler" => "all",} + )) + .unwrap(), + upstream_timeout: register_counter!(opts!( + "encrypted_dns_upstream_timeout", + "Number of upstream servers responses \ + having timed out", + labels! {"handler" => "all",} + )) + .unwrap(), + upstream_response_sizes: register_histogram!(histogram_opts!( + "encrypted_dns_upstream_response_sizes", + "Response size in bytes", + vec![64.0, 128.0, 192.0, 256.0, 512.0, 1024.0, 2048.0] + )) + .unwrap(), + } + } +} + +impl Default for Inner { + fn default() -> Self { + Self::new() + } +} + +impl Default for StartInstant { + fn default() -> StartInstant { + StartInstant(Instant::now()) + } +}