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,
|
||||
fmt::{self, Write},
|
||||
hash,
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
|
@ -46,7 +45,7 @@ macro_rules! mk_err_enum {
|
|||
}
|
||||
|
||||
mod errno;
|
||||
use self::errno::Errno;
|
||||
pub use self::errno::Errno;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct RequestLabels {
|
||||
|
@ -133,15 +132,6 @@ pub struct DstLabels {
|
|||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
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 {
|
||||
|
@ -461,55 +451,6 @@ impl Into<ctx::transport::TlsStatus> for TlsStatus {
|
|||
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 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
|
|
|
@ -59,6 +59,7 @@ mod latency;
|
|||
mod process;
|
||||
mod record;
|
||||
mod serve;
|
||||
mod tls_config_reload;
|
||||
mod transport;
|
||||
|
||||
use self::counter::Counter;
|
||||
|
@ -70,12 +71,10 @@ use self::labels::{
|
|||
TransportLabels,
|
||||
TransportCloseLabels,
|
||||
};
|
||||
pub use self::labels::{
|
||||
DstLabels,
|
||||
TlsConfigLabels,
|
||||
};
|
||||
pub use self::labels::DstLabels;
|
||||
pub use self::record::Record;
|
||||
pub use self::serve::Serve;
|
||||
pub use self::tls_config_reload::TlsConfigReload;
|
||||
|
||||
/// Writes a metric in prometheus-formatted output.
|
||||
///
|
||||
|
@ -112,10 +111,7 @@ struct Root {
|
|||
responses: http::ResponseScopes,
|
||||
transports: transport::OpenScopes,
|
||||
transport_closes: transport::CloseScopes,
|
||||
|
||||
tls_config: TlsConfigScopes,
|
||||
tls_config_last_reload_seconds: Option<Gauge>,
|
||||
|
||||
tls_config_reload: TlsConfigReload,
|
||||
process: process::Process,
|
||||
}
|
||||
|
||||
|
@ -134,8 +130,6 @@ struct Stamped<T> {
|
|||
inner: T,
|
||||
}
|
||||
|
||||
type TlsConfigScopes = Scopes<labels::TlsConfigLabels, Counter>;
|
||||
|
||||
/// Construct the Prometheus metrics.
|
||||
///
|
||||
/// Returns the `Record` and `Serve` sides. The `Serve` side
|
||||
|
@ -180,13 +174,6 @@ impl<'a, M: FmtMetric> Metric<'a, M> {
|
|||
// ===== 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 {
|
||||
Self {
|
||||
process: process::Process::new(&process),
|
||||
|
@ -218,9 +205,8 @@ impl Root {
|
|||
.stamped()
|
||||
}
|
||||
|
||||
fn tls_config(&mut self, labels: TlsConfigLabels) -> &mut Counter {
|
||||
self.tls_config.scopes.entry(labels)
|
||||
.or_insert_with(|| Counter::default())
|
||||
fn tls_config(&mut self) -> &mut TlsConfigReload {
|
||||
&mut self.tls_config_reload
|
||||
}
|
||||
|
||||
fn retain_since(&mut self, epoch: Instant) {
|
||||
|
@ -237,40 +223,13 @@ impl fmt::Display for Root {
|
|||
self.responses.fmt(f)?;
|
||||
self.transports.fmt(f)?;
|
||||
self.transport_closes.fmt(f)?;
|
||||
self.tls_config.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.tls_config_reload.fmt(f)?;
|
||||
self.process.fmt(f)?;
|
||||
|
||||
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<T> Stamped<T> {
|
||||
|
|
|
@ -7,9 +7,7 @@ use super::labels::{
|
|||
ResponseLabels,
|
||||
TransportLabels,
|
||||
TransportCloseLabels,
|
||||
TlsConfigLabels,
|
||||
};
|
||||
use std::time::UNIX_EPOCH;
|
||||
|
||||
/// Tracks Prometheus metrics
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -86,20 +84,10 @@ impl Record {
|
|||
},
|
||||
|
||||
Event::TlsConfigReloaded(ref when) =>
|
||||
self.update(|metrics| {
|
||||
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();
|
||||
}),
|
||||
self.update(|m| m.tls_config().success(when)),
|
||||
|
||||
Event::TlsConfigReloadFailed(ref err) =>
|
||||
self.update(|metrics| {
|
||||
metrics.tls_config(err.clone().into()).incr();
|
||||
}),
|
||||
self.update(|m| m.tls_config().error(err.clone())),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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