opentelemetry-rust icon indicating copy to clipboard operation
opentelemetry-rust copied to clipboard

Add default attributes for each metrics

Open r12f opened this issue 2 years ago • 2 comments

Hi, is there a way we could give each metrics a list of default attributes?

Take the hyper-prometheus as an example. It contains the 3 metrics below.

Code: https://github.com/open-telemetry/opentelemetry-rust/blob/main/examples/hyper-prometheus/src/main.rs

    let state = Arc::new(AppState {
        exporter,
        http_counter: meter
            .u64_counter("example.http_requests_total")
            .with_description("Total number of HTTP requests made.")
            .init(),
        http_body_gauge: meter
            .u64_histogram("example.http_response_size_bytes")
            .with_description("The metrics HTTP response sizes in bytes.")
            .init(),
        http_req_histogram: meter
            .f64_histogram("example.http_request_duration_seconds")
            .with_description("The HTTP request latencies in seconds.")
            .init(),
    });

And say, we would like to log the server location, tenant name, service name, and url for each metrics, which they first 3 are always the same for all metrics, while the url is the only one that changes. However, we will have to do this in every request call, which can be annoying to write, yet have to create/copy the data every time. We can make some helper functions to simplify the code a bit,, but still it will need to copy the strings around.

state.http_counter.add(&cx, 1, &[
    KeyValue { key: "Region".into(), Value: "West US".into() }, // In real case, this might be passed in as String, so we will need to copy here.
    KeyValue { key: "Tenant".into(), Value: "My Deployment".into() },
    KeyValue { key: "Service".into(), Value: "My Service".into() },
    KeyValue { key: "Url".into(), Value: "/foo".into() }, // or /bar, or something, depends on what request it is.
]);
......

state.http_req_histogram.record(
    &cx,
    request_start.elapsed().map_or(0.0, |d| d.as_secs_f64()),
    &[
        KeyValue { key: "Region".into(), value: "West US".into() },
        KeyValue { key: "Tenant".into(), value: "My Deployment".into() },
        KeyValue { key: "Service".into(), value: "My Service".into() },
        KeyValue { key: "Url".into(), value: "/foo".into() }, // or /bar, or something, depends on what request it is.
    ],
);
......

So I wonder if we could create 2 new things to passing the default attributes:

  • When creating Meter, we can add a list of default attributes that shares by all metrics.
  • When calling meter to create metrics, we can add the extra default attributes for each metrics.

r12f avatar Sep 24 '22 17:09 r12f

I think we can add attributes in get_meter function in MeterProvider, which is introduced in 1.13. s

[since 1.13.0] attributes (optional): Specifies the instrumentation scope attributes to associate with emitted telemetry.

TommyCpp avatar Sep 26 '22 07:09 TommyCpp

Thanks for helping, @TommyCpp ! and do you mean this MeterProvider: https://docs.rs/opentelemetry/latest/opentelemetry/metrics/trait.MeterProvider.html ? I did some search, I found this function in python open telemetry API, but not rust. but maybe I am not looking at the right place.

And later I found we can use promethues::Registry::new_custom function to create a registry with customized attributes, and register it to the exporter. However, it only allow us to add a set of global common attributes, but we could add attributes when creating the meters.

r12f avatar Sep 27 '22 06:09 r12f

d do you mean this MeterProvider: https://docs.rs/opentelemetry/latest/opentelemetry/metrics/trait.MeterProvider.html

Yeah, we are still working on bringing some new parameters to the MeterProvider so you can expect to have such ability on the next release. I will link the PR once it finishes

TommyCpp avatar Oct 02 '22 20:10 TommyCpp

Woot! This is an awesome news! Thanks a lot!!

r12f avatar Oct 02 '22 23:10 r12f

#815 has been released in #1156

jtescher avatar Jul 30 '23 16:07 jtescher

And say, we would like to log the server location, tenant name, service name, and url for each metrics, which they first 3 are always the same for all metrics, while the url is the only one that changes

tenant name, service name, and url -- These should be modelled as Resource in OpenTelemetry @r12f FYI.

cijothomas avatar Aug 18 '23 14:08 cijothomas

How does it work now?

benkeil avatar Feb 21 '24 20:02 benkeil

How does it work now?

can you clarify which part are you asking about? InstrumentationScope support is already added (This can be thought of attributes for Meter, so applies to all instruments created from that Meter). Resource support is already added (applied to entire MeterProvider.)

Unfortunately, the docs are not so much explicit about this, and neither are the examples :( I'll address that soon.

cijothomas avatar Feb 21 '24 20:02 cijothomas

pub fn init_meter(registry: &Registry) -> Result<Meter, ControllerError> {
    let exporter = opentelemetry_prometheus::exporter()
        .with_registry(registry.clone())
        .build()
        .map_err(|_| ControllerError::ConfigurationError)?;

    let provider = MeterProvider::builder().with_reader(exporter).build();

    // Ok(provider.meter("github-operator"))
    Ok(provider.versioned_meter(
        "github-operator",
        Some("0.1.0"),
        Some("0.1.0"),
        Some(vec![
            KeyValue::new(
                "environment".to_string(),
                std::env::var("APP_ENVIRONMENT").unwrap_or("local".into()),
            ),
            KeyValue::new("app".to_string(), "github-operator".to_string()),
        ]),
    ))
}

attributes are ignored:

# HELP operator_results_total reconciliation results of the operator
# TYPE operator_results_total counter
operator_results_total{controller="repository-github-controller",status="ok",otel_scope_name="github-operator",otel_scope_version="0.1.0"} 3
# HELP otel_scope_info Instrumentation Scope metadata
# TYPE otel_scope_info gauge
otel_scope_info{otel_scope_name="github-operator",otel_scope_version="0.1.0"} 1
# HELP target_info Target metadata
# TYPE target_info gauge
target_info{service_name="github-operator",telemetry_sdk_language="rust",telemetry_sdk_name="opentelemetry",telemetry_sdk_version="0.21.2"} 1

benkeil avatar Feb 21 '24 22:02 benkeil

^ Please open a new issue for that, as it seems to be only in the prometheus exporter.

cijothomas avatar Feb 21 '24 22:02 cijothomas

Also, std::env::var("APP_ENVIRONMENT").unwrap_or("local".into()), better fits Resource model, unless it is only applicable to a particular meter!

cijothomas avatar Feb 21 '24 22:02 cijothomas