Skip to content

Agent Health issue for OpenMetrics metrics dropped by configured limit - #24819

Open
nubtron wants to merge 21 commits into
masterfrom
nubtron/ai-7012-openmetrics-dropped-config
Open

Agent Health issue for OpenMetrics metrics dropped by configured limit#24819
nubtron wants to merge 21 commits into
masterfrom
nubtron/ai-7012-openmetrics-dropped-config

Conversation

@nubtron

@nubtron nubtron commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?

OpenMetrics stops submitting new metric contexts after it reaches max_returned_metrics. The check logs a warning, but the resulting gaps can look intermittent and are easy to miss.

This PR surfaces that condition in Agent Health. When an OpenMetrics v1 or v2 endpoint exceeds its effective limit, the check reports:

  • Issue name: OpenMetrics Metrics Dropped By Configured Limit
  • Issue type: openmetrics_metrics_dropped_by_configured_limit
  • the affected endpoint, configured limit, observed contexts, dropped contexts, and dropped ratio
  • remediation that starts with filtering unnecessary metrics before suggesting a higher limit, with explicit cost and memory cautions

Remediation shown to customers

The issue carries the following remediation (from metric_limit_issue._remediation):

Summary: Reduce what this endpoint sends to Datadog, or raise this instance's metric limit after checking the cost.

  1. Decide what you actually need. Use metrics / ignore_metrics (OpenMetrics v1) or metrics / exclude_metrics (OpenMetrics v2) on this instance to stop collecting series you do not query, alert on, or keep.
  2. Only then raise max_returned_metrics on this instance to a value above the observed count.
  3. Verify: enable debug_metrics.metric_contexts: true on the instance to publish datadog.agent.metrics.contexts.total and .limit, and confirm the total stays below the limit at peak. Consider a monitor at 80% of the limit.
  4. Check the cost before you leave it: additional contexts are billable custom metrics and increase Agent memory.

Each endpoint gets a stable issue identity derived from the host, check name, endpoint, and namespace. The issue is refreshed while drops continue, resolved on the first clean collection, and reused if the condition later returns.

Severity reflects the fraction of contexts dropped:

  • LOW: less than 5%
  • MEDIUM: 5% to less than 25%
  • HIGH: 25% or more

The Agent Health bridge is best-effort: reporting failures do not fail the check or interfere with the limiter's existing cleanup. The generic AgentCheck hook remains a no-op, so only OpenMetrics v1 and v2 opt into this issue.

The PR also adds the missing issue_type argument to AgentCheck.report_issue. The Agent payload, persistence, and forwarding paths already support this field, so no rtloader or Agent ABI change is needed.

Why?

When OpenMetrics exceeds max_returned_metrics, some metrics are silently discarded after the warning is emitted. Because exporter ordering can change between scrapes, customers may see different metrics disappear over time instead of one obvious hard cutoff.

Agent Health gives this failure mode a durable, endpoint-specific state with actionable remediation, while preserving the existing check lifecycle and limiter behavior.

Review checklist

  • Feature or bugfix has appropriate tests
  • qa/skip-qa is applied
  • Add a backport label if a backport is required

@nubtron nubtron added the qa/skip-qa Automatically skip this PR for the next QA label Aug 10, 2026
@datadog-prod-us1-5

datadog-prod-us1-5 Bot commented Aug 10, 2026

Copy link
Copy Markdown

Tests  Code Coverage

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🔄 Datadog auto-retried 4 jobs - 4 passed on retry View in Datadog

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 88.77%

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 7ea240d | Docs | View more details | Give us feedback!

@nubtron nubtron changed the title Prototype: Agent Health issue for OpenMetrics metrics dropped by configured limit Agent Health issue for OpenMetrics metrics dropped by configured limit Aug 10, 2026
nubtron added 17 commits August 10, 2026 18:59
The Fleet UI renders remediation step text as plain text, so the backticks
around config option names were shown literally to customers. Match the
plain-text convention used by other Agent Health producers.
The MetricLimitIssueReporter carried a boolean `legacy` flag whose only
effect was selecting between the v1 (`metrics` / `ignore_metrics`) and
v2 (`metrics` / `exclude_metrics`) config option names in remediation
text. Pass the actual option string instead so the reporter no longer
knows about OpenMetrics flavors and the call sites document themselves.
The Fleet UI renders Agent Health remediation text as plain text, so the
dotted form 'debug_metrics.metric_contexts: true' reads as a single literal
key. The check parses instance.get('debug_metrics', {}).get('metric_contexts'),
so a dotted top-level key would never match and no telemetry would be emitted.

