GithubHelp home page GithubHelp logo

prometheus / client_rust Goto Github PK

View Code? Open in Web Editor NEW
428.0 8.0 63.0 318 KB

Prometheus / OpenMetrics client library in Rust

License: Apache License 2.0

Rust 100.00%
openmetrics metrics prometheus instrumentation monitoring

client_rust's Introduction

Prometheus Rust client library

Test Status Crate API

Rust client library implementation of the Open Metrics specification. Allows developers to instrument applications and thus enables operators to monitor said applications with monitoring systems like Prometheus.

Documentation: https://docs.rs/prometheus-client/

Goals

  • No unsafe. Don't use unsafe Rust within the library itself.

  • Type safe. Leverage Rust's type system to catch common instrumentation mistakes at compile time.

  • Fast. Don't force users to worry about the performance impact of instrumentation. Instead encourage users to instrument often and extensively.

Specification Compliance

Below is a list of properties where this client library implementation lags behind the Open Metrics specification. Not being compliant with all requirements (MUST and MUST NOT) of the specification is considered a bug and likely to be fixed in the future. Contributions in all forms are most welcome.

  • State set metric.

  • Enforce "A Histogram MetricPoint MUST contain at least one bucket".

  • Enforce "A MetricFamily MUST have a [...] UNIT metadata".

  • Enforce "MetricFamily names [...] MUST be unique within a MetricSet."

  • Enforce "Names SHOULD be in snake_case".

  • Enforce "MetricFamily names beginning with underscores are RESERVED and MUST NOT be used unless specified by this standard".

  • Enforce "Exposers SHOULD avoid names that could be confused with the suffixes that text format sample metric names use".

  • Gauge histogram metric.

  • Allow "A MetricPoint in a Metric with the type [Counter, Histogram] SHOULD have a Timestamp value called Created".

  • Summary metric.

Related Libraries

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

client_rust's People

Contributors

56quarters avatar ackintosh avatar adamchalmers avatar apmasell avatar cheshirskycode avatar chitoku-k avatar decathorpe avatar dependabot[bot] avatar divagant-martian avatar doehyunbaek avatar erenon avatar howardjohn avatar jpds avatar koushiro avatar mozgiii avatar mxinden avatar nox avatar oriontvv avatar phyber avatar popadi avatar prombot avatar sd2k avatar thomaseizinger avatar victor-n-suadicani avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

client_rust's Issues

Custom collector for multiple metrics

Hi! I've been looking at implementing a Prometheus collector for the recently announced tokio-metrics crate. Every scrape, I'd like to gather runtime metrics for the currently Tokio runtime. The problem is that doing so requires a non-trivial amount of up-front work to aggregate all of the stats across the N workers in the runtime, which I'd rather not do during every metric's encode function (following the custom metric example).

Instead I think it'd be ideal if there was a way to do something similar to the client_python Custom Collector example, which allows custom collectors to record values for multiple metrics at each scrape time - that'd avoid me having to duplicate work (non-atomically) on every scrape. Do you think such an API would be possible?

Alternatively if you know of another pattern to get around this, I'd love to hear it!

Allow root registry creation with prefix AND label(s)

As the title says, is it okay to add a constructor (with_prefix_and_labels; please suggest a better name eventually) that allows the creation of a base/root registry with a prefix and some default labels? Or maybe a way to allow the mutation of the labels of a registry.

I have a bunch of counters coming from from processes running on different hosts and I'd like to have them labeled with about 2-3 base/identification labels to be able to query them in my dashboards properly. Due to some restrictions I am not able to inject these labels directly via kubernetes on Prometheus scrape. At the same time, I see no reason TO NOT allow the creation of a registry with default labels.

This is a question related a bit to the previously posted issue (#144) for which I submitted a pull request (#145).

Implement Summary metric

Hi! Thank your for the project :)

I found myself missing an implementation of the Summary metric, so decided to file an issue in case anyone (maybe myself) decides to contribute an implementation.


Open Metrics spec defines a metric type that computes quantiles locally on the client: Summary.

It's quite useful if you want to learn/discover how a system behaves, especially if you don't have much data a-priori. In that sense, Summary is dual to Histogram - both can be used to understand data distribution (e.g. latency data), but with different use-cases and tradeoffs.

Good overview on the differences between Summary and Histogram metrics is given in Prometheus doc https://prometheus.io/docs/practices/histograms/

Allow multiple labels in sub_registry_with_label method

Hey

I have a bunch of counters coming from from processes running on different hosts and I'd like to have them labeled with about 2-3 labels to be able to query them in my dashboards.

Is there a reason sub_registry_with_label accepts a single label? What if I want to add 2-3 labels to a bunch of metrics (globally)?

Consider removing text::Encode in favour of serde::Serialize

Serde's Serialize trait is implemented for dozens of types in the Rust ecosystem, its derive code is fairly well optimised, and it is the most popular serialization framework we have for Rust.

What do you think of removing the Encode trait in favour of Serialize, to get all the nice things there are in Serde for free?

Support deriving metric storage

It would be super useful to have derives for metrics storages, like was done for the prometheus crate (essentially porting https://crates.io/crates/prometheus-metric-storage).

#[derive(prometheus_metric_storage::MetricStorage)]
#[metric(subsystem = "transport", labels("endpoint"))]
struct Metrics {
    /// Number of requests that are currently inflight.
    inflight: prometheus::IntGauge,

    /// Number of finished requests by response code.
    #[metric(labels("status"))]
    requests_finished: prometheus::IntCounterVec,

    /// Number of finished requests by total processing duration.
    #[metric(buckets(0.1, 0.2, 0.5, 1, 2, 4, 8))]
    requests_duration_seconds: prometheus::Histogram,
}

fn main() {
    let metrics = Metrics::new(
        prometheus::default_registry(),
        /* endpoint = */ "0.0.0.0:8080"
    ).unwrap();

    metrics.inflight.inc();
    metrics.requests_finished.with_label_values(&["200"]).inc();
    metrics.requests_duration_seconds.observe(0.015);
}

This would enable to not forget to register metrics that are in a struct into the registry.

src/registry: Consider using Into for metric when registering

With the diff below, one would not need to Box a metric before registering it with a Registry<Box<M>>. The downside is, that it makes it harder for Rust to infer M.

diff --git a/src/lib.rs b/src/lib.rs
index d39b566..d86d2dd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -52,7 +52,7 @@
 //!   "http_requests",
 //!   // And the metric help text.
 //!   "Number of HTTP requests received",
-//!   Box::new(http_requests.clone()),
+//!   http_requests.clone(),
 //! );
 //!
 //! // Somewhere in your business logic record a single HTTP GET request.
diff --git a/src/registry.rs b/src/registry.rs
index be9fd18..3033483 100644
--- a/src/registry.rs
+++ b/src/registry.rs
@@ -97,8 +97,8 @@ impl<M> Registry<M> {
     ///
     /// registry.register("my_counter", "This is my counter", counter.clone());
     /// ```
-    pub fn register<N: Into<String>, H: Into<String>>(&mut self, name: N, help: H, metric: M) {
-        self.priv_register(name, help, metric, None)
+    pub fn register<N: Into<String>, H: Into<String>, IM: Into<M>>(&mut self, name: N, help: H, metric: IM) {
+        self.priv_register(name, help, metric.into(), None)
     }
 
     /// Register a metric with the [`Registry`] specifying the metric's unit.

Add `#[flatten]` directive for derivation of nested structs

Given the structs like:

struct Common {
  field_a: String,
  field_b: String,
  field_c: String
}

#[derive(Encode)]
struct Metric1 {
  unique_field: String
  #[flatten]
  common: Common
}

#[derive(Encode)]
struct Metric2 {
  unique_field_2: String
  #[serde(flatten)]
  common: Common
}

I want the resulting metrics:

metric1{field_a="foo", field_b="bar", field_c="baz",unique_field="something"}
metric2{field_a="foo", field_b="bar", field_c="baz",unique_field_2="something_else"}

(Note: in real world Common and the number of metrics are much larger)

This would match the semantics of serde(flatten)

See #105 (comment) for more discussion

Const Metrics / Custom Collectors

Hi,

Thanks for creating an official Rust crate for Prometheus. :)

I'm wondering how we should handle Const Metrics with this crate. Are these supported at the moment? If they are, it's a little non-obvious.

My use case is for exporting counters from the operating system. The OS itself guarantees that these are always increasing (unless the counter wraps, etc), but they're difficult to export with only the inc and inc_by methods as additional variables must be maintained to work out the difference between the old OS counter and the current OS counter, so we can finally inc_by.

If Const Metrics are not currently supported, please consider this a feature request.

Thanks!

Expensive metric validation in debug mode

When run in debug mode, I think it is worth exploring running different validations on the registered metrics.

Examples:

  • We could make sure a counter name does not end in _total as that is added automatically already.
  • Registry::register could ensure that no duplicate metric names are being registered.
  • Registry::register could ensure that the user did not provide an additional . in the HELP text. See #56

I think a goal worth striving for is keeping the dependency tree small for the sake of compile times.

Allow flattening of a struct through derive(EncodeLabelSet) at any position

Currently when deriving EncodeLabelSet and flattening a struct the flattened struct must appear last, and there must be only one flattened struct, from the test:

#[test]
fn flatten() {
    #[derive(EncodeLabelSet, Hash, Clone, Eq, PartialEq, Debug)]
    struct CommonLabels {
        a: u64,
        b: u64,
    }
    #[derive(EncodeLabelSet, Hash, Clone, Eq, PartialEq, Debug)]
    struct Labels {
        unique: u64,
        #[prometheus(flatten)]
        common: CommonLabels,
    }

    // …

If you place common before unique in struct Labels like this:

#[derive(EncodeLabelSet, Hash, Clone, Eq, PartialEq, Debug)]
struct Labels {
    #[prometheus(flatten)]
    common: CommonLabels,
    unique: u64,
}

Compilation fails:

error[E0382]: borrow of moved value: `encoder`
   --> derive-encode/tests/lib.rs:147:14
    |
147 |     #[derive(EncodeLabelSet, Hash, Clone, Eq, PartialEq, Debug)]
    |              ^^^^^^^^^^^^^^
    |              |
    |              value borrowed here after move
    |              move occurs because `encoder` has type `LabelSetEncoder<'_>`, which does not implement the `Copy` trait
    |

This occurs because ownership of encoder is given to the flattened struct

I think this would be a breaking change to fix, but fixing it would allow fields to appear in any order, or allow flattening of multiple structs without nesting them all one inside the other in tail position.

How to add two different metrics to one register?

let total_bytes: Family<TrafficLabels, Counter> = Family::default();
    let connection_count: Family<ConnectionLabels, Gauge> = Family::default();
    let mut registry = Registry::default();
    registry.register(
        "total_bytes",
        "Accumulated bytes going through sever",
        Box::new(total_bytes.clone()),
    );
    
    registry.register(
        "connection count",
        "Count of current connections",
        Box::new(connection_count.clone()),
    );

results in:

mismatched types
expected struct `Family<TrafficLabels, prometheus_client::metrics::counter::Counter, fn() -> prometheus_client::metrics::counter::Counter>`
   found struct `Family<ConnectionLabels, prometheus_client::metrics::gauge::Gauge, fn() -> prometheus_client::metrics::gauge::Gauge>`rustc[E0308](https://doc.rust-lang.org/error-index.html#E0308)

Does this crate implement Prometheus or OpenMetrics?

There is a relationship between OpenMetrics and Prometheus, but as far as I understand, they are not the same thing, and are definitely not fully compatible with each other.

lib.rs currently states that this repo is a "Client library implementation of the Open Metrics specification".

If that's true, then I propose that this repo should not exist underneath the prometheus GitHub organization. If it will remain in the prometheus org, then I propose that it should change its mandate such that Prometheus compatibility is the first-order goal, and OpenMetrics is a secondary and e.g. nice-to-have goal.

Combining registries?

Is there an elegant way of combining multiple registries in a single encode output?

An example of a use case would be writing an exporter for metrics from an external system, as opposed to the own application's metrics.

The idea is that new metric families would be created and populated on each scrape. But there could also be exporter-related metrics that would be constant between scrapes, such as an info, etc.

One way of doing this right now would be to register the exporter's metrics to a new, per-scrape Registry, together with the scrape metrics and encode that. This approach seems somewhat verbose.

A more ergonomic approach would be for the encode function to take some iterable of Families and encode that, which is basically what the Registry is from its point of view.

Remove impl Add<&Prefix> for String

Because of rust-lang/rust#77143, the impl Add<&Prefix> for String can prevent the compilation of unrelated, previously working programs, if they use string concat. This prevents adding this library to such a project, or prevents adding other deps to a project that already uses prometheus. The resulting error message is also cryptict.

Please consider removing the trait impl, thanks.

exporting metrics lists without registering them

Currently the encoder only supports a single metric. There is no concept like metrics lists.
It's not uncommon that collectors get raw data from their source and generate a list of metrics from that.
Right now it seems like we have to register every metric, but it would be great if we had a way to generate metrics on the fly on every scrape and pass them to the encoder.

Or am I just missing the right module?

Custom encoder?

I would like to send (partial) metrics stored the Registry in original JSON format differ from OpenMetrics, into an endpoint different from Prometheus server.

Here is a pseudo code, shows what I want to do:

        let mut registry = <Registry>::default();

        // (omitted)

        // Using the OpenMetrics format.
        let mut buffer = vec![];
        encode(&mut buffer, &registry).unwrap();

        // On the other hand, send (partial) metrics in JSON, into an endpoint different from Prometheus server.
        let mut data = vec![];
        for (descriptor, metric) in registry.iter() {
            if descriptor.name() == "__test__" {
                data.push(
                    translate_to_json(metric), // original JSON format
                );
            }
        }
        send(data); // send to an endpoint different from Prometheus server

I think I need to implement custom encoder, translate metrics to JSON format.

Please let me know if there is any good way. 🙏

protobuf: Labels duplicate between metrics

Sample code to reproduce an issue:

        let family = Family::<Vec<(String, String)>, Counter>::default();

        // ...

        family
            .get_or_create(&vec![
                ("method".to_string(), "GET".to_string()),
                ("status".to_string(), "200".to_string()),
            ])
            .inc();

        family
            .get_or_create(&vec![
                ("method".to_string(), "POST".to_string()),
                ("status".to_string(), "200".to_string()),
            ])
            .inc();

        let metric_set = prometheus_client::encoding::proto::encode(&registry).unwrap();

Present Behaviour

The encoded counter metrics are:

labels:
* method: GET
* status: 200
value:
* total: 1
labels:
* method: GET
* status: 200
* method: POST
* status: 200
value:
* total: 1

The second metrics above has duplicated labels.

Expected Behaviour

We expect the encoded counter metrics looks like:

labels:
* method: GET
* status: 200
value:
* total: 1
labels:
* method: POST
* status: 200
value:
* total: 1

Additional Info

I have added a test case to reproduce this issue on #123. I was looking into this but couldn't find how to fix. 😓

I saw this issue on protobuf encoding, it might also got on the text encoding.

Allow to optionally specify timestamps

It would be terrific to be able to pass an optional chrono instance as a timestamp to specify the recency of the particular metric. My usecase is a prometheus exporter where the metrics are cached and it would therefore be correct to specify the time of the original retrieval of the metric instead of leaving out the timestamp which implicitly states "now".

Sharing dynamically dispatched registry in web framework state

I may be missing something but it seems like it's not possible to use the Registry with the default M = SendEncodeMetric type as shared state in web frameworks (e.g. tide::with_state), because those require that the state is all Sync but SendEncodeMetric is not Sync. If I update the tide example to use a dynamically dispatched Registry then it fails to compile:

✦ ❯ cargo c --example tide
error[E0277]: `(dyn SendEncodeMetric + 'static)` cannot be shared between threads safely
   --> examples/tide.rs:25:36
    |
25  |       let mut app = tide::with_state(State {
    |  ___________________----------------_^
    | |                   |
    | |                   required by a bound introduced by this call
26  | |         registry: Arc::new(registry),
27  | |     });
    | |_____^ `(dyn SendEncodeMetric + 'static)` cannot be shared between threads safely
    |
    = help: the trait `Sync` is not implemented for `(dyn SendEncodeMetric + 'static)`
    = note: required because of the requirements on the impl of `Sync` for `Unique<(dyn SendEncodeMetric + 'static)>`
    = note: required because it appears within the type `Box<(dyn SendEncodeMetric + 'static)>`
    = note: required because it appears within the type `(Descriptor, Box<(dyn SendEncodeMetric + 'static)>)`
    = note: required because of the requirements on the impl of `Sync` for `Unique<(Descriptor, Box<(dyn SendEncodeMetric + 'static)>)>`
    = note: required because it appears within the type `alloc::raw_vec::RawVec<(Descriptor, Box<(dyn SendEncodeMetric + 'static)>)>`
    = note: required because it appears within the type `Vec<(Descriptor, Box<(dyn SendEncodeMetric + 'static)>)>`
    = note: required because it appears within the type `Registry`
    = note: required because of the requirements on the impl of `std::marker::Send` for `Arc<Registry>`
note: required because it appears within the type `State`
   --> examples/tide.rs:59:8
    |
59  | struct State {
    |        ^^^^^
note: required by a bound in `with_state`
   --> /Users/ben/.cargo/registry/src/github.com-1ecc6299db9ec823/tide-0.16.0/src/lib.rs:153:20
    |
153 |     State: Clone + Send + Sync + 'static,
    |                    ^^^^ required by this bound in `with_state`

<several related errors omitted>

It's fixed by adding a Sync bound to SendEncodeMetric but it feels like this is a common use case so I imagine it's come up before and I'm doing something silly - am I?

Thanks!

Metric names are incorrectly generated

The problem is demonstrated by the following comment

//! let expected = "# HELP my_counter This is my counter.\n".to_owned() +
//!                "# TYPE my_counter counter\n" +
//!                "my_counter_total 1\n" +
//!                "# EOF\n";

The HELP and TYPE lines should use my_counter_total, not my_counter.

HistogramTimer API

Hi! My team at work is converting some of our projects over from docs.rs/prometheus to this crate. One nice-to-have feature we miss from the old crate is the HistogramTimer type. I suggest adding it into this crate for two reasons:

  1. It's convenient for working with histograms and less error-prone than tracking time manually (using HistogramTimer means you don't have to check every possible early return/drop point yourself)
  2. It would simplify the process of porting code from docs.rs/prometheus over to this crate.

Happy to implement this myself.

Clone Family.metrics and iterate over family

Problems

  1. There is no way to copy/clone the HashMap<S,M> within family.

    • Use case: Storing metrics to compare against later
  2. There is no way to iterate over a metric Family or get metrics without knowing the labels.

    • The only to get all metrics is to manually call get_or_create() for every metric. This isn't great if you don't know the label names (don't store them etc...).

I am happy to tackle these if you want. I think making M clone (not sure why it isn't atm) and returning a new hashmap with the cloned values would fix both these problems.

Undeterministic order in output

The output or encode() is non-deterministic when creating multiple metrics of the same type.

So basically:

pub fn repro() -> String {
    let mut registry = <prometheus_client::registry::Registry>::default();

    let gauge = Family::<MyLabels, Gauge<f64, AtomicU64>>::default();
    registry.register("test", "help", gauge.clone());

    gauge
        .get_or_create(&MyLabels {
            label: "one".into(),
        })
        .set(0.1);
    gauge
        .get_or_create(&MyLabels {
            label: "two".into(),
        })
        .set(0.2);

    let mut buffer = String::new();

    encode(&mut buffer, &registry).unwrap();

    buffer
}

This will sometimes return this:

HELP test help.
# TYPE test gauge
test{label="one"} 0.1
test{label="two"} 0.2
# EOF

And sometimes this:

HELP test help.
# TYPE test gauge
test{label="two"} 0.2
test{label="one"} 0.1
# EOF

I would expect the metrics to be somehow sorted deterministically.

Bug: cannot use Exemplars and Families together

Hi all, thanks for making this library, I'm really excited to get started with exemplars. But I can't see how to combine exemplars and families.

Problem
By my read of the OpenMetrics spec, I should be able to export metrics like this:

latency_bucket{result="success",le="0.00256"} 27300 # {trace_id="3a2f90c9f80b894f"} 0.001345422

Note that the latency metric has labels in both its family (result) and its exemplars (trace_id)

I am trying to implement that using this library, but it won't compile. Why? Because the trait TypedMetric is not implemented for CounterWithExemplar<ExemplarLabel> and that means my metric does not impl SendSyncEncodeMetric. So it can't be registered. See this example:

use prometheus_client::{
    encoding::text::SendSyncEncodeMetric,
    metrics::{exemplar::HistogramWithExemplars, family::Family, histogram::exponential_buckets},
    registry::Registry,
};
use prometheus_client_derive_encode::Encode;

fn main() {
    // Create a metric registry.
    let mut registry = <Registry>::default();

    // Metric will be used something like this:
    // latency_bucket{result="success",le="0.00256"} 27300 # {trace_id="3a2f90c9f80b894f"} 0.001345422 1.6188203823429482e+09
    let latency: Family<ResultLabel, HistogramWithExemplars<TraceLabel>> =
        Family::new_with_constructor(|| {
            HistogramWithExemplars::new(exponential_buckets(1.0, 2.0, 10))
        });

    // This line doesn't compile:
    //
    // the trait `TypedMetric` is not implemented for `HistogramWithExemplar<TraceLabel>`
    let b: Box<dyn SendSyncEncodeMetric> = Box::new(latency);

    // Register metrics.
    registry.register("latency", "help text goes here", b);
}

#[derive(Clone, Hash, PartialEq, Eq, Encode, Debug, Default)]
pub struct ResultLabel {
    pub result: String,
}

#[derive(Clone, Hash, PartialEq, Eq, Encode, Debug, Default)]
pub struct TraceLabel {
    trace_id: String,
}

How can we create Prometheus Descriptors?

All the fields present in the Prometheus Descriptor are private which doesn't allow to initialise a new desc for custom metric. Should there be a default or parametrized constructor?

Let's say, I want to create a collector which contains different metrics and those metrics should have a new desc. How can I create one? Is the Descriptor concept fully implemented in this crate?

Similar to this piece of code: https://github.com/tikv/rust-prometheus/blob/ac86a264223c8d918a43e739ca3c48bb4aaedb90/src/desc.rs#L86

Using `()` as label set generates invalid format

I tried using () as the label set for a family, like Family<(), Histogram, ...>. Unfortunately this resulted in the following line in my metrics output:

histogram_name_bucket{,le="1.0"} 44

This results in a expected label name, got "COMMA" error when Prometheus tries to collect the metrics.

I would expect this to "just work" and just not insert any label (i.e. basically not have the leading comma in {,le="1.0"})

Global registry pattern

For systems where there are many components which need to register their own metrics, shared mutable access to the registry is required in order to keep things nice and simple (for the user). Providing a built-in solution for this pattern in the crate would lower the barrier of adoption, and could also help folks not to mess up their own implementation of the pattern where they might code the mutex incorrectly.

The prometheus crate has such a pattern, and it definitely makes getting started quite easy.

Counter API is overly restrictive

Currently Counter's API is:
https://github.com/prometheus/client_rust/blob/master/src/metrics/counter.rs#L76-L83

    /// Increase the [`Counter`] by 1, returning the previous value.
    pub fn inc(&self) -> N {
        self.value.inc()
    }

    /// Increase the [`Counter`] by `v`, returning the previous value.
    pub fn inc_by(&self, v: N) -> N {
        self.value.inc_by(v)
    }

which requires inc and inc_by to return the previous value. This is rarely needed for metric collecting use-case, and it hinders the ability to use per-thread thread-local accumulator to prevent contention (like this) and increase performance.

Implementing a process collector

Hello,

I recently stumbled upon tikv/rust-prometheus#392 and now I'm preparing a migration from rust-prometheus. I'm wondering how it would be possible to add a collector for process metrics just like what rust-prometheus does currently. I'm really inexperienced in those packages, and I don't really see how the ProcessCollector thing would translate here, to add some metrics related to the running process.

Can you tell me what would be necessary to add support for this ? I was thinking probably as another crate that exposes a single global function like crate::export_process_metrics(); so that crate would have to add timers to run the collection and hope that the timer runs often enough to give a precise measurement when prometheus scrapes the endpoint ?

Regards,
Gerry

Add example for actix-web framework

Hi guys, thanks for your contribution!

There is an issue with using the client with actix-web framework.
Because Registry doesn't implement Copy - the only working solution I've found is to wrap it with Mutex. But it requires locking at least on each collecting of metrics which isn't good for performance. Are there any other suggestions?

Make `Descriptor::new` `const`

Consider making Descriptor::new const. This would be handy when used with Collector when passing a borrowed 'static `Descriptor.

As far as I can tell, the only current blocker is the string manipulation to add a ,:

client_rust/src/registry.rs

Lines 437 to 438 in 85033bf

let help = help.into() + ".";

Missing GaugeWithExemplar

I want to have a GaugeWithExemplar that adds an exemplar whenever gauge derivates from zero. The actual use-case is making a flamegraph and putting it into the exemplar label, so that it can be easily found.

It seems like it would mostly be a copy of CounterWithExemplar, so I'm happy to make a PR if this makes sense.

Replace owning_ref

Owning ref is (1) seemingly unmaintained since last commit was 2 years ago and (2) unsound. Something else should probably be used.

Public encoding functions?

Sometimes I have already e.g. nodes: Vec<Node> in the application state where Node is like

struct Node {
   url: String,
   requests: AtomicU64,
}

(When you are already working with a &Node, bumping the requests counter is just an atomic inc. It's much more efficient than get_or_create(...).inc().)

And I'd like to expose the requests counter of all nodes as a metric family. It might be possible with the collector API, but it would still require quite some boxing, cloning and iterator mapping.

Instead I'd like to encode the metrics myself, e.g.:

encode_descriptor(&mut buf, ...);
for n in &ctx.nodes {
    encode_counter_with_labels(&mut buf, [("node", &n.url)], n.requests.load(...));
}
encode_eof(&mut buf);

This will not require any extra allocation or cloning. By fusing the collecting and encoding phase, metrics can be encoded very efficiently.

Hidden imports in lib.rs example code

Hello folks,

Looking at the example code in lib.rs (when rendered on docs.rs), it was a little confusing to figure out what was going on due to many functions and types from the client_rust library being imported but the imports themselves being hidden.

What do you think about un-hiding the library imports so that it's more clear which parts of the client_rust library the example code is referencing?

feat: derive register logic on struct of metrics

One oftentimes has a struct of metrics like:

struct Metrics {
    a: Counter,
    b: Gauge,
}

Code to register the metrics in Metrics with a Registry could be generated via a derive macro on Metrics.

  • The metric name would be taken from the field name.
  • The metric help text would be taken from the Rust doc String.
  • The metric unit could be provided via a macro attribute.
#[derive(Register)]
struct Metrics {
    /// My Gauge tracking the number of xxx
    a: Counter,
    /// My Counter, tracking the event xxx
    #[prometheus-unit(Seconds)]
    b: Gauge,
}

Where the Register trait is something along the lines of:

trait Register {
  fn create_and_register(registry: &mut Registry) -> Self;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.