Skip to content

Commit 09deb54

Browse files
palindrom615claude
andcommitted
docs: add comprehensive rustdoc documentation for OpenTelemetry exporter
Add detailed documentation following patterns from other metrics exporters: - Module-level overview with features, usage examples, and performance notes - Comprehensive API documentation for OpenTelemetryRecorder - Detailed method docs with examples and behavioral constraints - Internal type documentation for MetricDescription and MetricMetadata - Missing docs enforcement and broken link detection 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 878c999 commit 09deb54

File tree

3 files changed

+134
-69
lines changed

3 files changed

+134
-69
lines changed
Lines changed: 85 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,100 @@
11
# metrics-exporter-opentelemetry
22

3-
[![Documentation](https://docs.rs/metrics-exporter-opentelemetry/badge.svg)](https://docs.rs/metrics-exporter-opentelemetry)
3+
[![docs-badge][docs-badge]][docs] [![crates-badge][crates-badge]][crates] [![license-badge][license-badge]][license]
44

5-
A [`metrics`][metrics] exporter for [OpenTelemetry].
5+
[docs-badge]: https://docs.rs/metrics-exporter-opentelemetry/badge.svg
6+
[docs]: https://docs.rs/metrics-exporter-opentelemetry
7+
[crates-badge]: https://img.shields.io/crates/v/metrics-exporter-opentelemetry.svg
8+
[crates]: https://crates.io/crates/metrics-exporter-opentelemetry
9+
[license-badge]: https://img.shields.io/crates/l/metrics-exporter-opentelemetry.svg
10+
[license]: #license
11+
12+
A [`metrics`]-compatible exporter for sending metrics to OpenTelemetry collectors.
13+
14+
[`metrics`]: https://docs.rs/metrics/
15+
16+
## Overview
17+
18+
A [`metrics`]-compatible exporter for OpenTelemetry collectors and OTLP endpoints.
619

720
## Features
821

9-
- Export metrics to OpenTelemetry collectors using OTLP
10-
- Support for counters, gauges, and histograms
11-
- Integration with the OpenTelemetry SDK
12-
- Configurable export intervals and endpoints
22+
- Counters, gauges, and histograms
23+
- Custom histogram bucket boundaries
24+
- Metric descriptions and units
25+
- Lock-free concurrent data structures
26+
- Works with any OpenTelemetry [`Meter`]
27+
28+
[`Meter`]: https://docs.rs/opentelemetry/latest/opentelemetry/metrics/trait.Meter.html
29+
30+
## Quick Start
1331

14-
## Usage
32+
Add this to your `Cargo.toml`:
33+
34+
```toml
35+
[dependencies]
36+
metrics = "0.24"
37+
metrics-exporter-opentelemetry = "0.1"
38+
opentelemetry = "0.30"
39+
opentelemetry_sdk = "0.30"
40+
```
41+
42+
Basic usage:
1543

1644
```rust
17-
use metrics::{counter, gauge, histogram};
18-
use metrics_exporter_opentelemetry::OpenTelemetryBuilder;
19-
use opentelemetry_otlp::WithExportConfig;
20-
use opentelemetry_sdk::{
21-
metrics::{PeriodicReader, SdkMeterProvider},
22-
runtime,
23-
};
24-
25-
// Configure OpenTelemetry exporter
26-
let exporter = opentelemetry_otlp::MetricExporter::builder()
27-
.with_tonic()
28-
.with_endpoint("http://localhost:4317")
29-
.build()?;
30-
31-
// Create a periodic reader
32-
let reader = PeriodicReader::builder(exporter, runtime::Tokio)
33-
.with_interval(Duration::from_secs(10))
34-
.build();
35-
36-
// Build the meter provider
37-
let provider = SdkMeterProvider::builder()
38-
.with_reader(reader)
39-
.build();
40-
41-
// Install the metrics exporter
42-
OpenTelemetryBuilder::new()
43-
.with_meter_provider(provider)
44-
.install()?;
45-
46-
// Now you can use the metrics macros
47-
counter!("requests_total").increment(1);
48-
gauge!("cpu_usage").set(0.75);
49-
histogram!("request_duration").record(0.234);
45+
use metrics_exporter_opentelemetry::OpenTelemetryRecorder;
46+
use opentelemetry::metrics::MeterProvider;
47+
use opentelemetry_sdk::metrics::SdkMeterProvider;
48+
49+
// Create an OpenTelemetry meter
50+
let provider = SdkMeterProvider::default();
51+
let meter = provider.meter("my_application");
52+
53+
// Create and install the recorder
54+
let recorder = OpenTelemetryRecorder::new(meter);
55+
metrics::set_global_recorder(recorder).expect("failed to install recorder");
56+
57+
// Use metrics as normal
58+
metrics::counter!("requests_total", "method" => "GET").increment(1);
59+
metrics::gauge!("cpu_usage", "core" => "0").set(45.2);
60+
metrics::histogram!("response_time", "endpoint" => "/api/users").record(0.123);
5061
```
5162

52-
## Examples
63+
## Custom Histogram Boundaries
64+
65+
```rust
66+
let recorder = OpenTelemetryRecorder::new(meter);
5367

54-
- [`opentelemetry_push`](examples/opentelemetry_push.rs): Demonstrates exporting metrics to an OpenTelemetry collector
55-
- [`opentelemetry_stdout`](examples/opentelemetry_stdout.rs): Shows metrics export to stdout for debugging
68+
recorder.set_histogram_bounds(
69+
&metrics::KeyName::from("response_time"),
70+
vec![0.001, 0.005, 0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0]
71+
);
72+
73+
metrics::set_global_recorder(recorder).expect("failed to install recorder");
74+
```
75+
76+
## Metric Descriptions and Units
77+
78+
You can provide descriptions and units for your metrics using the `describe_*` macros.
79+
80+
CAUTION: These macros must be called before the metrics are recorded. The instruments created before calling these macros will not have descriptions or units.
81+
82+
```rust
83+
use metrics::{describe_counter, describe_histogram, Unit};
84+
85+
describe_counter!("requests_total", Unit::Count, "Total HTTP requests");
86+
describe_histogram!("response_time", Unit::Seconds, "Response time distribution");
87+
88+
metrics::counter!("requests_total").increment(1);
89+
metrics::histogram!("response_time").record(0.045);
90+
```
5691

57-
## License
92+
## Compatibility
5893

59-
This project is licensed under the MIT license.
94+
### Metric Type Mapping
6095

61-
[metrics]: https://github.com/metrics-rs/metrics
62-
[OpenTelemetry]: https://opentelemetry.io/
96+
| `metrics` Type | OpenTelemetry Instrument |
97+
|----------------|-------------------------|
98+
| `Counter` | `ObservableCounter` (u64) |
99+
| `Gauge` | `ObservableGauge` (f64) |
100+
| `Histogram` | `Histogram` (f64) |

metrics-exporter-opentelemetry/src/lib.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
//! An OpenTelemetry metrics exporter for `metrics`.
1+
#![doc = include_str!("../README.md")]
2+
#![cfg_attr(docsrs, feature(doc_cfg), deny(rustdoc::broken_intra_doc_links))]
3+
#![deny(missing_docs)]
4+
25
mod instruments;
36
mod metadata;
47
mod storage;
@@ -10,7 +13,19 @@ use metrics_util::registry::Registry;
1013
use metrics_util::MetricKind;
1114
use opentelemetry::metrics::Meter;
1215

13-
/// The OpenTelemetry recorder.
16+
/// A [`Recorder`] that exports metrics to OpenTelemetry.
17+
///
18+
/// ```rust,no_run
19+
/// use opentelemetry::metrics::MeterProvider;
20+
/// use metrics_exporter_opentelemetry::OpenTelemetryRecorder;
21+
/// use opentelemetry_sdk::metrics::SdkMeterProvider;
22+
///
23+
/// let provider = SdkMeterProvider::default();
24+
/// let meter = provider.meter("my_app");
25+
/// let recorder = OpenTelemetryRecorder::new(meter);
26+
///
27+
/// metrics::set_global_recorder(recorder).expect("failed to install recorder");
28+
/// ```
1429
pub struct OpenTelemetryRecorder {
1530
registry: Registry<Key, OtelMetricStorage>,
1631
metadata: MetricMetadata,
@@ -21,20 +36,17 @@ impl OpenTelemetryRecorder {
2136
pub fn new(meter: Meter) -> Self {
2237
let metadata = MetricMetadata::new();
2338
let storage = OtelMetricStorage::new(meter, metadata.clone());
24-
Self {
25-
registry: Registry::new(storage),
26-
metadata,
27-
}
39+
Self { registry: Registry::new(storage), metadata }
2840
}
2941

30-
pub fn set_histogram_bounds(
31-
&self,
32-
key: &KeyName,
33-
bounds: Vec<f64>,
34-
) {
42+
/// Sets custom bucket boundaries for a histogram metric.
43+
///
44+
/// Must be called before the histogram is first created. Boundaries cannot be
45+
/// changed after a histogram has been created.
46+
pub fn set_histogram_bounds(&self, key: &KeyName, bounds: Vec<f64>) {
3547
self.metadata.set_histogram_bounds(key.clone(), bounds);
3648
}
37-
49+
3850
/// Gets a description entry for testing purposes.
3951
#[cfg(test)]
4052
pub fn get_description(

metrics-exporter-opentelemetry/src/metadata.rs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,41 @@ use metrics_util::MetricKind;
33
use scc::HashMap;
44
use std::sync::Arc;
55

6+
/// A metric description containing unit and textual description.
7+
///
8+
/// This structure holds the metadata associated with a metric, including its unit of
9+
/// measurement and human-readable description. This information is used to enrich
10+
/// the OpenTelemetry metric output.
611
#[derive(Clone)]
712
pub struct MetricDescription {
13+
/// The unit of measurement for this metric (e.g., bytes, seconds, count)
814
unit: Option<Unit>,
15+
/// Human-readable description of what this metric measures
916
description: SharedString,
1017
}
1118

1219
impl MetricDescription {
20+
/// Returns the unit of measurement for this metric.
1321
pub fn unit(&self) -> Option<Unit> {
1422
self.unit
1523
}
16-
24+
25+
/// Returns the human-readable description of this metric.
1726
pub fn description(&self) -> SharedString {
1827
self.description.clone()
1928
}
2029
}
2130

22-
/// Stores all metric metadata including descriptions and histogram bounds
31+
/// Stores all metric metadata including descriptions and histogram bounds.
32+
///
33+
/// This structure maintains a centralized store of metadata for all metrics, providing
34+
/// lock-free concurrent access through SCC (Scalable Concurrent Collections) HashMaps.
35+
/// It stores both metric descriptions (with units) and custom histogram bucket boundaries.
36+
///
37+
/// # Thread Safety
38+
///
39+
/// This structure is designed for high-performance concurrent access. Multiple threads
40+
/// can safely read and write metadata simultaneously with minimal contention.
2341
#[derive(Clone, Default)]
2442
pub struct MetricMetadata {
2543
descriptions: Arc<HashMap<(KeyName, MetricKind), MetricDescription>>,
@@ -28,12 +46,9 @@ pub struct MetricMetadata {
2846

2947
impl MetricMetadata {
3048
pub fn new() -> Self {
31-
Self {
32-
descriptions: Arc::new(HashMap::new()),
33-
histogram_bounds: Arc::new(HashMap::new()),
34-
}
49+
Self { descriptions: Arc::new(HashMap::new()), histogram_bounds: Arc::new(HashMap::new()) }
3550
}
36-
51+
3752
pub fn set_description(
3853
&self,
3954
key_name: KeyName,
@@ -44,19 +59,19 @@ impl MetricMetadata {
4459
let new_entry = MetricDescription { unit, description };
4560
let _ = self.descriptions.insert((key_name, metric_kind), new_entry);
4661
}
47-
62+
4863
pub fn get_description(
4964
&self,
5065
key_name: &KeyName,
5166
metric_kind: MetricKind,
5267
) -> Option<MetricDescription> {
5368
self.descriptions.read(&(key_name.clone(), metric_kind), |_, v| v.clone())
5469
}
55-
70+
5671
pub fn set_histogram_bounds(&self, key_name: KeyName, bounds: Vec<f64>) {
5772
let _ = self.histogram_bounds.insert(key_name, bounds);
5873
}
59-
74+
6075
pub fn get_histogram_bounds(&self, key_name: &KeyName) -> Option<Vec<f64>> {
6176
self.histogram_bounds.read(key_name, |_, v| v.clone())
6277
}

0 commit comments

Comments
 (0)