Skip to content

Conversation

@Karrq
Copy link
Contributor

@Karrq Karrq commented Nov 18, 2025

Closes #20

This PR also includes some other small improvements:

  • split the existing metric types in separate modules
  • add a simple Justfile
  • move large examples from README.md to dedicated examples files
  • enforce help string when using prometric-derive
  • dedicated handling for histograms/summary "partitions" in prometric-derive
  • prometric-derive now respects user's specified paths for metric types

TODO:

  • Add examples
  • Add support in prometric-derive
  • Properly implement the glue code from metrics-util's Summary for SummaryProvider
  • Add more tests

deps: metrics-util for Summary logic
feat: GenericSummary, converts into prometheus proto's Summary
feat: SummaryVecBuilder enabling SummaryVec
feat: SummaryVec, mirrors HistogramVec
@Karrq Karrq requested a review from mempirate November 18, 2025 17:25
@Karrq Karrq self-assigned this Nov 18, 2025
refactor(derive): `buckets`/`quantiles` attributes and invariant checks
feat(example): add Summary usage
fix(examples): add missing help strings
@Karrq Karrq marked this pull request as ready for review November 18, 2025 22:41
feat(summary): rolling summary
feat(summary): ConcurrentSummaryProvider
docs: improve documentation
chore: cleanup `core` dead file
deps: feature-gate summary deps
chore: cleanup unused MetricType::Summary.1 field
test: ensure quantile defaults work
chore: remove unused `GenericSummary::observe`
refactor: rename `GenericSummary::concurrent_observe` to `observe`
Copy link
Contributor

@mempirate mempirate left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass, primarily some style stuff. Very nice job

&self,
maybe_buckets: Option<syn::Expr>,
maybe_quantiles: Option<syn::Expr>,
) -> Result<Partitions> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could return Result<Option<Partitions>> and we can remove the Partitions::{None, NotApplicable} variants. Up to you

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about it, but decided to go with more explicit variants, to preserve the semantics better, if one day we need to change this I'd rather have it much clearer

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate more on how you preserve the semantics better?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To indicate that this parsed item is specifically for this usecase, but also if we want to make hard errors out of "NotApplicable" we could, for example if it was provided and we were processing a Counter

I can rework it to be an option, in the end it's a small difference, it's just that when parsing I prefer to be explicit about the various options, especially since we have an enum already (for buckets/quantiles, which ok could be just the inner syn::Expr)

@Karrq
Copy link
Contributor Author

Karrq commented Nov 20, 2025

Changed to ArcCell but it's still not working correctly (test is failing)
I think I will have to change the approach a bit, I believe those .load calls are actually cloning the Arc sometimes :/

test(arccell): check invariants are upheld
refactor: new batch reserves
@Karrq Karrq requested a review from thedevbirb November 21, 2025 08:37
Copy link
Contributor

@merklefruit merklefruit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work! Leaving some questions to understand for myself 🙂

Karrq and others added 6 commits November 21, 2025 15:27
Co-authored-by: nicolas <48695862+merklefruit@users.noreply.github.com>
fix: deadlock with cloned GenericSummary (not a full clone)
fix(summary:generic): usage with MetricVecBuilder
test: summary + macro smoke test
refactor: SummaryProvider -> NonConcurrentSummaryProvider
refactor: ConcurrentSummaryProvider -> SummaryProvider
fix: relax trait bounds where possible
lint: clippy
test: add concurrent Summary metric test
@Karrq Karrq requested a review from mempirate November 21, 2025 17:08
Copy link
Contributor

@mempirate mempirate left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, some minor things but approved. I would like to see this tested in the real world before we do a release, can work on that this week in one of the projects.

}
}

// TODO: switch to FixedVec
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FixedVec because we know the number of observations before committing I suppose? Would it be more efficient?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, Fixed in terms of fixed capacity https://docs.rs/orx-concurrent-vec/latest/orx_concurrent_vec/struct.FixedVec.html

The number of measurements will be at most batch size (or a few over those) so we could preallocate the required capacity instead of having the ConcurrentVec grow

Copy link
Contributor

@thedevbirb thedevbirb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor things

&self,
maybe_buckets: Option<syn::Expr>,
maybe_quantiles: Option<syn::Expr>,
) -> Result<Partitions> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate more on how you preserve the semantics better?

Comment on lines 9 to 11
/// A simple Summary metric implementation
#[derive(Debug, Clone)]
pub struct SimpleSummary {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does "Simple" mean here? Overall the distinction between rolling and simple isn't super clear, I have a rough idea but I want to be sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment, but it's to differentiate it from Rolling.
The rolling one has a configured expiry duration so values past that duration are expired and removed, thus not returned from the snapshot, and thus not used for quantile computation

if matches!(e, prometheus::Error::AlreadyReg) {
registry
.unregister(boxed.clone())
.unwrap_or_else(|_| panic!("Failed to unregister metric {id}"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it okay to panic here because this is code running at compile time?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not running at compile time, it's run during the metric initialization (when building it)
I copied it from the other metrics, which do the same.

This scenario can happen if the collector was not registered, which is also not possible because we just got "AlreadyReg" error, indicating that it was indeed registered.
In the same way, the register function errors when the collector was already registered, which we just unregistered.

Looking inside the function, it seems like the only other error (from register) other than AlreadyReg would just be a configuration error: descriptor with same name but different help, for example, which is not something recoverable really

refactor: generic extraction method for readability
docs: explain RollingSummary
docs: explain SimpleSummary
fix(rolling): return total count in snapshot
Copy link
Contributor

@thedevbirb thedevbirb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job!

@mempirate mempirate merged commit 80f8352 into main Nov 25, 2025
4 checks passed
@mempirate mempirate deleted the feat/summary branch November 25, 2025 08:54
@github-actions github-actions bot mentioned this pull request Nov 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support the Summary metric type

5 participants