# Hesione

A Prometheus client

---

## Overview

There are a handful of other Prometheus clients for Rust already, but I decided
to make another one. Rust has a lot of language features, and I felt like none
of the existing implementations were truly using those to their advantage. With
Hesione, traits are leveraged to make metric storage types pluggable, and
a derive macro exists to make defining metrics and generating their collective
outputs easy, among other things.

Also, [my GitLab instance][repo] has GitHub and GitLab.com account sign-in
enabled, so if you'd like to open issues or contribute code, please feel free to
do so!

[repo]: https://forge.typ3.tech/charles/hesione

## Features

* Rust things:
    * [X] Codegen that simplifies metric definitions
    * [X] Easy to instrument your code with
    * [X] Well-tested
    * [ ] Process metrics
* Prometheus things:
    * [X] Counters
    * [X] Gauges
    * [ ] Histograms
    * [ ] Summaries

## Examples

```rust
use std::sync::{
    Arc,
    atomic::{Ordering, AtomicUsize},
};

use once_cell::sync::Lazy;
use hesione::{Hesione, Counter, labels};

/// The collection of metrics used by your program
#[derive(Hesione)]
struct Metrics {
    /// The amount of HTTP requests
    ///
    /// Extra documentation that won't show up in Prometheus' help text can go
    /// here. For example, I'll take this moment to mention that `AtomicUsize`
    /// is just an arbitrary choice here. If you'd like to use another type to
    /// store the value in, this is possible (with the stipulation that the type
    /// you want implements the `hesione::Value` trait).
    http_reqs: Counter<AtomicUsize>,
}

/// A globally usable instance of the above structure
///
/// This isn't strictly necessary, although it will likely make instrumentation
/// much easier.
static METRICS: Lazy<Metrics> = Lazy::new(Metrics::default);

// Instrument your code by importing METRICS and modifying its fields:
METRICS.http_reqs.inc(Ordering::SeqCst, None);

// You can also add labels when accessing a metric:
let labels = labels! {
    "status_code": 404.to_string(),
}.unwrap();
METRICS.http_reqs.inc(Ordering::SeqCst, Some(labels));

// Call this method in your `/metrics` HTTP endpoint to generate the output:
let actual = METRICS.to_prometheus_lines(Ordering::SeqCst, None);

// This is what the output will look like for this example:
let expected = concat!(
        // The help text comes from the first line of the doc comments
        "# HELP http_reqs The amount of HTTP requests\n",

        // Type hints are dictated by the struct's field type
        "# TYPE http_reqs counter\n",

        // Metric names are generated by the struct's field name
        "http_reqs 1\n",
        "http_reqs{status_code=\"404\"} 1\n",
        "\n",
    );

assert_eq!(expected, actual);
```

## Contributing code

Be sure to run the `.hooks/install.sh` script after the first clone. The
post-merge hook will re-run this script to apply changes to the hooks, if there
are any. The pre-commit hook runs the formatter, linter (on deny warnings mode),
and the test suite. If you don't want to run hard-mode linter or the tests for
some reason (maybe you already did and just don't want to do it again
automatically, or are committing code-unrelated things), you can set the
`SKIP_TESTS_PLEASE` environment variable to anything.

## License

This project is licensed under either of

* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
  <http://www.apache.org/licenses/LICENSE-2.0>)

* MIT license ([LICENSE-MIT](LICENSE-MIT) or
  <http://opensource.org/licenses/MIT>)

at your option.
