Skip to content

Split into backend-agnostic core + per-backend serving packages - #60

Open
mtelvers wants to merge 1 commit into
mirage:masterfrom
mtelvers:proto/backend-agnostic
Open

Split into backend-agnostic core + per-backend serving packages#60
mtelvers wants to merge 1 commit into
mirage:masterfrom
mtelvers:proto/backend-agnostic

Conversation

@mtelvers

@mtelvers mtelvers commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Recording and collection no longer depend on a concurrency library, so metric-defining libraries depend only on prometheus; an application chooses Lwt or Eio only when it serves metrics.

  • prometheus (core): Lwt-free, direct-style. CollectorRegistry.collect returns a plain snapshot; a collector may perform I/O via effects, handled by whatever scheduler runs collect.
  • prometheus-app: backend-free text-format renderer + GC collectors (no cohttp, no concurrency library).
  • prometheus-cohttp: a /metrics handler functor over cohttp's Cohttp.Generic.Server.S, usable with any cohttp backend.
  • prometheus-lwt (+ .unix): Lwt collectors (register_lwt), an Lwt collect that merges the core's synchronous metrics, Lwt timing helpers, and the cohttp-lwt server + cmdliner + logging.
  • prometheus-eio: direct-style timing helpers and a cohttp-eio handler; async collection needs no special machinery under Eio.

Tests cover the core (incl. an effects-driven collector), the Lwt sync+async merge, and the Eio path under Eio_main. README updated.

Replaces #59.

@mtelvers
mtelvers force-pushed the proto/backend-agnostic branch 2 times, most recently from 6fc4251 to 794d5cb Compare June 2, 2026 06:59
@dinosaure dinosaure self-assigned this Jun 3, 2026
Comment thread src/prometheus.mli

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure if it's right to just delete the Lwt.t, the trick is to define a type 'a io and specify it as type 'a io = 'a Lwt.t for lwt and type 'a t = 'a for something like eio.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It think we can we just drop OCaml 4 support for new versions of prometheus now. As long as we have a compiler with support for effects, we can still implement Lwt support even if the core library is direct style.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure to follow you, the main aim is to keep Lwt.t as it is (that doesn’t have much to do with the effects and OCaml 4/5).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@dinosaure, Lwt.t is preserved, just in Prometheus_lwt.CollectorRegistry rather than in the core. The Lwt-facing surface in lwt/prometheus_lwt.mli is the same shape as v1.2's register_lwt / register_pre_collect_lwt / collect : t -> snapshot Lwt.t, so Lwt applications keep the semantics they had.

The choice was: (a) parameterise the core over 'a io (your Make(IO) shape) so a single library serves both backends, or (b) make the core direct-style and ship a small Lwt wrapper that re-introduces the Lwt.t surface for Lwt callers.

This PR goes with (b) because recording (Counter.inc, Gauge.set, Histogram.observe) is genuinely synchronous and doesn't want to flow through 'a io. Under (a), library authors who only define and increment metrics still see the abstraction. Under (b), they don't. Eio also drops out for free: a collector that needs to suspend just performs IO via effects, no Make(IO_eio) needed.

The runtime behaviour and the visible Lwt API are identical between (a) and (b); the difference is which side of the library carries the abstraction. The current shape gives both groups what they need: library authors a scheduler-free core, Lwt apps an unchanged Lwt.t API, Eio apps a direct-style one.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hmmhmm, sorry I need more time to review and see the implication of such change in the context of lwt.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I took a look at this patch, and I think that the Lwt type isn't necessary in the core since Prometheus doesn't actually need to block in normal use as it's updating a scoreboard (like incrementing an int or other counter).

However, it would be far easier to review if the PR were split up into two: one that only moves the Lwt logic out of the core, and then a subsequent set of PRs that add eio, miou and whatever other backends people want. Having just the Lwt moving out of the core will be the interface breaking one for most existing users, so I'd like to release that separately of any new features. @mtelvers has agreed to have a go at this; thanks Mark!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@mtelvers I also think #56 looks relevant to the refactoring

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ok let's move, I lost my energy when I saw the force-push during my review but globally, it seems good for me.

Recording and collection no longer depend on a concurrency library, so
metric-defining libraries depend only on `prometheus`; an application
chooses Lwt or Eio only when it serves metrics.

- prometheus (core): Lwt-free, direct-style. CollectorRegistry.collect
  returns a plain snapshot; a collector may perform I/O via effects,
  handled by whatever scheduler runs collect. Includes the direct-style
  timing helpers (Gauge.time, track_inprogress, Summary.time).
