Consolidate telemetry::metrics::tls_config_reload (#45)
Details of TLS configuration reload metrics span several modules. This change consolidates all of this logic into a single module with a single public type, `TlsConfigReload`, that supports recording successful reloads, recording errors, and formatting its current state. This sets up further simplifications, eventually leading to the removal of the `Event` API.
This commit is contained in:
parent
47b0f0402d
commit
9912f4577b
|
@ -2,7 +2,6 @@ use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt::{self, Write},
|
fmt::{self, Write},
|
||||||
hash,
|
hash,
|
||||||
path::PathBuf,
|
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -46,7 +45,7 @@ macro_rules! mk_err_enum {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod errno;
|
mod errno;
|
||||||
use self::errno::Errno;
|
pub use self::errno::Errno;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
pub struct RequestLabels {
|
pub struct RequestLabels {
|
||||||
|
@ -133,15 +132,6 @@ pub struct DstLabels {
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
pub struct TlsStatus(ctx::transport::TlsStatus);
|
pub struct TlsStatus(ctx::transport::TlsStatus);
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
|
||||||
pub enum TlsConfigLabels {
|
|
||||||
Reloaded,
|
|
||||||
InvalidTrustAnchors,
|
|
||||||
InvalidPrivateKey,
|
|
||||||
InvalidEndEntityCert,
|
|
||||||
Io { path: PathBuf, errno: Option<Errno>, },
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== impl RequestLabels =====
|
// ===== impl RequestLabels =====
|
||||||
|
|
||||||
impl RequestLabels {
|
impl RequestLabels {
|
||||||
|
@ -461,55 +451,6 @@ impl Into<ctx::transport::TlsStatus> for TlsStatus {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== impl TlsConfigLabels =====
|
|
||||||
|
|
||||||
impl TlsConfigLabels {
|
|
||||||
pub fn success() -> Self {
|
|
||||||
TlsConfigLabels::Reloaded
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<tls::ConfigError> for TlsConfigLabels {
|
|
||||||
fn from(err: tls::ConfigError) -> Self {
|
|
||||||
match err {
|
|
||||||
tls::ConfigError::Io(path, error_code) =>
|
|
||||||
TlsConfigLabels::Io { path, errno: error_code.map(Errno::from) },
|
|
||||||
tls::ConfigError::FailedToParseTrustAnchors(_) =>
|
|
||||||
TlsConfigLabels::InvalidTrustAnchors,
|
|
||||||
tls::ConfigError::EndEntityCertIsNotValid(_) =>
|
|
||||||
TlsConfigLabels::InvalidEndEntityCert,
|
|
||||||
tls::ConfigError::InvalidPrivateKey =>
|
|
||||||
TlsConfigLabels::InvalidPrivateKey,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for TlsConfigLabels {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
TlsConfigLabels::Reloaded =>
|
|
||||||
f.pad("status=\"reloaded\""),
|
|
||||||
TlsConfigLabels::Io { ref path, errno: Some(errno) } =>
|
|
||||||
write!(f,
|
|
||||||
"status=\"io_error\",path=\"{}\",errno=\"{}\"",
|
|
||||||
path.display(), errno
|
|
||||||
),
|
|
||||||
TlsConfigLabels::Io { ref path, errno: None } =>
|
|
||||||
write!(f,
|
|
||||||
"status=\"io_error\",path=\"{}\",errno=\"UNKNOWN\"",
|
|
||||||
path.display(),
|
|
||||||
),
|
|
||||||
TlsConfigLabels::InvalidPrivateKey =>
|
|
||||||
f.pad("status=\"invalid_private_key\""),
|
|
||||||
TlsConfigLabels::InvalidEndEntityCert =>
|
|
||||||
f.pad("status=\"invalid_end_entity_cert\""),
|
|
||||||
TlsConfigLabels::InvalidTrustAnchors =>
|
|
||||||
f.pad("status=\"invalid_trust_anchors\""),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for tls::ReasonForNoIdentity {
|
impl fmt::Display for tls::ReasonForNoIdentity {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -59,6 +59,7 @@ mod latency;
|
||||||
mod process;
|
mod process;
|
||||||
mod record;
|
mod record;
|
||||||
mod serve;
|
mod serve;
|
||||||
|
mod tls_config_reload;
|
||||||
mod transport;
|
mod transport;
|
||||||
|
|
||||||
use self::counter::Counter;
|
use self::counter::Counter;
|
||||||
|
@ -70,12 +71,10 @@ use self::labels::{
|
||||||
TransportLabels,
|
TransportLabels,
|
||||||
TransportCloseLabels,
|
TransportCloseLabels,
|
||||||
};
|
};
|
||||||
pub use self::labels::{
|
pub use self::labels::DstLabels;
|
||||||
DstLabels,
|
|
||||||
TlsConfigLabels,
|
|
||||||
};
|
|
||||||
pub use self::record::Record;
|
pub use self::record::Record;
|
||||||
pub use self::serve::Serve;
|
pub use self::serve::Serve;
|
||||||
|
pub use self::tls_config_reload::TlsConfigReload;
|
||||||
|
|
||||||
/// Writes a metric in prometheus-formatted output.
|
/// Writes a metric in prometheus-formatted output.
|
||||||
///
|
///
|
||||||
|
@ -112,10 +111,7 @@ struct Root {
|
||||||
responses: http::ResponseScopes,
|
responses: http::ResponseScopes,
|
||||||
transports: transport::OpenScopes,
|
transports: transport::OpenScopes,
|
||||||
transport_closes: transport::CloseScopes,
|
transport_closes: transport::CloseScopes,
|
||||||
|
tls_config_reload: TlsConfigReload,
|
||||||
tls_config: TlsConfigScopes,
|
|
||||||
tls_config_last_reload_seconds: Option<Gauge>,
|
|
||||||
|
|
||||||
process: process::Process,
|
process: process::Process,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,8 +130,6 @@ struct Stamped<T> {
|
||||||
inner: T,
|
inner: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
type TlsConfigScopes = Scopes<labels::TlsConfigLabels, Counter>;
|
|
||||||
|
|
||||||
/// Construct the Prometheus metrics.
|
/// Construct the Prometheus metrics.
|
||||||
///
|
///
|
||||||
/// Returns the `Record` and `Serve` sides. The `Serve` side
|
/// Returns the `Record` and `Serve` sides. The `Serve` side
|
||||||
|
@ -180,13 +174,6 @@ impl<'a, M: FmtMetric> Metric<'a, M> {
|
||||||
// ===== impl Root =====
|
// ===== impl Root =====
|
||||||
|
|
||||||
impl Root {
|
impl Root {
|
||||||
metrics! {
|
|
||||||
tls_config_last_reload_seconds: Gauge {
|
|
||||||
"Timestamp of when the TLS configuration files were last reloaded \
|
|
||||||
successfully (in seconds since the UNIX epoch)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(process: &Arc<ctx::Process>) -> Self {
|
pub fn new(process: &Arc<ctx::Process>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
process: process::Process::new(&process),
|
process: process::Process::new(&process),
|
||||||
|
@ -218,9 +205,8 @@ impl Root {
|
||||||
.stamped()
|
.stamped()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tls_config(&mut self, labels: TlsConfigLabels) -> &mut Counter {
|
fn tls_config(&mut self) -> &mut TlsConfigReload {
|
||||||
self.tls_config.scopes.entry(labels)
|
&mut self.tls_config_reload
|
||||||
.or_insert_with(|| Counter::default())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retain_since(&mut self, epoch: Instant) {
|
fn retain_since(&mut self, epoch: Instant) {
|
||||||
|
@ -237,40 +223,13 @@ impl fmt::Display for Root {
|
||||||
self.responses.fmt(f)?;
|
self.responses.fmt(f)?;
|
||||||
self.transports.fmt(f)?;
|
self.transports.fmt(f)?;
|
||||||
self.transport_closes.fmt(f)?;
|
self.transport_closes.fmt(f)?;
|
||||||
self.tls_config.fmt(f)?;
|
self.tls_config_reload.fmt(f)?;
|
||||||
|
|
||||||
if let Some(timestamp) = self.tls_config_last_reload_seconds {
|
|
||||||
Self::tls_config_last_reload_seconds.fmt_help(f)?;
|
|
||||||
Self::tls_config_last_reload_seconds.fmt_metric(f, timestamp)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.process.fmt(f)?;
|
self.process.fmt(f)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TlsConfigScopes {
|
|
||||||
metrics! {
|
|
||||||
tls_config_reload_total: Counter {
|
|
||||||
"Total number of times the proxy's TLS config files were reloaded."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for TlsConfigScopes {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
if self.scopes.is_empty() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
Self::tls_config_reload_total.fmt_help(f)?;
|
|
||||||
Self::tls_config_reload_total.fmt_scopes(f, &self, |s| &s)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== impl Stamped =====
|
// ===== impl Stamped =====
|
||||||
|
|
||||||
impl<T> Stamped<T> {
|
impl<T> Stamped<T> {
|
||||||
|
|
|
@ -7,9 +7,7 @@ use super::labels::{
|
||||||
ResponseLabels,
|
ResponseLabels,
|
||||||
TransportLabels,
|
TransportLabels,
|
||||||
TransportCloseLabels,
|
TransportCloseLabels,
|
||||||
TlsConfigLabels,
|
|
||||||
};
|
};
|
||||||
use std::time::UNIX_EPOCH;
|
|
||||||
|
|
||||||
/// Tracks Prometheus metrics
|
/// Tracks Prometheus metrics
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -86,20 +84,10 @@ impl Record {
|
||||||
},
|
},
|
||||||
|
|
||||||
Event::TlsConfigReloaded(ref when) =>
|
Event::TlsConfigReloaded(ref when) =>
|
||||||
self.update(|metrics| {
|
self.update(|m| m.tls_config().success(when)),
|
||||||
let timestamp_secs = when
|
|
||||||
.duration_since(UNIX_EPOCH)
|
|
||||||
.expect("SystemTime before UNIX_EPOCH!")
|
|
||||||
.as_secs()
|
|
||||||
.into();
|
|
||||||
metrics.tls_config_last_reload_seconds = Some(timestamp_secs);
|
|
||||||
metrics.tls_config(TlsConfigLabels::success()).incr();
|
|
||||||
}),
|
|
||||||
|
|
||||||
Event::TlsConfigReloadFailed(ref err) =>
|
Event::TlsConfigReloadFailed(ref err) =>
|
||||||
self.update(|metrics| {
|
self.update(|m| m.tls_config().error(err.clone())),
|
||||||
metrics.tls_config(err.clone().into()).incr();
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
use std::{fmt, path::PathBuf, time::{SystemTime, UNIX_EPOCH}};
|
||||||
|
|
||||||
|
use telemetry::metrics::{Counter, Gauge, Metric, Scopes, labels::Errno};
|
||||||
|
use transport::tls;
|
||||||
|
|
||||||
|
metrics! {
|
||||||
|
tls_config_last_reload_seconds: Gauge {
|
||||||
|
"Timestamp of the last successful TLS configuration reload \
|
||||||
|
(in seconds since the UNIX epoch)"
|
||||||
|
},
|
||||||
|
tls_config_reload_total: Counter {
|
||||||
|
"Total number of TLS configuration reloads"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct TlsConfigReload {
|
||||||
|
last_reload: Option<Gauge>,
|
||||||
|
by_status: Scopes<Status, Counter>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Hash)]
|
||||||
|
enum Status {
|
||||||
|
Reloaded,
|
||||||
|
InvalidTrustAnchors,
|
||||||
|
InvalidPrivateKey,
|
||||||
|
InvalidEndEntityCert,
|
||||||
|
Io { path: PathBuf, errno: Option<Errno>, },
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== impl TlsConfigReload =====
|
||||||
|
|
||||||
|
impl TlsConfigReload {
|
||||||
|
pub fn success(&mut self, when: &SystemTime) {
|
||||||
|
let t = when
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.expect("times must be after UNIX epoch")
|
||||||
|
.as_secs();
|
||||||
|
self.last_reload = Some(t.into());
|
||||||
|
|
||||||
|
self.by_status.scopes
|
||||||
|
.entry(Status::Reloaded)
|
||||||
|
.or_insert_with(|| Counter::default())
|
||||||
|
.incr()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn error(&mut self, e: tls::ConfigError) {
|
||||||
|
self.by_status.scopes
|
||||||
|
.entry(e.into())
|
||||||
|
.or_insert_with(|| Counter::default())
|
||||||
|
.incr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for TlsConfigReload {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
if !self.by_status.scopes.is_empty() {
|
||||||
|
tls_config_reload_total.fmt_help(f)?;
|
||||||
|
tls_config_reload_total.fmt_scopes(f, &self.by_status, |s| &s)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(timestamp) = self.last_reload {
|
||||||
|
tls_config_last_reload_seconds.fmt_help(f)?;
|
||||||
|
tls_config_last_reload_seconds.fmt_metric(f, timestamp)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== impl Status =====
|
||||||
|
|
||||||
|
impl From<tls::ConfigError> for Status {
|
||||||
|
fn from(err: tls::ConfigError) -> Self {
|
||||||
|
match err {
|
||||||
|
tls::ConfigError::Io(path, error_code) =>
|
||||||
|
Status::Io { path, errno: error_code.map(Errno::from) },
|
||||||
|
tls::ConfigError::FailedToParseTrustAnchors(_) =>
|
||||||
|
Status::InvalidTrustAnchors,
|
||||||
|
tls::ConfigError::EndEntityCertIsNotValid(_) =>
|
||||||
|
Status::InvalidEndEntityCert,
|
||||||
|
tls::ConfigError::InvalidPrivateKey =>
|
||||||
|
Status::InvalidPrivateKey,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Status {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Status::Reloaded =>
|
||||||
|
f.pad("status=\"reloaded\""),
|
||||||
|
Status::Io { ref path, errno: Some(errno) } =>
|
||||||
|
write!(f,
|
||||||
|
"status=\"io_error\",path=\"{}\",errno=\"{}\"",
|
||||||
|
path.display(), errno
|
||||||
|
),
|
||||||
|
Status::Io { ref path, errno: None } =>
|
||||||
|
write!(f,
|
||||||
|
"status=\"io_error\",path=\"{}\",errno=\"UNKNOWN\"",
|
||||||
|
path.display(),
|
||||||
|
),
|
||||||
|
Status::InvalidPrivateKey =>
|
||||||
|
f.pad("status=\"invalid_private_key\""),
|
||||||
|
Status::InvalidEndEntityCert =>
|
||||||
|
f.pad("status=\"invalid_end_entity_cert\""),
|
||||||
|
Status::InvalidTrustAnchors =>
|
||||||
|
f.pad("status=\"invalid_trust_anchors\""),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue