diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/config.rs | 57 | ||||
| -rw-r--r-- | src/main.rs | 74 |
2 files changed, 129 insertions, 2 deletions
diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..153c170 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,57 @@ +use std::sync::LazyLock; + +use anyhow::Result; +use confique::Config; +use opentelemetry_otlp::Protocol; + +#[derive(Config)] +pub struct CspyConfig { + #[config(env = "CSPY_DOCKER_SOCKET")] + pub docker_socket: Option<String>, + + #[config(env = "CSPY_OTLP_PROTO", default = "httpbinary", deserialize_with = crate::config::deser_protocol)] + pub otlp_protocol: Protocol, + + #[config(env = "CSPY_OTLP_ENDPOINT")] + pub otlp_endpoint: Option<String>, +} + +pub static CONFIG: LazyLock<CspyConfig> = LazyLock::new(|| { + let cfg_loc = std::env::var("CSPY_CONFIG"); + let cfg_loc = cfg_loc.as_deref().ok().unwrap_or(&"/etc/containerspy/config.json"); + + CspyConfig::builder() + .env() + .file(cfg_loc) + .load() + .unwrap() +}); + + +/// deserialization boilerplate +struct ProtoDeserVisitor; + +/// deserialization boilerplate +impl<'de> confique::serde::de::Visitor<'de> for ProtoDeserVisitor { + type Value = Protocol; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str(r#""httpbinary", "httpjson", or "grpc"."#) + } + + fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E> + where + E: confique::serde::de::Error, { + Ok(match v { + "httpbinary" => Protocol::HttpBinary, + "httpjson" => Protocol::HttpJson, + "grpc" => Protocol::Grpc, + &_ => return Err(E::custom(format!("{v} is not a valid OTLP protocol, valid options are httpbinary, httpjson, or grpc."))) + }) + } +} + +/// deserialization boilerplate +fn deser_protocol<'de, D: confique::serde::Deserializer<'de>>(d: D) -> Result<Protocol, D::Error> { + d.deserialize_str(ProtoDeserVisitor) +} diff --git a/src/main.rs b/src/main.rs index e7a11a9..3e1b75c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,73 @@ -fn main() { - println!("Hello, world!"); +use std::time::Duration; + +use anyhow::Result; +use bollard::Docker; +use config::CONFIG; +use opentelemetry::{metrics::MeterProvider, KeyValue}; +use opentelemetry_otlp::{MetricExporter, Protocol, WithExportConfig}; +use opentelemetry_sdk::{metrics::SdkMeterProvider, Resource}; + +mod config; + +#[tokio::main(flavor = "current_thread")] +async fn main() -> Result<()> { + /* // open a docker connection + let docker = + if let Some(path) = &CONFIG.docker_socket { + Docker::connect_with_socket(path, 60, bollard::API_DEFAULT_VERSION)? + } + else { + Docker::connect_with_local_defaults()? + }; + + let info = docker.info().await?; + + println!("Connected to Docker Daemon version {:?}", info.server_version); */ + + // connect the OTLP exporter + let metric_exporter = + match CONFIG.otlp_protocol { + Protocol::HttpBinary | Protocol::HttpJson => { + let builder = MetricExporter::builder().with_http().with_protocol(CONFIG.otlp_protocol); + let builder = + if let Some(e) = &CONFIG.otlp_endpoint { + println!("{e}"); + builder.with_endpoint(e) + } else { + builder + }; + + builder.build()? + }, + Protocol::Grpc => { + let builder = MetricExporter::builder().with_tonic().with_protocol(Protocol::Grpc); + + let builder = + if let Some(e) = &CONFIG.otlp_endpoint { + builder.with_endpoint(e.as_str()) + } else { + builder + }; + + builder.build()? + }, + }; + + //let test_resource = Resource::builder().with_service_name("containerspy").build(); + + let meter_provider = SdkMeterProvider::builder() + //.with_resource(test_resource) + //.with_periodic_exporter(opentelemetry_stdout::MetricExporter::default()) + .with_periodic_exporter(metric_exporter) + .build(); + + let m = meter_provider + .meter("test_meter") + .u64_gauge("testing_gauge") + .build(); + + m.record(10, &[KeyValue::new("label", 4)]); + + + Ok(()) } |