- prometheus-app: backend-free text-format renderer + GC collectors
  (no cohttp, no concurrency library).
- prometheus-cohttp: a /metrics handler functor over cohttp's
  Cohttp.Generic.Server.S, usable with any cohttp backend.
- prometheus-lwt (+ .unix): Lwt collectors (register_lwt), an Lwt collect
  that merges the core's synchronous metrics, Lwt timing helpers, and the
  cohttp-lwt server + cmdliner + logging.
- prometheus-eio: a cohttp-eio handler; async collection needs no special
  machinery under Eio, and timing reuses the core's direct-style helpers.

Lower bounds are 4.08 for the non-Eio packages and 5.0 for prometheus-eio.
Tests cover the core, the Lwt sync+async merge, and the effects-driven Eio
path under Eio_main. README updated.
@mtelvers
mtelvers force-pushed the proto/backend-agnostic branch from 794d5cb to c82ff32 Compare June 30, 2026 21:17
avsm added a commit to avsm/prometheus that referenced this pull request Aug 5, 2026
Split off the Lwt-specific parts of the library so that defining and
recording metrics no longer pulls in a concurrency library. Metric
recording is synchronous anyway (it updates an in-memory scoreboard) so
the core does not need Lwt.

This is the first half of mirage#60, so that the interface-breaking move can
be reviewed separately.

Co-authored-by: Mark Elvers <mark.elvers@tunbury.org>
avsm added a commit to avsm/prometheus that referenced this pull request Aug 6, 2026
Introduce the `prometheus-lwt` package with the API that the core will keep
once its Lwt dependency is removed (mirage#60 mirage#65), but implemented for now via Lwt
support still present in `prometheus`.

Therefore nothing breaks in this release as existing users can migrate to
`Prometheus_lwt` and also to the new synchronous `_fn` functions at their own
pace. The actual interface break will then happen in a later release without
further source changes for migrated Lwt users.

Also add synchronous variants of the timing helpers to the core since the
existing Lwt-typed functions occupy the unsuffixed names until the break.

Suggested by @talex5 in mirage#65.

Co-authored-by: Mark Elvers <mark.elvers@tunbury.org>
avsm added a commit to avsm/prometheus that referenced this pull request Aug 6, 2026
Introduce the `prometheus-lwt` package with the API that the core will keep
once its Lwt dependency is removed (mirage#60 mirage#65), but implemented for now via Lwt
support still present in `prometheus`.

Therefore nothing breaks in this release as existing users can migrate to
`Prometheus_lwt` and also to the new synchronous `_fn` functions at their own
pace. The actual interface break will then happen in a later release without
further source changes for migrated Lwt users.

Also add synchronous variants of the timing helpers to the core since the
existing Lwt-typed functions occupy the unsuffixed names until the break.

Suggested by @talex5 in mirage#65.

Co-authored-by: Mark Elvers <mark.elvers@tunbury.org>
avsm added a commit to avsm/prometheus that referenced this pull request Aug 6, 2026
Introduce the `prometheus-lwt` package with the API that the core will keep
once its Lwt dependency is removed (mirage#60 mirage#65), but implemented for now via Lwt
support still present in `prometheus`.

Therefore nothing breaks in this release as existing users can migrate to
`Prometheus_lwt` and also to the new synchronous `_fn` functions at their own
pace. The actual interface break will then happen in a later release without
further source changes for migrated Lwt users.

Also add synchronous variants of the timing helpers to the core since the
existing Lwt-typed functions occupy the unsuffixed names until the break.

Suggested by @talex5 in mirage#65.

Co-authored-by: Mark Elvers <mark.elvers@tunbury.org>
talex5 added a commit to avsm/prometheus that referenced this pull request Aug 6, 2026
Introduce the `prometheus-lwt` package with the API that the core will keep
once its Lwt dependency is removed (mirage#60 mirage#65), but implemented for now via Lwt
support still present in `prometheus`.

Therefore nothing breaks in this release as existing users can migrate to
`Prometheus_lwt` and also to the new synchronous functions at their own
pace. The actual interface break will then happen in a later release without
further source changes for migrated Lwt users.

Also add synchronous variants of the timing helpers to the core since the
existing Lwt-typed functions occupy the unsuffixed names until the break.

Suggested by @talex5 in mirage#65.

Co-authored-by: Mark Elvers <mark.elvers@tunbury.org>
Co-authored-by: Thomas Leonard <talex5@gmail.com>
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.

4 participants