diff --git a/Cargo.lock b/Cargo.lock index 00d52cc7a9..529d7e972b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1060,6 +1060,7 @@ dependencies = [ "linkerd-app-inbound", "linkerd-app-outbound", "linkerd-error", + "linkerd-metrics", "linkerd-opencensus", "rangemap", "regex", @@ -1135,7 +1136,6 @@ dependencies = [ "linkerd-stack", "linkerd-stack-metrics", "linkerd-stack-tracing", - "linkerd-system", "linkerd-tls", "linkerd-trace-context", "linkerd-tracing", @@ -1145,7 +1145,6 @@ dependencies = [ "pin-project", "quickcheck", "regex", - "semver", "serde_json", "thiserror", "tokio", @@ -1623,6 +1622,7 @@ dependencies = [ "hyper", "linkerd-stack", "parking_lot", + "prometheus", "quickcheck", "tokio", "tracing", @@ -2010,15 +2010,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "linkerd-system" -version = "0.1.0" -dependencies = [ - "libc", - "procfs", - "tracing", -] - [[package]] name = "linkerd-tls" version = "0.1.0" @@ -2132,10 +2123,12 @@ version = "0.1.0" dependencies = [ "futures", "jemallocator", + "lazy_static", "linkerd-app", "linkerd-meshtls", "linkerd-signal", "num_cpus", + "semver", "tokio", "tracing", ] @@ -2559,9 +2552,9 @@ dependencies = [ [[package]] name = "procfs" -version = "0.15.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943ca7f9f29bab5844ecd8fdb3992c5969b6622bb9609b9502fef9b4310e3f1f" +checksum = "b1de8dacb0873f77e6aefc6d71e044761fcc68060290f5b1089fcdf84626bb69" dependencies = [ "bitflags 1.3.2", "byteorder", @@ -2570,6 +2563,23 @@ dependencies = [ "rustix 0.36.16", ] +[[package]] +name = "prometheus" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" +dependencies = [ + "cfg-if", + "fnv", + "lazy_static", + "libc", + "memchr", + "parking_lot", + "procfs", + "protobuf", + "thiserror", +] + [[package]] name = "prost" version = "0.11.8" @@ -2678,6 +2688,12 @@ dependencies = [ "prost 0.12.1", ] +[[package]] +name = "protobuf" +version = "2.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" + [[package]] name = "quick-error" version = "1.2.3" @@ -2947,9 +2963,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" diff --git a/Cargo.toml b/Cargo.toml index a00b13f1f8..2bf37ce225 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,7 +60,6 @@ members = [ "linkerd/stack", "linkerd/stack/metrics", "linkerd/stack/tracing", - "linkerd/system", "linkerd/tonic-watch", "linkerd/tls", "linkerd/tls/test-util", diff --git a/linkerd/app/Cargo.toml b/linkerd/app/Cargo.toml index 2221e5a1ca..de3bb56dc9 100644 --- a/linkerd/app/Cargo.toml +++ b/linkerd/app/Cargo.toml @@ -24,6 +24,7 @@ linkerd-app-gateway = { path = "./gateway" } linkerd-app-inbound = { path = "./inbound" } linkerd-app-outbound = { path = "./outbound" } linkerd-error = { path = "../error" } +linkerd-metrics = { path = "../metrics", features = ["process"] } linkerd-opencensus = { path = "../opencensus" } rangemap = "1" regex = "1" diff --git a/linkerd/app/core/Cargo.toml b/linkerd/app/core/Cargo.toml index 1a98d081fe..010fc9a2cf 100644 --- a/linkerd/app/core/Cargo.toml +++ b/linkerd/app/core/Cargo.toml @@ -73,11 +73,5 @@ version = "0.4" default-features = false features = ["make", "spawn-ready", "timeout", "util", "limit"] -[target.'cfg(target_os = "linux")'.dependencies] -linkerd-system = { path = "../../system" } - -[build-dependencies] -semver = "1" - [dev-dependencies] quickcheck = { version = "1", default-features = false } diff --git a/linkerd/app/core/src/lib.rs b/linkerd/app/core/src/lib.rs index 3141a88e1d..1e082a2649 100644 --- a/linkerd/app/core/src/lib.rs +++ b/linkerd/app/core/src/lib.rs @@ -24,7 +24,6 @@ pub mod metrics; pub mod proxy; pub mod serve; pub mod svc; -pub mod telemetry; pub mod transport; pub use drain; diff --git a/linkerd/app/core/src/metrics.rs b/linkerd/app/core/src/metrics.rs index ffca10efca..edefbefca7 100644 --- a/linkerd/app/core/src/metrics.rs +++ b/linkerd/app/core/src/metrics.rs @@ -11,7 +11,7 @@ use crate::{ classify::Class, control, http_metrics, http_metrics as metrics, opencensus, profiles, stack_metrics, svc::Param, - telemetry, tls, + tls, transport::{self, labels::TlsConnect}, }; use linkerd_addr::Addr; @@ -143,14 +143,7 @@ where // === impl Metrics === impl Metrics { - pub fn new( - retain_idle: Duration, - start_time: telemetry::StartTime, - ) -> (Self, impl FmtMetrics + Clone + Send + 'static) { - let process = telemetry::process::Report::new(start_time); - - let build_info = telemetry::build_info::Report::default(); - + pub fn new(retain_idle: Duration) -> (Self, impl FmtMetrics + Clone + Send + 'static) { let (control, control_report) = { let m = metrics::Requests::::default(); let r = m.clone().into_report(retain_idle).with_prefix("control"); @@ -212,9 +205,7 @@ impl Metrics { .and_report(control_report) .and_report(transport_report) .and_report(opencensus_report) - .and_report(stack) - .and_report(process) - .and_report(build_info); + .and_report(stack); (metrics, report) } diff --git a/linkerd/app/core/src/telemetry.rs b/linkerd/app/core/src/telemetry.rs deleted file mode 100644 index 63acd33a92..0000000000 --- a/linkerd/app/core/src/telemetry.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod build_info; -pub mod process; -pub use self::process::StartTime; diff --git a/linkerd/app/core/src/telemetry/build_info.rs b/linkerd/app/core/src/telemetry/build_info.rs deleted file mode 100644 index 5e96de5aad..0000000000 --- a/linkerd/app/core/src/telemetry/build_info.rs +++ /dev/null @@ -1,38 +0,0 @@ -use linkerd_metrics::{metrics, FmtLabels, FmtMetric, FmtMetrics, Gauge}; -use std::{env, fmt}; - -pub const VERSION: &str = env!("LINKERD2_PROXY_VERSION"); -pub const DATE: &str = env!("LINKERD2_PROXY_BUILD_DATE"); -pub const VENDOR: &str = env!("LINKERD2_PROXY_VENDOR"); -pub const GIT_SHA: &str = env!("GIT_SHA"); -pub const PROFILE: &str = env!("PROFILE"); - -metrics! { - proxy_build_info: Gauge { - "Proxy build info" - } -} - -#[derive(Clone, Debug, Default)] -pub struct Report(()); - -struct Labels; - -impl FmtMetrics for Report { - fn fmt_metrics(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - proxy_build_info.fmt_help(f)?; - Gauge::from(1).fmt_metric_labeled(f, "proxy_build_info", &Labels)?; - Ok(()) - } -} - -impl FmtLabels for Labels { - fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "version=\"{VERSION}\"")?; - write!(f, ",git_sha=\"{GIT_SHA}\"")?; - write!(f, ",profile=\"{PROFILE}\"")?; - write!(f, ",date=\"{DATE}\"")?; - write!(f, ",vendor=\"{VENDOR}\"")?; - Ok(()) - } -} diff --git a/linkerd/app/core/src/telemetry/process.rs b/linkerd/app/core/src/telemetry/process.rs deleted file mode 100644 index 967203a66f..0000000000 --- a/linkerd/app/core/src/telemetry/process.rs +++ /dev/null @@ -1,205 +0,0 @@ -use linkerd_metrics::{metrics, Counter, FmtMetrics, Gauge, MillisAsSeconds}; -use std::fmt; -use std::time::{SystemTime, UNIX_EPOCH}; -use tokio::time::Instant; - -metrics! { - process_start_time_seconds: Gauge { - "Time that the process started (in seconds since the UNIX epoch)" - }, - - process_uptime_seconds_total: Counter { - "Total time since the process started (in seconds)" - } -} - -/// The process' start time, consisting of both a `SystemTime` *and* an -/// `Instant`. -/// -/// The `SystemTime` represents the Unix timestamp when the process -/// started, while the `Instant` is anchored against that unix timestamp and is -/// used to calculate elapsed time more efficiently than by taking system timestamps. -#[derive(Copy, Clone, Debug)] -pub struct StartTime { - sys: SystemTime, - instant: Instant, -} - -#[derive(Clone, Debug)] -pub struct Report { - /// The process's start time in seconds since the Unix epoch. - /// - /// This is used to generate the `pprocess_start_time_seconds` gauge. This - /// could be calculated from the `SystemTime``, but the value will never change, - /// so we may as well pre-calculate it once. - start_time_from_epoch: u64, - - /// The process's start time as an `Instant`, used for calculating the uptime. - start_instant: Instant, - - #[cfg(target_os = "linux")] - system: linux::System, -} - -impl Report { - pub fn new(start_time: StartTime) -> Self { - let start_time_from_epoch = start_time - .sys - .duration_since(UNIX_EPOCH) - .expect("process start time") - .as_secs(); - - #[cfg(not(target_os = "linux"))] - tracing::info!("System-level metrics are only supported on Linux"); - Self { - start_time_from_epoch, - start_instant: start_time.instant, - #[cfg(target_os = "linux")] - system: linux::System::new(), - } - } -} - -impl FmtMetrics for Report { - fn fmt_metrics(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - process_start_time_seconds.fmt_help(f)?; - process_start_time_seconds.fmt_metric(f, &Gauge::from(self.start_time_from_epoch))?; - - // Use `staturating_duration_since` rather than `elapsed` to avoid - // possible panics in the event of clock non-monotonicity. - let uptime = Instant::now().saturating_duration_since(self.start_instant); - let uptime_millis = uptime.as_millis(); - process_uptime_seconds_total.fmt_help(f)?; - process_uptime_seconds_total.fmt_metric(f, &Counter::from(uptime_millis as u64))?; - - #[cfg(target_os = "linux")] - self.system.fmt_metrics(f)?; - - Ok(()) - } -} - -impl StartTime { - pub fn now() -> Self { - Self { - sys: SystemTime::now(), - instant: Instant::now(), - } - } -} - -impl From for Instant { - fn from(StartTime { instant, .. }: StartTime) -> Instant { - instant - } -} - -impl Default for StartTime { - fn default() -> Self { - Self::now() - } -} - -#[cfg(target_os = "linux")] -mod linux { - use linkerd_metrics::{metrics, Counter, FmtMetrics, Gauge, MillisAsSeconds}; - use linkerd_system as sys; - use std::fmt; - use tracing::warn; - - metrics! { - process_cpu_seconds_total: Counter { - "Total user and system CPU time spent in seconds." - }, - process_open_fds: Gauge { "Number of open file descriptors." }, - process_max_fds: Gauge { "Maximum number of open file descriptors." }, - process_virtual_memory_bytes: Gauge { - "Virtual memory size in bytes." - }, - process_resident_memory_bytes: Gauge { - "Resident memory size in bytes." - } - } - - #[derive(Clone, Debug, Default)] - pub(super) struct System { - page_size: Option, - ms_per_tick: Option, - } - - impl System { - pub fn new() -> Self { - let page_size = match sys::page_size() { - Ok(ps) => Some(ps), - Err(err) => { - warn!("Failed to load page size: {}", err); - None - } - }; - let ms_per_tick = match sys::ms_per_tick() { - Ok(mpt) => Some(mpt), - Err(err) => { - warn!("Failed to load cpu clock speed: {}", err); - None - } - }; - Self { - page_size, - ms_per_tick, - } - } - } - - impl FmtMetrics for System { - fn fmt_metrics(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let stat = match sys::blocking_stat() { - Ok(stat) => stat, - Err(err) => { - warn!("failed to read process stats: {}", err); - return Ok(()); - } - }; - - if let Some(mpt) = self.ms_per_tick { - let clock_ticks = stat.utime + stat.stime; - let cpu_ms = clock_ticks * mpt; - process_cpu_seconds_total.fmt_help(f)?; - process_cpu_seconds_total.fmt_metric(f, &Counter::from(cpu_ms))?; - } else { - warn!("Could not determine process_cpu_seconds_total"); - } - - process_virtual_memory_bytes.fmt_help(f)?; - process_virtual_memory_bytes.fmt_metric(f, &Gauge::from(stat.vsize))?; - - if let Some(ps) = self.page_size { - process_resident_memory_bytes.fmt_help(f)?; - process_resident_memory_bytes.fmt_metric(f, &Gauge::from(stat.rss * ps))?; - } else { - warn!("Could not determine process_resident_memory_bytes"); - } - - match sys::open_fds(stat.pid) { - Ok(open_fds) => { - process_open_fds.fmt_help(f)?; - process_open_fds.fmt_metric(f, &open_fds.into())?; - } - Err(err) => { - warn!("Could not determine process_open_fds: {}", err); - } - } - - match sys::max_fds() { - Ok(max_fds) => { - process_max_fds.fmt_help(f)?; - process_max_fds.fmt_metric(f, &max_fds.into())?; - } - Err(err) => { - warn!("Could not determine process_max_fds: {}", err); - } - } - - Ok(()) - } - } -} diff --git a/linkerd/app/inbound/src/test_util.rs b/linkerd/app/inbound/src/test_util.rs index 9ba0b2cf90..a6a74cf34e 100644 --- a/linkerd/app/inbound/src/test_util.rs +++ b/linkerd/app/inbound/src/test_util.rs @@ -92,8 +92,7 @@ pub fn default_config() -> Config { pub fn runtime() -> (ProxyRuntime, drain::Signal) { let (drain_tx, drain) = drain::channel(); let (tap, _) = tap::new(); - let (metrics, _) = - metrics::Metrics::new(std::time::Duration::from_secs(10), Default::default()); + let (metrics, _) = metrics::Metrics::new(std::time::Duration::from_secs(10)); let runtime = ProxyRuntime { identity: rustls::creds::default_for_test().1.into(), metrics: metrics.proxy, diff --git a/linkerd/app/integration/src/proxy.rs b/linkerd/app/integration/src/proxy.rs index a211beaba1..bb3c73f45c 100644 --- a/linkerd/app/integration/src/proxy.rs +++ b/linkerd/app/integration/src/proxy.rs @@ -460,14 +460,7 @@ async fn run(proxy: Proxy, mut env: TestEnv, random_ports: bool) -> Listening { let bind_adm = listen::BindTcp::default(); let (shutdown_tx, mut shutdown_rx) = tokio::sync::mpsc::unbounded_channel(); let main = config - .build( - bind_in, - bind_out, - bind_adm, - shutdown_tx, - trace_handle, - Default::default(), - ) + .build(bind_in, bind_out, bind_adm, shutdown_tx, trace_handle) .await .expect("config"); diff --git a/linkerd/app/outbound/src/test_util.rs b/linkerd/app/outbound/src/test_util.rs index 5cd899502a..2a3a58ad78 100644 --- a/linkerd/app/outbound/src/test_util.rs +++ b/linkerd/app/outbound/src/test_util.rs @@ -56,8 +56,7 @@ pub(crate) fn default_config() -> Config { pub(crate) fn runtime() -> (ProxyRuntime, drain::Signal) { let (drain_tx, drain) = drain::channel(); let (tap, _) = tap::new(); - let (metrics, _) = - metrics::Metrics::new(std::time::Duration::from_secs(10), Default::default()); + let (metrics, _) = metrics::Metrics::new(std::time::Duration::from_secs(10)); let runtime = ProxyRuntime { identity: linkerd_meshtls_rustls::creds::default_for_test().1.into(), metrics: metrics.proxy, diff --git a/linkerd/app/src/lib.rs b/linkerd/app/src/lib.rs index fe9719c4fc..f270403a56 100644 --- a/linkerd/app/src/lib.rs +++ b/linkerd/app/src/lib.rs @@ -21,7 +21,6 @@ use linkerd_app_core::{ dns, drain, metrics::FmtMetrics, svc::Param, - telemetry, transport::{addrs::*, listen::Bind}, Error, ProxyRuntime, }; @@ -98,7 +97,6 @@ impl Config { bind_admin: BAdmin, shutdown_tx: mpsc::UnboundedSender<()>, log_level: trace::Handle, - start_time: telemetry::StartTime, ) -> Result where BIn: Bind + 'static, @@ -128,7 +126,7 @@ impl Config { .. } = self; debug!("building app"); - let (metrics, report) = Metrics::new(admin.metrics_retain_idle, start_time); + let (metrics, report) = Metrics::new(admin.metrics_retain_idle); let dns = dns.build(); diff --git a/linkerd/metrics/Cargo.toml b/linkerd/metrics/Cargo.toml index df83bbdddc..4d9a1a2187 100644 --- a/linkerd/metrics/Cargo.toml +++ b/linkerd/metrics/Cargo.toml @@ -8,6 +8,7 @@ publish = false [features] default = [] +process = ["prometheus/process"] test_util = [] [dependencies] @@ -16,6 +17,7 @@ http = "0.2" hyper = { version = "0.14", features = ["http1", "http2"] } linkerd-stack = { path = "../stack", optional = true } parking_lot = "0.12" +prometheus = "0.13" tokio = { version = "1", features = ["time"] } tracing = "0.1" diff --git a/linkerd/metrics/src/counter.rs b/linkerd/metrics/src/counter.rs index 9513c3df13..e9f037e697 100644 --- a/linkerd/metrics/src/counter.rs +++ b/linkerd/metrics/src/counter.rs @@ -1,5 +1,5 @@ use super::{ - prom::{FmtLabels, FmtMetric}, + fmt::{FmtLabels, FmtMetric}, Factor, }; use std::fmt::{self, Display}; diff --git a/linkerd/metrics/src/prom.rs b/linkerd/metrics/src/fmt.rs similarity index 100% rename from linkerd/metrics/src/prom.rs rename to linkerd/metrics/src/fmt.rs diff --git a/linkerd/metrics/src/gauge.rs b/linkerd/metrics/src/gauge.rs index d35b3416c6..63952477e5 100644 --- a/linkerd/metrics/src/gauge.rs +++ b/linkerd/metrics/src/gauge.rs @@ -1,4 +1,4 @@ -use super::prom::{FmtLabels, FmtMetric}; +use super::fmt::{FmtLabels, FmtMetric}; use std::fmt::{self, Display}; use std::sync::atomic::{AtomicU64, Ordering}; diff --git a/linkerd/metrics/src/lib.rs b/linkerd/metrics/src/lib.rs index ed717e709e..b894fd8439 100644 --- a/linkerd/metrics/src/lib.rs +++ b/linkerd/metrics/src/lib.rs @@ -4,26 +4,37 @@ //! Utilities for exposing metrics to Prometheus. mod counter; +mod fmt; mod gauge; mod histogram; pub mod latency; #[cfg(feature = "linkerd-stack")] mod new_metrics; -mod prom; mod serve; mod store; +#[cfg(feature = "process")] +mod uptime; #[cfg(feature = "linkerd-stack")] pub use self::new_metrics::NewMetrics; pub use self::{ counter::Counter, + fmt::{FmtLabels, FmtMetric, FmtMetrics, Metric}, gauge::Gauge, histogram::Histogram, - prom::{FmtLabels, FmtMetric, FmtMetrics, Metric}, serve::Serve, store::{LastUpdate, SharedStore, Store}, }; +pub mod prom { + pub use prometheus::*; + + #[cfg(feature = "process")] + pub fn register_uptime_collector() -> Result<()> { + register(Box::::default()) + } +} + #[macro_export] macro_rules! metrics { { $( $name:ident : $kind:ty { $help:expr } ),+ } => { diff --git a/linkerd/metrics/src/serve.rs b/linkerd/metrics/src/serve.rs index 96edfb6a03..c4f23209bb 100644 --- a/linkerd/metrics/src/serve.rs +++ b/linkerd/metrics/src/serve.rs @@ -36,20 +36,34 @@ impl Serve { pub fn serve(&self, req: http::Request) -> std::io::Result> { if Self::is_gzip(&req) { trace!("gzipping metrics"); - let mut writer = GzEncoder::new(Vec::::new(), CompressionOptions::fast()); - write!(&mut writer, "{}", self.metrics.as_display())?; + let buf = { + let mut writer = GzEncoder::new(Vec::::new(), CompressionOptions::fast()); + self.write(&mut writer)?; + writer.finish()? + }; Ok(http::Response::builder() .header(http::header::CONTENT_ENCODING, "gzip") .header(http::header::CONTENT_TYPE, "text/plain") - .body(writer.finish()?.into()) + .body(Body::from(buf)) .expect("Response must be valid")) } else { let mut writer = Vec::::new(); - write!(&mut writer, "{}", self.metrics.as_display())?; + self.write(&mut writer)?; Ok(http::Response::builder() .header(http::header::CONTENT_TYPE, "text/plain") .body(Body::from(writer)) .expect("Response must be valid")) } } + + fn write(&self, f: &mut impl Write) -> std::io::Result<()> { + write!(f, "{}", self.metrics.as_display())?; + + let prom = crate::prom::gather(); + let enc = crate::prom::TextEncoder::new(); + let txt = enc + .encode_to_string(&prom) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?; + write!(f, "{}", txt) + } } diff --git a/linkerd/metrics/src/uptime.rs b/linkerd/metrics/src/uptime.rs new file mode 100644 index 0000000000..93e65468d5 --- /dev/null +++ b/linkerd/metrics/src/uptime.rs @@ -0,0 +1,32 @@ +use crate::prom; +use tokio::time; + +pub struct Uptime { + metric: prom::Gauge, + start: time::Instant, +} + +impl Default for Uptime { + fn default() -> Self { + Self { + start: time::Instant::now(), + metric: prom::Gauge::new( + "process_uptime_seconds_total", + "Total time since the process started (in seconds)", + ) + .expect("valid metric"), + } + } +} + +impl prom::core::Collector for Uptime { + fn desc(&self) -> Vec<&prom::core::Desc> { + self.metric.desc() + } + + fn collect(&self) -> Vec { + self.metric + .set((time::Instant::now() - self.start).as_secs_f64()); + self.metric.collect() + } +} diff --git a/linkerd/system/Cargo.toml b/linkerd/system/Cargo.toml deleted file mode 100644 index 1f53e16683..0000000000 --- a/linkerd/system/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "linkerd-system" -version = "0.1.0" -authors = ["Linkerd Developers "] -license = "Apache-2.0" -edition = "2021" -publish = false -description = """ -Unsafe code for accessing system-level counters for memory & CPU usage. -""" - -[dependencies] -tracing = "0.1" - -[target.'cfg(target_os = "linux")'.dependencies] -libc = "0.2" -procfs = { version = "0.15.1", default-features = false } diff --git a/linkerd/system/src/lib.rs b/linkerd/system/src/lib.rs deleted file mode 100644 index 8f1a26908c..0000000000 --- a/linkerd/system/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Unsafe code for accessing system-level counters for memory & CPU usage. - -#![deny( - rust_2018_idioms, - rust_2018_idioms, - clippy::disallowed_methods, - unsafe_code -)] - -#[cfg(target_os = "linux")] -mod linux; - -#[cfg(target_os = "linux")] -pub use self::linux::{blocking_stat, max_fds, ms_per_tick, open_fds, page_size, Stat}; - -#[cfg(not(target_os = "linux"))] -compile_error!("The system crate requires Linux"); diff --git a/linkerd/system/src/linux.rs b/linkerd/system/src/linux.rs deleted file mode 100644 index d8a27a9544..0000000000 --- a/linkerd/system/src/linux.rs +++ /dev/null @@ -1,65 +0,0 @@ -use libc::{self, pid_t}; -use procfs::{ - process::{self, LimitValue, Process}, - ProcResult, -}; -use std::{fs, io}; -use tracing::{error, warn}; - -pub use process::Stat; - -pub fn page_size() -> io::Result { - sysconf(libc::_SC_PAGESIZE, "page size") -} - -pub fn ms_per_tick() -> io::Result { - // On Linux, CLK_TCK is ~always `100`, so pure integer division - // works. This is probably not suitable if we encounter other - // values. - let clock_ticks_per_sec = sysconf(libc::_SC_CLK_TCK, "clock ticks per second")?; - let ms_per_tick = 1_000 / clock_ticks_per_sec; - if clock_ticks_per_sec != 100 { - warn!( - clock_ticks_per_sec, - ms_per_tick, "Unexpected value; process_cpu_seconds_total may be inaccurate." - ); - } - Ok(ms_per_tick) -} - -pub fn blocking_stat() -> ProcResult { - Process::myself()?.stat() -} - -pub fn open_fds(pid: pid_t) -> io::Result { - let mut open = 0; - for f in fs::read_dir(format!("/proc/{}/fd", pid))? { - if !f?.file_type()?.is_dir() { - open += 1; - } - } - Ok(open) -} - -pub fn max_fds() -> ProcResult { - let limits = Process::myself()?.limits()?.max_open_files; - match limits.soft_limit { - LimitValue::Unlimited => match limits.hard_limit { - LimitValue::Unlimited => Ok(0), - LimitValue::Value(hard) => Ok(hard), - }, - LimitValue::Value(soft) => Ok(soft), - } -} - -#[allow(unsafe_code)] -fn sysconf(num: libc::c_int, name: &'static str) -> Result { - match unsafe { libc::sysconf(num) } { - e if e <= 0 => { - let error = io::Error::last_os_error(); - error!("error getting {}: {:?}", name, error); - Err(error) - } - val => Ok(val as u64), - } -} diff --git a/linkerd2-proxy/Cargo.toml b/linkerd2-proxy/Cargo.toml index 8b3af75ab7..adf86edf03 100644 --- a/linkerd2-proxy/Cargo.toml +++ b/linkerd2-proxy/Cargo.toml @@ -18,14 +18,19 @@ pprof = ["linkerd-app/pprof"] [dependencies] futures = { version = "0.3", default-features = false } +lazy_static = "1" num_cpus = { version = "1", optional = true } +tokio = { version = "1", features = ["rt", "time", "net"] } +tracing = "0.1" + linkerd-app = { path = "../linkerd/app" } # We don't actually use code from this crate in `main`; it's here only so we can # control its feature flags. linkerd-meshtls = { path = "../linkerd/meshtls" } linkerd-signal = { path = "../linkerd/signal" } -tokio = { version = "1", features = ["rt", "time", "net"] } -tracing = "0.1" [target.x86_64-unknown-linux-gnu.dependencies] jemallocator = { version = "0.5" } + +[build-dependencies] +semver = "1" diff --git a/linkerd/app/core/build.rs b/linkerd2-proxy/build.rs similarity index 100% rename from linkerd/app/core/build.rs rename to linkerd2-proxy/build.rs diff --git a/linkerd2-proxy/src/main.rs b/linkerd2-proxy/src/main.rs index 2a2a0c7aa2..9c42bf07c3 100644 --- a/linkerd2-proxy/src/main.rs +++ b/linkerd2-proxy/src/main.rs @@ -12,10 +12,7 @@ compile_error!( ); use linkerd_app::{ - core::{ - telemetry::{build_info, StartTime}, - transport::BindTcp, - }, + core::{metrics::prom, transport::BindTcp}, trace, Config, }; use linkerd_signal as signal; @@ -30,9 +27,17 @@ mod rt; const EX_USAGE: i32 = 64; +const VERSION: &str = env!("LINKERD2_PROXY_VERSION"); +const DATE: &str = env!("LINKERD2_PROXY_BUILD_DATE"); +const VENDOR: &str = env!("LINKERD2_PROXY_VENDOR"); +const GIT_SHA: &str = env!("GIT_SHA"); +const PROFILE: &str = env!("PROFILE"); + fn main() { - let start_time = StartTime::now(); - let trace = match trace::Settings::from_env(start_time.into()).init() { + PROXY_BUILD_INFO.set(1.0); + prom::register_uptime_collector().expect("uptime collector must be valid"); + + let trace = match trace::Settings::from_env(time::Instant::now()).init() { Ok(t) => t, Err(e) => { eprintln!("Invalid logging configuration: {}", e); @@ -40,14 +45,7 @@ fn main() { } }; - info!( - "{profile} {version} ({sha}) by {vendor} on {date}", - date = build_info::DATE, - sha = build_info::GIT_SHA, - version = build_info::VERSION, - profile = build_info::PROFILE, - vendor = build_info::VENDOR, - ); + info!("{PROFILE} {VERSION} ({GIT_SHA}) by {VENDOR} on {DATE}",); // Load configuration from the environment without binding ports. let config = match Config::try_from_env() { @@ -67,14 +65,7 @@ fn main() { let bind = BindTcp::with_orig_dst(); let app = match config - .build( - bind, - bind, - BindTcp::default(), - shutdown_tx, - trace, - start_time, - ) + .build(bind, bind, BindTcp::default(), shutdown_tx, trace) .await { Ok(app) => app, @@ -141,3 +132,18 @@ fn main() { } }); } + +lazy_static::lazy_static! { + static ref PROXY_BUILD_INFO: prom::Gauge = prom::register_gauge!(prom::opts!( + "proxy_build_info", + "Proxy build info", + prom::labels! { + "version" => VERSION, + "git_sha" => GIT_SHA, + "profile" => PROFILE, + "date" => DATE, + "vendor" => VENDOR, + } + )) + .unwrap(); +}