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())
+ }
+}