1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-29 22:01:14 +03:00

Gate the prometheus exporter behind a feature

Also fixes the Docker image building and the CI builds
This commit is contained in:
Quentin Gliech
2022-09-28 10:52:41 +02:00
parent e9fd0eb36a
commit 9e3b3567b2
4 changed files with 72 additions and 30 deletions

View File

@ -31,8 +31,8 @@ opentelemetry-jaeger = { version = "0.17.0", features = ["rt-tokio", "collector_
opentelemetry-otlp = { version = "0.11.0", features = ["trace", "metrics", "http-proto"], optional = true }
opentelemetry-zipkin = { version = "0.16.0", features = ["opentelemetry-http"], default-features = false, optional = true }
opentelemetry-http = { version = "0.7.0", features = ["tokio", "hyper"], optional = true }
opentelemetry-prometheus = "0.11.0"
prometheus = "0.13.2"
opentelemetry-prometheus = { version = "0.11.0", optional = true }
prometheus = { version = "0.13.2", optional = true }
mas-config = { path = "../config" }
mas-email = { path = "../email" }
@ -49,7 +49,7 @@ mas-templates = { path = "../templates" }
indoc = "1.0.7"
[features]
default = ["otlp", "jaeger", "zipkin", "native-roots"]
default = ["otlp", "jaeger", "zipkin", "prometheus", "native-roots"]
# Use the native root certificates
native-roots = ["mas-http/native-roots", "mas-handlers/native-roots"]
@ -59,9 +59,11 @@ webpki-roots = ["mas-http/webpki-roots", "mas-handlers/webpki-roots"]
# Read the builtin static files and templates from the source directory
dev = ["mas-templates/dev", "mas-static-files/dev"]
# Enable OpenTelemetry OTLP exporter. Requires "protoc"
# Enable OpenTelemetry OTLP exporter.
otlp = ["dep:opentelemetry-otlp", "dep:opentelemetry-http"]
# Enable OpenTelemetry Jaeger exporter and propagator.
jaeger = ["dep:opentelemetry-jaeger"]
# Enable OpenTelemetry Zipkin exporter and B3 propagator.
zipkin = ["dep:opentelemetry-zipkin", "dep:opentelemetry-http"]
# Enable OpenTelemetry Prometheus exporter. Requires "protoc"
prometheus = ["dep:opentelemetry-prometheus", "dep:prometheus"]

View File

@ -12,14 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::{
convert::Infallible,
net::{SocketAddr, TcpListener},
time::Duration,
};
use std::time::Duration;
use anyhow::{bail, Context as _};
use hyper::{header::CONTENT_TYPE, service::make_service_fn, Body, Method, Request, Response};
use mas_config::{
JaegerExporterProtocolConfig, MetricsExporterConfig, Propagator, TelemetryConfig,
TracingExporterConfig,
@ -41,10 +36,7 @@ use opentelemetry_jaeger::Propagator as JaegerPropagator;
use opentelemetry_semantic_conventions as semcov;
#[cfg(feature = "zipkin")]
use opentelemetry_zipkin::{B3Encoding, Propagator as ZipkinPropagator};
use prometheus::{Encoder, TextEncoder};
use tokio::sync::OnceCell;
use tower::service_fn;
use tracing::info;
use url::Url;
static METRICS_BASIC_CONTROLLER: OnceCell<Option<BasicController>> = OnceCell::const_new();
@ -60,8 +52,10 @@ pub async fn setup(
mas_http::set_propagator(&propagator);
global::set_text_map_propagator(propagator);
let tracer = tracer(&config.tracing.exporter).await?;
let meter = meter(&config.metrics.exporter)?;
let tracer = tracer(&config.tracing.exporter)
.await
.context("Failed to configure traces exporter")?;
let meter = meter(&config.metrics.exporter).context("Failed to configure metrics exporter")?;
METRICS_BASIC_CONTROLLER.set(meter.clone())?;
Ok((tracer, meter))
@ -97,8 +91,7 @@ fn match_propagator(
))),
p => bail!(
"The service was compiled without support for the {:?} propagator, but config uses it.",
p
"The service was compiled without support for the {p:?} propagator, but config uses it.",
),
}
}
@ -112,7 +105,9 @@ fn propagator(propagators: &[Propagator]) -> anyhow::Result<impl TextMapPropagat
#[cfg(any(feature = "otlp", feature = "jaeger"))]
async fn http_client() -> anyhow::Result<impl opentelemetry_http::HttpClient + 'static> {
let client = mas_http::make_untraced_client().await?;
let client = mas_http::make_untraced_client()
.await
.context("Failed to build HTTP client used by telemetry exporter")?;
let client =
opentelemetry_http::hyper::HyperClient::new_with_timeout(client, Duration::from_secs(30));
Ok(client)
@ -138,18 +133,22 @@ fn otlp_tracer(endpoint: &Option<Url>) -> anyhow::Result<Tracer> {
.tracing()
.with_exporter(exporter)
.with_trace_config(trace_config())
.install_batch(opentelemetry::runtime::Tokio)?;
.install_batch(opentelemetry::runtime::Tokio)
.context("Failed to configure OTLP trace exporter")?;
Ok(tracer)
}
#[cfg(not(feature = "otlp"))]
fn otlp_tracer(_endpoint: &Option<Url>) -> anyhow::Result<Tracer> {
fn otlp_tracer(endpoint: &Option<Url>) -> anyhow::Result<Tracer> {
let _ = endpoint;
anyhow::bail!("The service was compiled without OTLP exporter support, but config exports traces via OTLP.")
}
#[cfg(not(feature = "jaeger"))]
fn jaeger_agent_tracer(host: &str, port: u16) -> anyhow::Result<Tracer> {
let _ = host;
let _ = port;
anyhow::bail!("The service was compiled without Jaeger exporter support, but config exports traces via Jaeger.")
}
@ -160,7 +159,9 @@ fn jaeger_agent_tracer(host: &str, port: u16) -> anyhow::Result<Tracer> {
.with_trace_config(trace_config())
.with_endpoint((host, port));
let tracer = pipeline.install_batch(opentelemetry::runtime::Tokio)?;
let tracer = pipeline
.install_batch(opentelemetry::runtime::Tokio)
.context("Failed to configure Jaeger agent exporter")?;
Ok(tracer)
}
@ -171,6 +172,10 @@ async fn jaeger_collector_tracer(
username: Option<&str>,
password: Option<&str>,
) -> anyhow::Result<Tracer> {
let _ = endpoint;
let _ = username;
let _ = password;
futures_util::future::ready(()).await; // Silence the "unused async" lint
anyhow::bail!("The service was compiled without Jaeger exporter support, but config exports traces via Jaeger.")
}
@ -195,13 +200,17 @@ async fn jaeger_collector_tracer(
pipeline = pipeline.with_password(password);
}
let tracer = pipeline.install_batch(opentelemetry::runtime::Tokio)?;
let tracer = pipeline
.install_batch(opentelemetry::runtime::Tokio)
.context("Failed to configure Jaeger collector exporter")?;
Ok(tracer)
}
#[cfg(not(feature = "zipkin"))]
async fn zipkin_tracer(_collector_endpoint: &Option<Url>) -> anyhow::Result<Tracer> {
async fn zipkin_tracer(collector_endpoint: &Option<Url>) -> anyhow::Result<Tracer> {
let _ = collector_endpoint;
futures_util::future::ready(()).await; // Silence the "unused async" lint
anyhow::bail!("The service was compiled without Jaeger exporter support, but config exports traces via Jaeger.")
}
@ -218,7 +227,9 @@ async fn zipkin_tracer(collector_endpoint: &Option<Url>) -> anyhow::Result<Trace
pipeline = pipeline.with_collector_endpoint(collector_endpoint.as_str());
}
let tracer = pipeline.install_batch(opentelemetry::runtime::Tokio)?;
let tracer = pipeline
.install_batch(opentelemetry::runtime::Tokio)
.context("Failed to configure Zipkin exporter")?;
Ok(tracer)
}
@ -262,13 +273,15 @@ fn otlp_meter(endpoint: &Option<url::Url>) -> anyhow::Result<BasicController> {
)
.with_resource(resource())
.with_exporter(exporter)
.build()?;
.build()
.context("Failed to configure OTLP metrics exporter")?;
Ok(controller)
}
#[cfg(not(feature = "otlp"))]
fn otlp_meter(_endpoint: &Option<url::Url>) -> anyhow::Result<BasicController> {
fn otlp_meter(endpoint: &Option<url::Url>) -> anyhow::Result<BasicController> {
let _ = endpoint;
anyhow::bail!("The service was compiled without OTLP exporter support, but config exports metrics via OTLP.")
}
@ -289,7 +302,22 @@ fn stdout_meter() -> anyhow::Result<BasicController> {
Ok(controller)
}
#[cfg(not(feature = "prometheus"))]
fn prometheus_meter(address: &str) -> anyhow::Result<BasicController> {
let _ = address;
anyhow::bail!("The service was compiled without Prometheus exporter support, but config exports metrics via Prometheus.")
}
#[cfg(feature = "prometheus")]
fn prometheus_meter(address: &str) -> anyhow::Result<BasicController> {
use std::{
convert::Infallible,
net::{SocketAddr, TcpListener},
};
use hyper::{header::CONTENT_TYPE, service::make_service_fn, Body, Method, Request, Response};
use prometheus::{Encoder, TextEncoder};
let controller = sdk::metrics::controllers::basic(
sdk::metrics::processors::factory(
sdk::metrics::selectors::simple::histogram([
@ -307,7 +335,7 @@ fn prometheus_meter(address: &str) -> anyhow::Result<BasicController> {
let make_svc = make_service_fn(move |_conn| {
let exporter = exporter.clone();
async move {
Ok::<_, Infallible>(service_fn(move |req: Request<Body>| {
Ok::<_, Infallible>(tower::service_fn(move |req: Request<Body>| {
let exporter = exporter.clone();
async move {
let response = match (req.method(), req.uri().path()) {
@ -340,12 +368,14 @@ fn prometheus_meter(address: &str) -> anyhow::Result<BasicController> {
.context("could not parse listener address")?;
let listener = TcpListener::bind(address).context("could not bind address")?;
info!(
tracing::info!(
"Prometheus exporter listening on on http://{}/metrics",
listener.local_addr().unwrap()
);
let server = hyper::server::Server::from_tcp(listener)?.serve(make_svc);
let server = hyper::server::Server::from_tcp(listener)
.context("Failed to start HTTP server for the Prometheus metrics exporter")?
.serve(make_svc);
tokio::spawn(server);
Ok(controller)