Hi all,

I've picked up apache/pulsar#26403 ("[Go Functions] No way to register
custom metric collectors: every user metric is a summary") and would like a
steer on the API shape before putting up a PR, since it's a public-API
decision on FunctionContext.

Issue: https://github.com/apache/pulsar/issues/26403

Background: today every custom metric a Go function records goes through
FunctionContext.RecordMetric(name, value), which observes into a single
fixed SummaryVec. There's no way to express a counter, gauge, histogram, or
a metric with custom labels. The underlying *prometheus.Registry the
instance serves (pulsar-function-go/pf/stats.go) is an unexported package
variable, so there's no supported path for user code to register its own
collectors. Python functions can already do this today because
prometheus_client has a process-global registry the instance happens to
serve by default; Go's client_golang has no equivalent, so the same three
lines of user code that work in Python are impossible in Go. Java has the
same gap, tracked separately as #24853 (
https://github.com/apache/pulsar/issues/24853) since the fix is necessarily
Java-shaped there.

The proposed fix is small: expose the existing registry through
FunctionContext as a prometheus.Registerer (write-only interface —
Register/Unregister/MustRegister, no Gather), so user collectors get served
on the existing metrics endpoint alongside the SDK's own. I've confirmed
against current master that this is structurally a single accessor method;
no registry lifecycle changes are needed.

The open question, flagged by the issue's original author, is the API shape:

- Option A: a thin `FunctionContext.GetMetricsRegistry()
prometheus.Registerer`. Composes with any existing client_golang code a
user already has; minimal surface to review and maintain.
- Option B: typed helpers (NewUserCounter, NewUserGauge, NewUserHistogram)
that pre-apply the standard tenant/namespace/name/instance/cluster labels.
Friendlier and harder to misuse, but more design surface, and not obviously
aligned yet with whatever shape #24853 lands on for Java.

I'd lean toward shipping Option A first — it's small enough to review in
one pass and doesn't foreclose adding typed helpers later as a separate,
additive change if there's demand.

Separately: every existing SDK metric is already registered under the
pulsar_function_ prefix at init(), before any user code runs, so a user
Register-ing a collector whose name collides with an existing one will
panic at runtime today. I'd like to fold a fix for that into the same PR —
either rejecting the pulsar_function_ prefix in the returned Registerer, or
documenting it clearly on the accessor. Open to guidance on which.

Happy to write this up as a short design note if that's more useful than a
thread. Let me know which direction makes sense, and I'll get a PR up.

Thanks,
Kritharth

Reply via email to