Skip to content

Add supervisor/count metric for health and state monitoring#19114

Merged
abhishekrb19 merged 14 commits into
apache:masterfrom
aruraghuwanshi:supervisor-health-metrics
Mar 12, 2026
Merged

Add supervisor/count metric for health and state monitoring#19114
abhishekrb19 merged 14 commits into
apache:masterfrom
aruraghuwanshi:supervisor-health-metrics

Conversation

@aruraghuwanshi

@aruraghuwanshi aruraghuwanshi commented Mar 9, 2026

Copy link
Copy Markdown
Contributor

Add supervisor/count metric for health and state monitoring

Previously, supervisor health was only exposed via the REST API (GET /druid/indexer/v1/supervisor/{id}/health) and the sys.supervisors SQL table. There was no way to scrape supervisor health/state from Prometheus, StatsD, or other metric emitters for monitoring and alerting.

This PR adds SupervisorStatsMonitor, which emits a supervisor/count gauge metric per supervisor. Each active supervisor contributes a value of 1, tagged with supervisorId, type, and state (RUNNING, SUSPENDED, UNHEALTHY_SUPERVISOR, UNHEALTHY_TASKS, etc.). Users can aggregate by state for dashboards and alerts (e.g. sum(supervisor_count{state=~"UNHEALTHY_.*"})).

Description

Design

  • Pattern: Mirrors TaskCountStatsMonitor / TaskCountStatsProvider: a provider interface in server/, implemented by SupervisorManager in indexing-service/, consumed by an Overlord-only monitor.
  • Metric: supervisor/count — gauge, value 1 per supervisor; dimensions: supervisorId, type, state.
  • State source: Uses getState().getBasicState() (7 values) instead of detailed states to avoid high cardinality.
  • Opt-in: Users add SupervisorStatsMonitor to druid.monitoring.monitors; no behavioral change without it.
  • Cost: Only uses getState() and spec metadata (cheap reads); no getStatus() calls on the monitor interval.

Release note

Adds a new supervisor/count metric when SupervisorStatsMonitor is enabled in druid.monitoring.monitors. The metric reports each supervisor’s state (RUNNING, SUSPENDED, UNHEALTHY_SUPERVISOR, etc.) for Prometheus, StatsD, and other metric systems.


Key changed/added classes in this PR
  • SupervisorStatsProvider (new interface)
  • SupervisorStatsProvider.SupervisorStats (new inner class)
  • SupervisorStatsMonitor (new)
  • SupervisorManager (implements SupervisorStatsProvider)

This PR has:

  • been self-reviewed.
  • added documentation for new or modified features or behaviors.
  • a release note entry in the PR description.
  • added Javadocs for most classes and all non-trivial methods. Linked related entities via Javadoc links.
  • added or updated version, license, or notice information in licenses.yaml
  • added comments explaining the "why" and the intent of the code wherever would not be obvious for an unfamiliar reader.
  • added unit tests or modified existing tests to cover new code paths, ensuring the threshold for code coverage is met.
  • added integration tests.
  • been tested in a test Druid cluster.

Introduce SupervisorStatsMonitor that exposes supervisor count per state
(RUNNING, SUSPENDED, UNHEALTHY_SUPERVISOR, etc.) with dimensions
supervisorId, type, and state. Opt-in via druid.monitoring.monitors.

@kfaraz kfaraz left a comment

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.

Looks good, left a minor suggestion.

Comment thread server/src/main/java/org/apache/druid/server/metrics/SupervisorStatsMonitor.java Outdated
Comment thread docs/operations/metrics.md Outdated
Comment thread docs/configuration/index.md Outdated
aruraghuwanshi and others added 3 commits March 10, 2026 12:52
Co-authored-by: Abhishek Radhakrishnan <[email protected]>
…unt metric

- Add dataSource, stream, and detailedState fields to SupervisorStats
- Populate dataSource from SupervisorSpec.getDataSources() via DefaultQueryMetrics.getTableNamesAsString()
- Populate stream from SupervisorSpec.getSource() (null for non-streaming supervisors)
- Populate detailedState from Supervisor.getState().toString() (null only when state is null)
- Emit dataSource always, stream and detailedState conditionally via setDimensionIfNotNull
- Update tests to cover new dimensions, null stream, multi-datasource, and detailedState != state cases
- Update metrics.md to list new dimensions and link to supervisor status report for state/detailedState values

@abhishekrb19 abhishekrb19 left a comment

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.

Lgtm, left a few small suggestions. Thanks!

Comment thread extensions-contrib/prometheus-emitter/src/main/resources/defaultMetrics.json Outdated
aruraghuwanshi and others added 2 commits March 10, 2026 13:59
…rop null checks

- Inline supervisorId, stateStr, dataSource, stream, and detailedState
- Use spec.getId() instead of entry.getKey()
- Remove redundant null check on spec.getDataSources()
- Use spec.getSource() in place of spec.getStream() (fix suggested typo)
- Replace Collections.emptyList() null fallback with direct getDataSources() usage
Comment on lines +93 to +105
public Collection<SupervisorStatsProvider.SupervisorStats> getSupervisorStats()
{
List<SupervisorStatsProvider.SupervisorStats> stats = new ArrayList<>();
for (Map.Entry<String, Pair<Supervisor, SupervisorSpec>> entry : supervisors.entrySet()) {
final SupervisorSpec spec = entry.getValue().rhs;
final SupervisorStateManager.State state = entry.getValue().lhs.getState();

stats.add(new SupervisorStatsProvider.SupervisorStats(
spec.getId(),
spec.getType(),
state == null ? "UNKNOWN" : state.getBasicState().toString(),
DefaultQueryMetrics.getTableNamesAsString(new HashSet<>(spec.getDataSources())),
spec.getSource(),

@abhishekrb19 abhishekrb19 Mar 11, 2026

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 looks like jacoco-coverage is failing due to lack of code coverage for this new method, which seems legitimate. Could you please add a few unit tests in SupervisorManagerTest?

Covers empty supervisors, active supervisors with non-null state, and
supervisors with null state to satisfy jacoco diff coverage for the
new method.
Move SegmentIdWithShardSpec import before SupervisorStatsProvider so
segment comes before server as required by alphabetical ordering.
Revert unintended change to DefaultQueryMetrics and update
SupervisorManagerTest to expect for supervisors with no
data sources, matching getTableNamesAsString behavior.
TestSupervisorSpec.getDataSources() returned an empty list, causing
the supervisor stats test to assert [] (stringified empty list) as
the dataSource — a confusing and unrealistic value. Return the
supervisor id instead, matching real SupervisorSpec implementations.
@abhishekrb19
abhishekrb19 merged commit 348f509 into apache:master Mar 12, 2026
61 of 63 checks passed
@github-actions github-actions Bot added this to the 37.0.0 milestone Mar 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants