Skip to content

Add prometheus exporter#17392

Merged
etiennejouan merged 3 commits intomainfrom
tt-add-metrics-endpoint
Jan 23, 2026
Merged

Add prometheus exporter#17392
etiennejouan merged 3 commits intomainfrom
tt-add-metrics-endpoint

Conversation

@thomtrp
Copy link
Copy Markdown
Contributor

@thomtrp thomtrp commented Jan 23, 2026

Create a metric endpoint and expose prometheus gauge for event stream count.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 7 files

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Jan 23, 2026

Greptile Overview

Greptile Summary

This PR adds Prometheus metrics support to expose live event stream counts via a new /metrics endpoint.

Key Changes:

  • Added prom-client dependency for Prometheus integration
  • Created PrometheusService to manage Prometheus registry and gauge metrics with support for custom collect callbacks
  • Created PrometheusController exposing public /metrics endpoint for Prometheus scraping
  • Added scanAndCountSetMembers() method to CacheStorageService for efficiently counting Redis set members across multiple keys matching a pattern
  • Integrated metrics collection in EventStreamService to track twenty_event_streams_live_total gauge
  • Default Node.js metrics are automatically collected via collectDefaultMetrics()

Implementation:
The implementation follows NestJS patterns with proper module imports and dependency injection. The metrics endpoint is marked as public (no authentication required) which is standard for Prometheus scrape targets. Error handling is implemented in the gauge collection callback to prevent metrics scraping failures from affecting the service.

Confidence Score: 4/5

  • This PR is safe to merge with low risk
  • The implementation is well-structured and follows established patterns in the codebase. However, the score is 4 instead of 5 because there are no tests for the new functionality, which is flagged by custom instruction 458c2737-e49d-49c4-a233-2605d1516703. The code quality is good with proper error handling, appropriate use of Redis operations, and clean separation of concerns. The public metrics endpoint is appropriately secured with guards.
  • No files require special attention - all changes are straightforward and well-implemented

Important Files Changed

Filename Overview
packages/twenty-server/src/engine/core-modules/cache-storage/services/cache-storage.service.ts Added scanAndCountSetMembers method to count Redis set members matching a pattern
packages/twenty-server/src/engine/core-modules/metrics/prometheus.controller.ts New controller exposing /metrics endpoint for Prometheus scraping with public access
packages/twenty-server/src/engine/core-modules/metrics/prometheus.service.ts New service managing Prometheus registry, gauge creation, and metrics collection
packages/twenty-server/src/engine/subscriptions/event-stream.service.ts Integrated Prometheus gauge tracking live event stream count with error handling

Sequence Diagram

sequenceDiagram
    participant Prometheus as Prometheus Server
    participant Controller as PrometheusController
    participant Service as PrometheusService
    participant EventStream as EventStreamService
    participant Cache as CacheStorageService
    participant Redis as Redis

    Note over Service: On Module Init
    Service->>Service: collectDefaultMetrics()
    EventStream->>Service: createGauge(config)
    Service->>Service: Register gauge with collect callback

    Note over Prometheus: Periodic Scrape
    Prometheus->>Controller: GET /metrics
    Controller->>Service: getMetrics()
    Service->>Service: Trigger collect callbacks
    Service->>EventStream: collect() callback executed
    EventStream->>EventStream: getTotalActiveStreamCount()
    EventStream->>Cache: scanAndCountSetMembers('workspace:*:activeStreams')
    Cache->>Redis: SCAN with pattern matching
    Redis-->>Cache: Return matching keys
    Cache->>Redis: SCARD for each key
    Redis-->>Cache: Return set member counts
    Cache-->>EventStream: Return total count
    EventStream->>Service: gauge.set(count)
    Service-->>Controller: Return formatted metrics
    Controller-->>Prometheus: 200 OK with metrics data
Loading

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@socket-security
Copy link
Copy Markdown

socket-security bot commented Jan 23, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​opentelemetry/​exporter-prometheus@​0.211.0741008995100

View full report

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Jan 23, 2026

🚀 Preview Environment Ready!

Your preview environment is available at: http://bore.pub:61555

This environment will automatically shut down when the PR is closed or after 5 hours.

Copy link
Copy Markdown
Contributor

@etiennejouan etiennejouan left a comment

Choose a reason for hiding this comment

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

Looks good but I wonder why we don't rely on OTEL API (for all metrics collection) ?

@thomtrp thomtrp force-pushed the tt-add-metrics-endpoint branch from c899bb2 to 9861253 Compare January 23, 2026 15:12
@github-actions
Copy link
Copy Markdown
Contributor

TODOs/FIXMEs:

  • //TODO : Define meter name usage in monitoring: packages/twenty-server/src/engine/core-modules/metrics/metrics.service.ts
  • //TODO : Define meter name usage in monitoring: packages/twenty-server/src/engine/core-modules/metrics/metrics.service.ts

Generated by 🚫 dangerJS against 9861253

@thomtrp thomtrp changed the title Add metrics endpoint Add prometheus exporter Jan 23, 2026
Copy link
Copy Markdown
Contributor

@etiennejouan etiennejouan left a comment

Choose a reason for hiding this comment

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

Tested and it works great ! 👏

(Difference with previous implementation is that all metrics are exported on /metrics endpoint, not only the one you want)

@etiennejouan etiennejouan added this pull request to the merge queue Jan 23, 2026
Merged via the queue into main with commit 2346efd Jan 23, 2026
74 of 75 checks passed
@etiennejouan etiennejouan deleted the tt-add-metrics-endpoint branch January 23, 2026 15:49

if (keys.length > 0) {
const counts = await Promise.all(
keys.map((key) => redisClient.sCard(key)),
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.

This could be painful (N network calls), can we use Redis pipeline for that instead?

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.

Probably even better with LUA

camilo-agudelo-uma pushed a commit to innovation-grupo-uma/twenty-uma that referenced this pull request Feb 2, 2026
Create a metric endpoint and expose prometheus gauge for event stream
count.
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.

3 participants