Describe the nesting in prose ('set metric_contexts to true under the
debug_metrics section') and spell out both emitted metric names in full
instead of the orphaned '.limit'. Add assertions locking in the corrected
wording.
@cit-pr-commenter-54b7da

Copy link
Copy Markdown

evalya-impact-summary

evalya impact analysis
Impact analysis: 0 selected, 0 skipped (of 0 test tasks)
Publish tasks:   1 (always emitted)
Diff (8 files):
  datadog_checks_base/changelog.d/24819.added
  datadog_checks_base/datadog_checks/base/checks/base.py
  datadog_checks_base/datadog_checks/base/checks/openmetrics/base_check.py
  datadog_checks_base/datadog_checks/base/checks/openmetrics/metric_limit_issue.py
  datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/base.py
  datadog_checks_base/tests/base/checks/openmetrics/test_metric_limit_issue.py
  datadog_checks_base/tests/base/checks/test_agent_check.py
  openmetrics/tests/test_metric_limit_issue.py

Debug a specific task: evalya plan impact --path <path> --task <task>

Learn more about CI impact filtering

@nubtron
nubtron marked this pull request as ready for review August 24, 2026 13:28
@nubtron
nubtron requested review from a team as code owners August 24, 2026 13:28

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1584239ed8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread datadog_checks_base/tests/base/checks/openmetrics/test_metric_limit_issue.py Outdated
Comment on lines +1664 to +1669
if self.metric_limiter:
try:
reached_limit = self.metric_limiter.reached_limit
observed_count = self.metric_limiter.count
limit = self.metric_limiter.limit
self._on_metric_limit_state(reached_limit, observed_count, limit)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid resolving isolated metric-limit issues in the parent

When process_isolation is enabled, run_with_isolation creates a child check and its run() already reports the over-limit issue through the redirected datadog_agent. After the child exits, this parent-side block reads the untouched parent limiter (reached_limit=False, count=0) and invokes the same deterministic callback, immediately resolving the issue that the child just reported. Limit handling should occur only in the process that performed the scrape, or the child's limiter state must be propagated back.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Looks legit will look into it!

Comment on lines +103 to +106
def _on_metric_limit_state(self, reached_limit: bool, observed_count: int, limit: int) -> None:
self.metric_limit_issue_reporter.handle(
self,
self.instance.get('openmetrics_endpoint'),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use generated scraper endpoints when reporting limits

For V2 integrations that synthesize scraper_configs from integration-specific options, this lookup does not identify the endpoint that was scraped. For example, CiliumCheckV2 accepts agent_endpoint/operator_endpoint and only places openmetrics_endpoint in generated scraper configs; if a user enables max_returned_metrics, self.instance.get('openmetrics_endpoint') remains None, causing MetricLimitIssueReporter.handle() to return without reporting any drops. The callback needs the actual configured scraper endpoint or endpoints rather than the raw instance field.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Same here, looks like a valid comment.

…oints

The V2 metric-limit callback read openmetrics_endpoint from the raw instance,
which stays absent for integrations such as Cilium that synthesize scraper
configs from agent_endpoint/operator_endpoint, so drops were never reported.
Pass the actual configured scraper endpoint keys from self.scrapers instead,
and have V1 pass its one effective prometheus_url.

MetricLimitIssueReporter.handle now accepts a collection of endpoints and
normalizes it to a deterministic, de-duplicated, sorted tuple, discarding
empty values. One aggregate issue is reported for the whole run since the
limiter state cannot attribute drops to a single scraper. The machine-readable
extra['endpoints'] list and the issue identity reflect the endpoint set; the
existing single-endpoint public issue id is preserved, and multi-endpoint
identities hash the structured ordered collection.
@dd-octo-sts

dd-octo-sts Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Validation Report

All 21 validations passed.

Show details
Validation Description Status
agent-reqs Verify check versions match the Agent requirements file
ci Validate CI configuration and code coverage settings
codeowners Validate every integration has a CODEOWNERS entry
config Validate default configuration files against spec.yaml
dep Verify dependency pins are consistent and Agent-compatible
http Validate integrations use the HTTP wrapper correctly
imports Validate check imports do not use deprecated modules
integration-style Validate check code style conventions
jmx-metrics Validate JMX metrics definition files and config
labeler Validate PR labeler config matches integration directories
legacy-signature Validate no integration uses the legacy Agent check signature
license-headers Validate Python files have proper license headers
licenses Validate third-party license attribution list
metadata Validate metadata.csv metric definitions
models Validate configuration data models match spec.yaml
openmetrics Validate OpenMetrics integrations disable the metric limit
package Validate Python package metadata and naming
qa-label Validate the pull request declares whether it needs QA for the next Agent release
readmes Validate README files have required sections
saved-views Validate saved view JSON file structure and fields
version Validate version consistency between package and changelog

View full run

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.

1 participant