use crate::error::Result;
use opentelemetry::KeyValue;
use opentelemetry::metrics::{Counter, Histogram, Meter, UpDownCounter};
pub struct RasterMetrics {
pub read_count: Counter<u64>,
pub read_duration: Histogram<f64>,
pub read_bytes: Counter<u64>,
pub write_count: Counter<u64>,
pub write_duration: Histogram<f64>,
pub write_bytes: Counter<u64>,
pub reproject_count: Counter<u64>,
pub reproject_duration: Histogram<f64>,
pub resample_count: Counter<u64>,
pub resample_duration: Histogram<f64>,
pub warp_count: Counter<u64>,
pub warp_duration: Histogram<f64>,
pub compress_count: Counter<u64>,
pub compress_duration: Histogram<f64>,
pub compress_ratio: Histogram<f64>,
pub decompress_count: Counter<u64>,
pub decompress_duration: Histogram<f64>,
pub band_read_count: Counter<u64>,
pub band_read_duration: Histogram<f64>,
pub band_write_count: Counter<u64>,
pub band_write_duration: Histogram<f64>,
pub tile_count: Counter<u64>,
pub tile_generation_duration: Histogram<f64>,
pub tile_cache_hits: Counter<u64>,
pub tile_cache_misses: Counter<u64>,
pub overview_count: Counter<u64>,
pub overview_generation_duration: Histogram<f64>,
pub active_rasters: UpDownCounter<i64>,
pub raster_width: Histogram<f64>,
pub raster_height: Histogram<f64>,
pub raster_bands: Histogram<f64>,
pub raster_size_bytes: Histogram<f64>,
}
impl RasterMetrics {
pub fn new(meter: Meter) -> Result<Self> {
Ok(Self {
read_count: meter
.u64_counter("oxigdal.raster.read.count")
.with_description("Number of raster read operations")
.build(),
read_duration: meter
.f64_histogram("oxigdal.raster.read.duration")
.with_description("Duration of raster read operations in milliseconds")
.build(),
read_bytes: meter
.u64_counter("oxigdal.raster.read.bytes")
.with_description("Bytes read from raster")
.build(),
write_count: meter
.u64_counter("oxigdal.raster.write.count")
.with_description("Number of raster write operations")
.build(),
write_duration: meter
.f64_histogram("oxigdal.raster.write.duration")
.with_description("Duration of raster write operations in milliseconds")
.build(),
write_bytes: meter
.u64_counter("oxigdal.raster.write.bytes")
.with_description("Bytes written to raster")
.build(),
reproject_count: meter
.u64_counter("oxigdal.raster.reproject.count")
.with_description("Number of raster reprojection operations")
.build(),
reproject_duration: meter
.f64_histogram("oxigdal.raster.reproject.duration")
.with_description("Duration of raster reprojection in milliseconds")
.build(),
resample_count: meter
.u64_counter("oxigdal.raster.resample.count")
.with_description("Number of raster resample operations")
.build(),
resample_duration: meter
.f64_histogram("oxigdal.raster.resample.duration")
.with_description("Duration of raster resample in milliseconds")
.build(),
warp_count: meter
.u64_counter("oxigdal.raster.warp.count")
.with_description("Number of raster warp operations")
.build(),
warp_duration: meter
.f64_histogram("oxigdal.raster.warp.duration")
.with_description("Duration of raster warp in milliseconds")
.build(),
compress_count: meter
.u64_counter("oxigdal.raster.compress.count")
.with_description("Number of raster compression operations")
.build(),
compress_duration: meter
.f64_histogram("oxigdal.raster.compress.duration")
.with_description("Duration of raster compression in milliseconds")
.build(),
compress_ratio: meter
.f64_histogram("oxigdal.raster.compress.ratio")
.with_description("Compression ratio achieved")
.build(),
decompress_count: meter
.u64_counter("oxigdal.raster.decompress.count")
.with_description("Number of raster decompression operations")
.build(),
decompress_duration: meter
.f64_histogram("oxigdal.raster.decompress.duration")
.with_description("Duration of raster decompression in milliseconds")
.build(),
band_read_count: meter
.u64_counter("oxigdal.raster.band.read.count")
.with_description("Number of band read operations")
.build(),
band_read_duration: meter
.f64_histogram("oxigdal.raster.band.read.duration")
.with_description("Duration of band read in milliseconds")
.build(),
band_write_count: meter
.u64_counter("oxigdal.raster.band.write.count")
.with_description("Number of band write operations")
.build(),
band_write_duration: meter
.f64_histogram("oxigdal.raster.band.write.duration")
.with_description("Duration of band write in milliseconds")
.build(),
tile_count: meter
.u64_counter("oxigdal.raster.tile.count")
.with_description("Number of tiles generated")
.build(),
tile_generation_duration: meter
.f64_histogram("oxigdal.raster.tile.generation.duration")
.with_description("Duration of tile generation in milliseconds")
.build(),
tile_cache_hits: meter
.u64_counter("oxigdal.raster.tile.cache.hits")
.with_description("Number of tile cache hits")
.build(),
tile_cache_misses: meter
.u64_counter("oxigdal.raster.tile.cache.misses")
.with_description("Number of tile cache misses")
.build(),
overview_count: meter
.u64_counter("oxigdal.raster.overview.count")
.with_description("Number of overviews generated")
.build(),
overview_generation_duration: meter
.f64_histogram("oxigdal.raster.overview.generation.duration")
.with_description("Duration of overview generation in milliseconds")
.build(),
active_rasters: meter
.i64_up_down_counter("oxigdal.raster.active")
.with_description("Number of active raster datasets")
.build(),
raster_width: meter
.f64_histogram("oxigdal.raster.width")
.with_description("Raster width in pixels")
.build(),
raster_height: meter
.f64_histogram("oxigdal.raster.height")
.with_description("Raster height in pixels")
.build(),
raster_bands: meter
.f64_histogram("oxigdal.raster.bands")
.with_description("Number of raster bands")
.build(),
raster_size_bytes: meter
.f64_histogram("oxigdal.raster.size.bytes")
.with_description("Raster size in bytes")
.build(),
})
}
pub fn record_read(&self, duration_ms: f64, bytes: u64, format: &str, success: bool) {
let attrs = vec![
KeyValue::new("format", format.to_string()),
KeyValue::new("success", success),
];
self.read_count.add(1, &attrs);
self.read_duration.record(duration_ms, &attrs);
if success {
self.read_bytes.add(bytes, &attrs);
}
}
pub fn record_write(&self, duration_ms: f64, bytes: u64, format: &str, success: bool) {
let attrs = vec![
KeyValue::new("format", format.to_string()),
KeyValue::new("success", success),
];
self.write_count.add(1, &attrs);
self.write_duration.record(duration_ms, &attrs);
if success {
self.write_bytes.add(bytes, &attrs);
}
}
pub fn record_reproject(&self, duration_ms: f64, from_srs: &str, to_srs: &str, success: bool) {
let attrs = vec![
KeyValue::new("from_srs", from_srs.to_string()),
KeyValue::new("to_srs", to_srs.to_string()),
KeyValue::new("success", success),
];
self.reproject_count.add(1, &attrs);
self.reproject_duration.record(duration_ms, &attrs);
}
pub fn record_compress(
&self,
duration_ms: f64,
original_size: u64,
compressed_size: u64,
algorithm: &str,
success: bool,
) {
let attrs = vec![
KeyValue::new("algorithm", algorithm.to_string()),
KeyValue::new("success", success),
];
self.compress_count.add(1, &attrs);
self.compress_duration.record(duration_ms, &attrs);
if success && original_size > 0 {
let ratio = compressed_size as f64 / original_size as f64;
self.compress_ratio.record(ratio, &attrs);
}
}
pub fn record_tile_cache_hit(&self, zoom: u32) {
let attrs = vec![KeyValue::new("zoom", zoom as i64)];
self.tile_cache_hits.add(1, &attrs);
}
pub fn record_tile_cache_miss(&self, zoom: u32) {
let attrs = vec![KeyValue::new("zoom", zoom as i64)];
self.tile_cache_misses.add(1, &attrs);
}
pub fn inc_active_rasters(&self) {
self.active_rasters.add(1, &[]);
}
pub fn dec_active_rasters(&self) {
self.active_rasters.add(-1, &[]);
}
pub fn record_dimensions(&self, width: u32, height: u32, bands: u32) {
let attrs = vec![KeyValue::new("operation", "open")];
self.raster_width.record(width as f64, &attrs);
self.raster_height.record(height as f64, &attrs);
self.raster_bands.record(bands as f64, &attrs);
}
}
#[cfg(test)]
mod tests {
use super::*;
use opentelemetry::global;
#[test]
fn test_raster_metrics_creation() {
let meter = global::meter("test");
let metrics = RasterMetrics::new(meter);
assert!(metrics.is_ok());
}
}