Giter VIP home page Giter VIP logo

client_rust's Introduction

Prometheus
Prometheus

Visit prometheus.io for the full documentation, examples and guides.

CI Docker Repository on Quay Docker Pulls Go Report Card CII Best Practices Gitpod ready-to-code Fuzzing Status OpenSSF Scorecard

Prometheus, a Cloud Native Computing Foundation project, is a systems and service monitoring system. It collects metrics from configured targets at given intervals, evaluates rule expressions, displays the results, and can trigger alerts when specified conditions are observed.

The features that distinguish Prometheus from other metrics and monitoring systems are:

  • A multi-dimensional data model (time series defined by metric name and set of key/value dimensions)
  • PromQL, a powerful and flexible query language to leverage this dimensionality
  • No dependency on distributed storage; single server nodes are autonomous
  • An HTTP pull model for time series collection
  • Pushing time series is supported via an intermediary gateway for batch jobs
  • Targets are discovered via service discovery or static configuration
  • Multiple modes of graphing and dashboarding support
  • Support for hierarchical and horizontal federation

Architecture overview

Architecture overview

Install

There are various ways of installing Prometheus.

Precompiled binaries

Precompiled binaries for released versions are available in the download section on prometheus.io. Using the latest production release binary is the recommended way of installing Prometheus. See the Installing chapter in the documentation for all the details.

Docker images

Docker images are available on Quay.io or Docker Hub.

You can launch a Prometheus container for trying it out with

docker run --name prometheus -d -p 127.0.0.1:9090:9090 prom/prometheus

Prometheus will now be reachable at http://localhost:9090/.

Building from source

To build Prometheus from source code, You need:

Start by cloning the repository:

git clone https://github.com/prometheus/prometheus.git
cd prometheus

You can use the go tool to build and install the prometheus and promtool binaries into your GOPATH:

GO111MODULE=on go install github.com/prometheus/prometheus/cmd/...
prometheus --config.file=your_config.yml

However, when using go install to build Prometheus, Prometheus will expect to be able to read its web assets from local filesystem directories under web/ui/static and web/ui/templates. In order for these assets to be found, you will have to run Prometheus from the root of the cloned repository. Note also that these directories do not include the React UI unless it has been built explicitly using make assets or make build.

An example of the above configuration file can be found here.

You can also build using make build, which will compile in the web assets so that Prometheus can be run from anywhere:

make build
./prometheus --config.file=your_config.yml

The Makefile provides several targets:

  • build: build the prometheus and promtool binaries (includes building and compiling in web assets)
  • test: run the tests
  • test-short: run the short tests
  • format: format the source code
  • vet: check the source code for common errors
  • assets: build the React UI

Service discovery plugins

Prometheus is bundled with many service discovery plugins. When building Prometheus from source, you can edit the plugins.yml file to disable some service discoveries. The file is a yaml-formated list of go import path that will be built into the Prometheus binary.

After you have changed the file, you need to run make build again.

If you are using another method to compile Prometheus, make plugins will generate the plugins file accordingly.

If you add out-of-tree plugins, which we do not endorse at the moment, additional steps might be needed to adjust the go.mod and go.sum files. As always, be extra careful when loading third party code.

Building the Docker image

The make docker target is designed for use in our CI system. You can build a docker image locally with the following commands:

make promu
promu crossbuild -p linux/amd64
make npm_licenses
make common-docker-amd64

Using Prometheus as a Go Library

Remote Write

We are publishing our Remote Write protobuf independently at buf.build.

You can use that as a library:

go get buf.build/gen/go/prometheus/prometheus/protocolbuffers/go@latest

This is experimental.

Prometheus code base

In order to comply with go mod rules, Prometheus release number do not exactly match Go module releases. For the Prometheus v2.y.z releases, we are publishing equivalent v0.y.z tags.

Therefore, a user that would want to use Prometheus v2.35.0 as a library could do:

go get github.com/prometheus/[email protected]

This solution makes it clear that we might break our internal Go APIs between minor user-facing releases, as breaking changes are allowed in major version zero.

React UI Development

For more information on building, running, and developing on the React-based UI, see the React app's README.md.

More information

  • Godoc documentation is available via pkg.go.dev. Due to peculiarities of Go Modules, v2.x.y will be displayed as v0.x.y.
  • See the Community page for how to reach the Prometheus developers and users on various communication channels.

Contributing

Refer to CONTRIBUTING.md

License

Apache License 2.0, see LICENSE.

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 levaitamas 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

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?

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.

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?

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.

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".

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!

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,
}

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"})

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?

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.

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.

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.

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.

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.

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)

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!

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.

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

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/

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.

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

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

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.

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.

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.

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).

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.

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?

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.

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!

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.

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.