This commit is contained in:
Šimon Jan Šustek 2023-05-29 23:08:21 +02:00
commit 9cc3781230
9 changed files with 243 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

62
Cargo.lock generated Normal file
View File

@ -0,0 +1,62 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "anyhow"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
[[package]]
name = "ascii"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chunked_transfer"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cca491388666e04d7248af3f60f0c40cfb0991c72205595d7c396e3510207d1a"
[[package]]
name = "httpdate"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "prometheus_gbl_exporter"
version = "0.1.0"
dependencies = [
"anyhow",
"tiny_http",
]
[[package]]
name = "tiny_http"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389915df6413a2e74fb181895f933386023c71110878cd0825588928e64cdc82"
dependencies = [
"ascii",
"chunked_transfer",
"httpdate",
"log",
]

18
Cargo.toml Normal file
View File

@ -0,0 +1,18 @@
[package]
name = "prometheus_gbl_exporter"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tiny_http = "0.12"
anyhow = "1.0.71"
# minimalize size
[profile.release]
strip = true
opt-level = "z"
lto = true
codegen-units = 1
panic = "abort"

1
src/collectors/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod time;

12
src/collectors/time.rs Normal file
View File

@ -0,0 +1,12 @@
use crate::metric::{Metrics, Metric, MType};
use std::time::{SystemTime, UNIX_EPOCH};
pub fn scrape() -> Metrics {
let mut met = Metrics::new();
let start = SystemTime::now();
let since_the_epoch = start
.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
met.metrics.push(Metric::new_val("node_time_seconds", MType::Gauge, since_the_epoch.as_secs() as f64));
return met
}

7
src/collectors/uname.rs Normal file
View File

@ -0,0 +1,7 @@
use crate::metric::{Metrics, Metric, MType};
pub fn scrape() -> Metrics {
let mut met = Metrics::new();
met.metrics.push(Metric::new_val("node_time_seconds", MType::Gauge, since_the_epoch.as_secs() as f64));
return met
}

0
src/collectors/wifi.rs Normal file
View File

32
src/main.rs Normal file
View File

@ -0,0 +1,32 @@
mod metric;
mod collectors;
use tiny_http::{Server, Response, Method};
use anyhow::{Context, Result};
use collectors::time;
fn main() -> Result<()> {
let server = Server::http("0.0.0.0:9100").unwrap();
for request in server.incoming_requests() {
if request.method() != &Method::Get || request.url() != "/metrics" {
let response = Response::from_string("Not Found").with_status_code(404);
request.respond(response)?;
continue;
}
println!("request! method: {:?}, url: {:?}, headers: {:?}",
request.method(),
request.url(),
request.headers()
);
let mut output = String::new();
output.push_str(&time::scrape().prometheus());
let response = Response::from_string(output);
request.respond(response)?;
}
Ok(())
}

110
src/metric.rs Normal file
View File

@ -0,0 +1,110 @@
pub enum MType {
Gauge,
Counter,
}
impl std::fmt::Display for MType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
MType::Gauge => write!(f, "gauge"),
MType::Counter => write!(f, "counter")
}
}
}
struct MetricLabel {
label: String,
value: String,
}
impl MetricLabel {
fn prometheus(&self) -> String {
return format!("{}=\"{}\"", self.label, self.value)
}
}
struct MetricData {
labels: Vec<MetricLabel>,
value: f64
}
impl MetricData {
fn new(value: f64) -> MetricData {
return MetricData {
labels: Vec::new(),
value: value,
};
}
fn add_label(&mut self, label: String, value: String) {
self.labels.push(MetricLabel{label: label, value: value})
}
fn rounded_val(&self) -> String {
if self.value.fract() == 0.0 {
return (self.value.trunc() as i64).to_string();
}
return self.value.to_string();
}
}
pub struct Metric {
name: String,
mtype: MType,
data: Vec<MetricData>
}
impl Metric {
pub fn new(name: &str, mtype: MType) -> Metric {
return Metric {
name: String::from(name),
mtype: mtype,
data: Vec::new()
};
}
pub fn new_val(name: &str, mtype: MType, value: f64) -> Metric {
return Metric {
name: String::from(name),
mtype: mtype,
data: vec![MetricData::new(value)]
};
}
}
pub struct Metrics {
pub metrics: Vec<Metric>,
pub processtime: f64
}
impl Metrics {
pub fn prometheus(&self) -> String {
let mut type_section = String::new();
let mut metric_section = String::new();
for m in &self.metrics {
type_section.push_str(&format!("# TYPE {} {}\n", m.name, m.mtype));
for d in &m.data {
let mut labels = String::new();
for (i, l) in d.labels.iter().enumerate() {
labels.push_str(&l.prometheus());
if i != d.labels.len()-1 {
labels.push(',')
}
}
if labels.is_empty() {
metric_section.push_str(&format!("{} {}\n", m.name, d.rounded_val()));
} else {
metric_section.push_str(&format!("{}{{{}}} {}\n", m.name, labels, d.rounded_val()));
}
}
}
return type_section+&metric_section;
}
pub fn new() -> Metrics {
return Metrics {
metrics: Vec::new(),
processtime: 0.0
};
}
}