<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Elastic Observability Labs - alerting</title>
        <link>https://www.elastic.co/observability-labs</link>
        <description>Trusted security news &amp; research from the team at Elastic.</description>
        <lastBuildDate>Fri, 21 Aug 2026 18:46:47 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Elastic Observability Labs - alerting</title>
            <url>https://www.elastic.co/observability-labs/assets/observability-labs-thumbnail.png</url>
            <link>https://www.elastic.co/observability-labs</link>
        </image>
        <copyright>© 2026. Elasticsearch B.V. All Rights Reserved</copyright>
        <item>
            <title><![CDATA[TLS Certificate Monitoring with the OpenTelemetry Collector]]></title>
            <link>https://www.elastic.co/observability-labs/blog/edot-certificate-monitoring</link>
            <guid isPermaLink="false">edot-certificate-monitoring</guid>
            <pubDate>Fri, 09 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn how to monitor TLS certificate expiration in Kubernetes clusters using the OpenTelemetry Collector, ensuring comprehensive visibility into both external and internal certificates, using Elastic Observability
]]></description>
            <content:encoded><![CDATA[<p>In modern distributed systems, TLS certificates are the glue that holds
everything together while keeping it safe. Certificates aren't only used for
encrypting user traffic; they are fundamental building blocks of trust for your
entire system.</p>
<p>Indeed, an expired certificate is <em>not</em> just a minor technical glitch.
It is a direct hit on your most critical systems:</p>
<ul>
<li>
<p>Your CI/CD pipeline grinds to a halt because it can not trust the internal
image registry.</p>
</li>
<li>
<p>Your Single Sign-On (SSO) system fails, locking all your internal users out.</p>
</li>
<li>
<p>Your external clients see scary browser warnings, shattering user trust and
forcing support tickets.</p>
</li>
<li>
<p>Your SLOs burn due to services not being able to communicate with one another.</p>
</li>
</ul>
<p>In Kubernetes, certificates are usually dynamically generated and auto-renewed
by tools like <code>cert-manager</code>. In more unlucky scenarios, certificates might be
tucked away inside <code>Secrets</code> and <code>ConfigMaps</code>, leading to challenges while
inventorying them. It is neither hard nor unheard of to have a dozen critical
certificates and no centralized way to know when they are about to expire.</p>
<p>Additionally, only monitoring the certificates for external Load Balancers might
lead to huge <em>internal</em> risks, since many certificates never get exposed to
external users.</p>
<p>In this blog post, we will guide you through establishing comprehensive,
cluster-wide certificate monitoring using the OpenTelemetry Collector,
the <a href="https://github.com/enix/x509-certificate-exporter">x509-certificate-exporter</a>,
and Elastic Observability.</p>
<h2>Classical approach: HTTP monitoring</h2>
<p>The classical approach to monitor TLS certificate expiration in the Elastic
Observability is by treating it like any other service availability check. Historically,
this was accomplished using Heartbeat or, more recently, Elastic Observability's Synthetics.
These tools perform an external check against a public HTTPS endpoint and
automatically extract the certificate's validity dates, allowing you to
configure a
<a href="https://www.elastic.co/docs/solutions/observability/incident-management/create-tls-certificate-rule">Synthetics TLS certificate rule</a>
in Kibana to trigger an alert when expiration is within a specified threshold
(e.g., 30 days).</p>
<p>While effective for external-facing services, this &quot;classical&quot; approach has two
major shortcomings when dealing with Kubernetes:</p>
<ul>
<li>
<p>It only works for certificates exposed via HTTP(S), meaning you cannot use
this for internal services, databases, or message queues using other protocols.
In other words, this won't work to monitor common, critical TLS certificates
such as Kafka's.</p>
</li>
<li>
<p>The monitoring agent must have network access to the endpoint. In a segmented
or private Kubernetes environment, deploying agents with the necessary access
often introduces unnecessary complexity or security risks.</p>
</li>
</ul>
<p>To gain true cluster-wide visibility, we need to inspect the certificates at
their source: <em>inside</em> Kubernetes Secrets or ConfigMaps.</p>
<h2>A Kubernetes-native approach: monitor Secrets and ConfigMaps</h2>
<p>Monitoring TLS certificate expiration directly within Kubernetes Secrets and
ConfigMaps is the only reliable way to gain visibility into internal,
non-HTTP-exposed certificates, such as those used for service meshes, internal
registries, or databases. In this section, we will use the OpenTelemetry Collector to
monitor certificate expiration.</p>
<p>The OpenTelemetry Collector provides a mechanism to read
up-to-date information from the Kubernetes API, including Secrets, via the
<a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/k8sobjectsreceiver">k8sobjects receiver</a>.
However, this receiver only fetches <em>raw</em> TLS certificate resource data,
which the OpenTelemetry Transformation Language (OTTL) can not properly parse.
Therefore, we need to use a dedicated exporter to collect the certificate data
and expose the results in a digestible format.</p>
<h3>The industry-standard solution</h3>
<p>As mentioned above, simply reading certificate information from the Kubernetes API
is not a feasible solution. We will therefore use a specialized,
lightweight exporter (specifically, the popular
<a href="https://github.com/enix/x509-certificate-exporter">x509-certificate-exporter</a>)
to collect TLS certificate data and expose the results,
allowing the OpenTelemetry Collector's Prometheus receiver to seamlessly
scrape the data and send it to Elastic Observability.
This approach immediately and easily enables us to monitor both certificates
generated by <code>cert-manager</code> and self-managed ones, such as the ones created for
ECK.</p>
<p>A fully working configuration example and a script to set up a complete local
development environment is available <a href="https://github.com/elastic/edot-certificate-monitoring-blog-post">here</a>.
Feel free to use it to follow along as you read through this guide and try out the examples.
Please note that, while this repository uses the Elastic Distribution of OpenTelemetry (EDOT),
it can be easily adapted to use the OpenTelemetry Collector.</p>
<h4>Helm Chart Configuration</h4>
<p>We configured the <code>x509-certificate-exporter</code> with the official Helm Chart and
used the following minimal configuration:</p>
<pre><code class="language-yaml">secretsExporter:
  secretTypes:
  - type: kubernetes.io/tls
    key: tls.crt
  # For ECK that uses different secret types
  - type: Opaque
    key: tls.crt
  - type: Opaque
    key: ca.crt
  configMapKeys:
  - tls.crt
  - ca.crt

# Create a service to have a stable endpoint for scraping metrics
service:
  create: true
  # -- TCP port to expose the Service on
  port: 9793

# Disable prometheus service monitor and prometheus rules
prometheusServiceMonitor:
  create: false
prometheusRules:
  create: false
</code></pre>
<p>We refer to the reference values.yaml to get insights in the plethora of
configuration options.</p>
<h4>OpenTelemetry Collector Configuration</h4>
<p>Afterward, we configured the OpenTelemetry Collector to scrape the metrics from the
service:</p>
<pre><code class="language-yaml">prometheus/cert-expiration:
  config:
    scrape_configs:
      - job_name: &quot;cert-expiration&quot;
        scrape_interval: 60m
        static_configs:
          - targets:
              - &quot;x509-certificate-exporter.monitoring.svc.cluster.local:9793&quot;
</code></pre>
<p>We deliberately used a long scrape interval of 60 minutes, because certificate
expiration is a low-frequency concern.</p>
<h4>Visualizing the data in Kibana</h4>
<p>Once the data is ingested, we can explore it using Discover. We can select the
<code>metrics-*</code> Data View and search for our
data with the filter <code>data_stream.dataset : &quot;prometheusreceiver.otel&quot;</code>.</p>
<p>An example document looks like the following:</p>
<pre><code class="language-json">{
  &quot;@timestamp&quot;: &quot;2025-12-19T09:43:45.317Z&quot;,
  &quot;_metric_names_hash&quot;: &quot;7d113f55b70019d9&quot;,
  &quot;attributes&quot;: {
    &quot;issuer_CN&quot;: &quot;tls-cert.example.com&quot;,
    &quot;issuer_O&quot;: &quot;TLS Cert&quot;,
    &quot;secret_key&quot;: &quot;tls.crt&quot;,
    &quot;secret_name&quot;: &quot;tls-cert-secret&quot;,
    &quot;secret_namespace&quot;: &quot;test-certs&quot;,
    &quot;serial_number&quot;: &quot;250887723804527203192865532237673843132727735771&quot;,
    &quot;subject_CN&quot;: &quot;tls-cert.example.com&quot;,
    &quot;subject_O&quot;: &quot;TLS Cert&quot;
  },
  &quot;data_stream&quot;: {
    &quot;dataset&quot;: &quot;prometheusreceiver.otel&quot;,
    &quot;namespace&quot;: &quot;default&quot;,
    &quot;type&quot;: &quot;metrics&quot;
  },
  &quot;metrics&quot;: {
    &quot;x509_cert_expired&quot;: 0,
    &quot;x509_cert_not_after&quot;: 1768488242,
    &quot;x509_cert_not_before&quot;: 1765896242
  },
  &quot;resource&quot;: {
    &quot;attributes&quot;: {
      &quot;server.address&quot;: &quot;x509-certificate-exporter.monitoring.svc.cluster.local&quot;,
      &quot;server.port&quot;: &quot;9793&quot;,
      &quot;service.instance.id&quot;: &quot;x509-certificate-exporter.monitoring.svc.cluster.local:9793&quot;,
      &quot;service.name&quot;: &quot;cert-expiration&quot;,
      &quot;url.scheme&quot;: &quot;http&quot;
    }
  },
  &quot;scope&quot;: {
    &quot;name&quot;: &quot;github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver&quot;,
    &quot;version&quot;: &quot;9.2.2&quot;
  }
}
</code></pre>
<p>The core metric reported by the <code>x509-certificate-exporter</code> is
<code>x509_cert_not_after</code> that represent the Unix Epoch timestamp (in seconds) of the certificate's
expiration date. This metric has some attributes associated with it.
In the case of <code>Secrets</code>, the following attributes are relevant:</p>
<ul>
<li><code>secret_namespace</code>: The namespace of the Secret containing the certificate.</li>
<li><code>secret_name</code>: The name of the Secret containing the certificate.</li>
<li><code>secret_key</code>: The specific key within the Secret where the certificate is stored.</li>
</ul>
<p>In the case of <code>ConfigMaps</code>, we can infer the attributes of interest
from the <code>filepath</code> attribute.</p>
<p>Finally, we can leverage ES|QL to compute the remaining days until expiration.
In the following examples, we will use the <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/ts"><code>TS</code> command</a>,
which is optimized and recommended for interacting with time-series data.</p>
<p>For <code>Secrets</code>:</p>
<pre><code class="language-sql">TS metrics-*
| WHERE metrics.x509_cert_not_after is not NULL
| STATS expiration_date = MAX(LAST_OVER_TIME(metrics.x509_cert_not_after)) by attributes.secret_namespace, attributes.secret_name, attributes.secret_key
| EVAL remaining_days = DATE_DIFF(&quot;days&quot;, NOW(), TO_DATETIME (1000 * expiration_date))
| EVAL expiration_date = TO_DATETIME(1000 * expiration_date)
| SORT expiration_date ASC
</code></pre>
<p>And for <code>ConfigMaps</code>:</p>
<pre><code class="language-sql">TS metrics-*
| WHERE metrics.x509_cert_not_after IS NOT NULL
| WHERE attributes.filepath IS NOT NULL
| DISSECT attributes.filepath &quot;k8s/%{namespace}/%{configmap}&quot;
| WHERE configmap != &quot;kube-root-ca.crt&quot; // Filter out the Kubernetes API server certificate's signing CA
| STATS expiration_date = MAX(LAST_OVER_TIME(metrics.x509_cert_not_after)) by namespace, configmap, filename
| EVAL remaining_days = DATE_DIFF(&quot;days&quot;, NOW(), TO_DATETIME (1000 * expiration_date))
| EVAL expiration_date = TO_DATETIME(1000 * expiration_date)
| SORT expiration_date ASC
</code></pre>
<p>Based on these core queries, we can easily build a dashboard that shows the
remaining days until expiration for all the certificates in the cluster:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/edot-certificate-monitoring/dashboard.png" alt="Kibana Certificate Expiration Dashboard" /></p>
<p>and create alerts about certificates that are about to expire by adding a
condition after the query:</p>
<pre><code class="language-sql">WHERE remaining_days &lt; 30
</code></pre>
<h3>Conclusion</h3>
<p>In this blog post, we explored how to monitor TLS certificate expiration
within a Kubernetes cluster using the OpenTelemetry Collector.
We discussed the limitations of traditional HTTP-based monitoring
approaches and introduced a Kubernetes-native solution leveraging the
<code>x509-certificate-exporter</code> to extract certificate expiration data directly from
Kubernetes Secrets and ConfigMaps. This method provides comprehensive visibility
into all certificates used within the cluster, including those not exposed via
HTTP(S).</p>
<p>For the sake of simplicity, we just focused on monitoring certificate expiration
with the OpenTelemetry Collector on Kubernetes. However, this approach can be easily applied
with classical Elastic Agent by leveraging the
<a href="https://www.elastic.co/docs/reference/integrations/prometheus_input">Prometheus input package</a>
(read more on how to use input packages
<a href="https://www.elastic.co/observability-labs/blog/customize-data-ingestion-input-packages">here</a>)
and can be also extended to monitor certificates on virtual machines or
bare-metal servers by deploying the <code>x509-certificate-exporter</code> there.</p>
<p>Finally, is worth knowing that Elastic Observability, offers an officially supported
distribution of the OpenTelemetry Collector,
called <a href="https://www.elastic.co/observability-labs/blog/elastic-distributions-opentelemetry">Elastic Distributions of OpenTelemetry (EDOT)</a>.</p>
<p>If you are an Elastic user, you could consider using EDOT Collector to monitor certificates with
OpenTelemetry: since it is supported by Elastic Observability, it will be easier to manage and keep up to date. Alternatively you can use upstream OTel compnents also.</p>
<h3>What's next?</h3>
<p>Now that Elastic supports
<a href="https://www.elastic.co/docs/reference/fleet/alerting-rule-templates">Rule Templates</a>
and <a href="https://www.elastic.co/docs/solutions/observability/apm/opentelemetry">OpenTelemetry content packs</a>,
our near-term objective is to contribute to the integration repository to make
the setup of certificate monitoring even easier for our users.
Stay tuned for more updates on this!</p>
<p>Check out other resources on Elastic's OpenTelemetry</p>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-managed-otlp-endpoint-for-opentelemetry">Elastic's OTLP EndPoint</a></p>
<p><a href="https://www.elastic.co/observability-labs/blog/opentelemetry-accepts-elastics-donation-of-edot">Elastic's EDOT PHP Contribution</a></p>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-distribution-opentelemetry-sdk-central-configuration-opamp">Opentelemetry SDK Central Management with EDOT</a></p>
<p>Also sign up for <a href="https://cloud.elastic.co">Elastic Cloud</a> and try out your application with OpenTelemetry in Elastic</p>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/edot-certificate-monitoring/edot-certificate-monitoring.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Skip writing alert rules: 6 ready-made ES|QL templates ship inside the NGINX OTel integration]]></title>
            <link>https://www.elastic.co/observability-labs/blog/alerting-rule-templates-elastic-integrations</link>
            <guid isPermaLink="false">alerting-rule-templates-elastic-integrations</guid>
            <pubDate>Fri, 31 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic integrations come with alerting rule templates, each one an ES|QL query with a threshold already set. Create Elasticsearch alert rules in minutes, tune them to your traffic, and catch silent data streams early.]]></description>
            <content:encoded><![CDATA[<p>The NGINX OpenTelemetry Assets integration ships six <a href="https://www.elastic.co/docs/reference/fleet/alerting-rule-templates">alerting rule templates</a>. Each one is an <a href="https://www.elastic.co/docs/reference/query-languages/esql">ES|QL</a> query with a threshold already tuned. Install the integration, create a rule from one of the templates, and adjust the threshold to match your traffic. You get working alerts in minutes instead of writing them from scratch. This walkthrough covers the full setup, threshold tuning, and how to use an idle data streams rule to catch a service that stops sending data.</p>
<h2>Prerequisites for Elastic integration alerting rule templates</h2>
<p>Elastic Stack 9.4.0 or later.</p>
<p><em>Alerting rule templates have been available since 9.2.1, under the integration <strong>Assets</strong> tab. This article covers three things that need 9.4.0: the dedicated <strong>Alerting</strong> tab, idle data streams rules, and the NGINX OpenTelemetry Assets package, which is in technical preview.</em></p>
<h2>Step 1: Send NGINX logs and metrics to Elasticsearch with OpenTelemetry</h2>
<p>First, get NGINX metrics and logs into Elasticsearch.</p>
<p>Enable the NGINX <code>stub_status</code> module and make the access and error logs readable by the collector. Then, configure an <a href="https://www.elastic.co/docs/reference/opentelemetry">EDOT</a> or upstream OpenTelemetry Collector with the <code>nginx</code> and <code>filelog</code> receivers to export metrics and logs to Elasticsearch.</p>
<p>The <a href="https://www.elastic.co/docs/reference/integrations/nginx_otel">integration setup</a> has the full receiver and pipeline configuration.</p>
<p>If you want to reproduce this example, you can use the <a href="https://github.com/Delacrobix/Creating-alerts-from-OOTB-alerting-template">companion repository</a>.</p>
<p>Both signals matter for alerting, and each group of templates reads a different data stream:</p>
<ul>
<li>The <strong>log-based</strong> templates (4xx and 5xx error rates, error log spike) query <code>logs-nginx.access.otel-*</code> and <code>logs-nginx.error.otel-*</code>, which come from the <code>filelog</code> receiver.</li>
<li>The <strong>metric-based</strong> templates (active connections, dropped connections) query <code>metrics-nginxreceiver.otel-*</code>, which comes from the <code>nginx</code> receiver.</li>
</ul>
<p>This is easy to get wrong: the Fleet <a href="https://www.elastic.co/docs/solutions/observability/infra-and-hosts/collect-nginx-data-otel-integration-fleet-managed"><strong>Nginx (OpenTelemetry)</strong> input package</a> collects <code>stub_status</code> metrics only. Its companion for logs is the classic Nginx integration, which writes ECS-based <code>nginx.access</code> and <code>nginx.error</code> datasets, not the <code>*.otel-*</code> data streams the log-based templates query. If you rely on that pairing alone, the log-based rules have nothing to evaluate and silently never fire. Run the <code>filelog</code> receiver too, not just the <code>nginx</code> receiver.</p>
<h2>Step 2: Install the NGINX OpenTelemetry Assets integration</h2>
<p>NGINX OpenTelemetry Assets is a content-only package. It ships the dashboards, alerting rule templates, and SLO templates, but it does not collect data itself. The data comes from the collector you set up in Step 1.</p>
<p>You don't need to install it by hand. Once the NGINX OTel data from Step 1 starts arriving, Elastic detects it and installs the Assets package for you, which takes a minute or two. Confirm it under <strong>Management</strong> &gt; <strong>Integrations</strong> &gt; <strong>Installed integrations</strong>, where <code>NGINX OpenTelemetry Assets</code> should appear.</p>
<h2>Step 3: Create Elasticsearch alert rules from a rule template</h2>
<p>Open the integration and select the <strong>Alerting</strong> tab.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/alerting-rule-templates-elastic-integrations/02-alerting-tab.png" alt="The Alerting tab of the NGINX OpenTelemetry Assets integration listing its rule templates" /></p>
<p>This package ships six templates: high 4xx and 5xx error rates, high active connections, an error log spike, dropped connections, and a generic <code>High error rate by service</code> template that points at a placeholder <code>logs-myservicereceiver.otel-*</code> index for you to repoint and rename. The five NGINX rules run ES|QL every minute and group results by <code>host.name</code>, so an alert points at the host with the problem. The generic template groups by <code>service.name</code> instead, since it is meant to be repointed at whichever service you choose.</p>
<p>Select a template, for example <code>[Nginx OTel] High 5xx error rate</code>. Kibana opens a prefilled <strong>Create rule</strong> form built on an <a href="https://www.elastic.co/docs/explore-analyze/alerts-cases/alerts/rule-type-es-query">Elasticsearch query rule</a>. It runs the template's ES|QL on a schedule and alerts when the query returns rows.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/alerting-rule-templates-elastic-integrations/03-create-rule-form.png" alt="The prefilled Create rule form for the High 5xx error rate template" /></p>
<p>The query looks like this:</p>
<pre><code class="language-esql">FROM logs-nginx.access.otel-*
// Flag each access log entry as a server error (5xx) or not
| EVAL is_5xx = CASE(http.response.status_code &gt;= 500, 1, 0)
// Aggregate total requests and 5xx count per NGINX host
| STATS total = COUNT(*), errors_5xx = SUM(is_5xx) BY host.name
// Minimum sample size to avoid noisy low-traffic hosts
| WHERE total &gt; 50
// Calculate 5xx error rate as a percentage
| EVAL error_rate_pct = ROUND(TO_DOUBLE(errors_5xx) / TO_DOUBLE(total) * 100.0, 2)
// Alert threshold: adjust to tune sensitivity
| WHERE error_rate_pct &gt; 5.0
| SORT error_rate_pct DESC
| LIMIT 10
</code></pre>
<p>It counts requests and 5xx responses per host, keeps hosts with enough traffic to matter, and returns those above five percent.</p>
<p>Three things to get right while the form is open:</p>
<ul>
<li><strong>Send data first.</strong> ES|QL validates column names against the indices that exist when the query runs. Open a template before any NGINX data has been ingested and the editor reports <code>Unknown column &quot;http.response.status_code&quot;</code> and the form shows errors. Once data is flowing (Step 1), the same query validates and the error clears, so collect data before you create the rule.</li>
<li><strong>Set the time field to <code>@timestamp</code>.</strong></li>
<li><strong>Leave &quot;Create an alert for each row&quot; selected.</strong> Because the query groups by <code>host.name</code>, this makes every affected host raise its own alert.</li>
</ul>
<p>Add a <a href="https://www.elastic.co/docs/deploy-manage/manage-connectors">connector</a> and an action so the alert reaches Slack, email, or PagerDuty, then save and enable the rule.</p>
<h2>Step 4: Tune alerting rule template thresholds in ES|QL</h2>
<p>The thresholds are starting points, so confirm them against your own traffic. The threshold lives in the ES|QL <code>WHERE</code> clause.</p>
<p>To make the rule stricter, change <code>error_rate_pct &gt; 5.0</code> to <code>error_rate_pct &gt; 2.0</code>. To require more traffic before it fires, raise <code>total &gt; 50</code>. Use <strong>Test query</strong> in the rule form to confirm the edited query parses and returns rows before you save.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/alerting-rule-templates-elastic-integrations/04-test-query.png" alt="Test query results after editing the threshold in the ES|QL query" /></p>
<p>Three more settings are worth a look:</p>
<ul>
<li><strong>Time window</strong>: the look-back period the query runs over. A shorter window reacts faster but is noisier on bursty traffic.</li>
<li><strong>Rule schedule</strong>: how often the query runs, every minute by default.</li>
<li><strong>Alert delay</strong>: the number of consecutive runs the condition must hold before an alert is created, which filters out single-run blips.</li>
</ul>
<h2>How do you detect idle data streams in Elasticsearch?</h2>
<p>Threshold rules only fire while data keeps arriving. When an agent goes offline or an output breaks, the data stops, and a threshold rule has nothing to evaluate.</p>
<p>Many Elastic integrations include a dynamically generated <a href="https://www.elastic.co/docs/reference/fleet/alerting-rule-templates">idle data streams template</a> for exactly this case. It is named <code>[{Integration name}] Idle data streams</code> and appears in the same Alerting tab, though it is generated automatically rather than bundled with the integration. It alerts when no data is written to any of the integration's data stream patterns within a set period.</p>
<p>The NGINX OpenTelemetry packages do not include an idle data streams template, which is why no such template appears in the Alerting tab from Step 3. The end of this section covers what to do instead.</p>
<p>The default period is 24 hours, which is usually too long. A production service can go quiet for most of a day before you hear about it.</p>
<p>When you create the rule, drop the period to match how fast you need to know. Fifteen minutes to one hour works for a critical service. For a batch job, set a period comfortably longer than its run interval, so the quiet gaps between runs do not trigger it.</p>
<p>So why is this example left out? The template is generated from the data stream patterns an integration defines, and it is not generated for input-only packages. A content-only package like NGINX OpenTelemetry Assets defines no data streams of its own either. To catch silence in a collector-based setup like this, recreate the rule by hand with an <a href="https://www.elastic.co/docs/explore-analyze/alerts-cases/alerts/rule-type-es-query">Elasticsearch query rule</a>. Use the query DSL or KQL variant rather than ES|QL, because an ES|QL rule fires on returned rows and so cannot alert on the <em>absence</em> of data. Point it at the OTel data streams (<code>logs-nginx.access.otel-*</code>, or <code>metrics-nginxreceiver.otel-*</code>) and set the condition to fire when the number of matching documents <strong>is below 1</strong> over a window of, say, the last 15 minutes. That reproduces what an idle data streams template does, scoped to the data streams your collector writes.</p>
<h2>Get started with Elastic integration alerting rule templates</h2>
<p>Alerting rule templates turn alert setup into a few steps: send data, install the integration, create a rule from a template, and adjust the threshold. Treat the bundled thresholds as defaults to confirm, not numbers to trust blindly. And where an idle data streams template is available, reduce its 24-hour default so you find out quickly when a service goes silent.</p>
<h2>Resources</h2>
<ul>
<li><a href="https://github.com/Delacrobix/Creating-alerts-from-OOTB-alerting-template">Companion repository</a>, to generate the NGINX demo data used here</li>
<li><a href="https://www.elastic.co/docs/reference/fleet/alerting-rule-templates">Alerting rule templates</a></li>
<li><a href="https://www.elastic.co/docs/reference/integrations/nginx_otel">NGINX OpenTelemetry Assets integration</a></li>
<li><a href="https://www.elastic.co/observability-labs/blog/nginx-opentelemetry-end-to-end-tracing">End-to-end tracing for NGINX with OpenTelemetry</a></li>
<li><a href="https://www.elastic.co/docs/explore-analyze/alerts-cases/alerts/rule-type-es-query">Elasticsearch query rule</a></li>
<li><a href="https://www.elastic.co/docs/reference/fleet/alert-templates">Elastic Agent built-in alerts</a>, for monitoring the agents themselves</li>
</ul>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/alerting-rule-templates-elastic-integrations/01-header.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Smarter Alerting Arrives with Faster Triage, Clearer Groupings, and Actionable Guidance]]></title>
            <link>https://www.elastic.co/observability-labs/blog/elastic-stack-observability-alerting-upgrade</link>
            <guid isPermaLink="false">elastic-stack-observability-alerting-upgrade</guid>
            <pubDate>Thu, 04 Sep 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Exploring the latest enhancements in Elastic Stack alerting, including improved related alert grouping, linking dashboards to alert rules, and embedding investigation guides into alerts.]]></description>
            <content:encoded><![CDATA[<p>In the 9.1 release, we've made significant upgrades to alerting to help SREs and operators cut through the noise, understand what's happening faster, and take meaningful action with less guesswork.</p>
<p>Here's what's new:</p>
<h2>Improved Related Alert Grouping with Relevance Scoring &amp; Reasoning</h2>
<p>We've enhanced our related alert detection to go beyond surface-level correlations. Alerts are now grouped based on a relevance score that reflects the strength of their relationship across dimensions like:</p>
<ul>
<li><strong>Shared entities or resources</strong> (e.g. same host, pod, or service)</li>
<li><strong>Temporal proximity</strong> (alerts firing within a suspiciously short window)</li>
<li><strong>Signal similarity</strong> (e.g. spikes in logs, metrics, and traces that point to the same failure mode)</li>
</ul>
<p>More importantly, we now <strong>show the why</strong>. You'll see why an alert is grouped, whether it's sharing the same Kubernetes pod, has similar log patterns, or was triggered by the same upstream anomaly. This gives users confidence in the grouping logic and accelerates root cause analysis.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/elastic-stack-observability-alerting-upgrade/alerting-1.jpg" alt="Related Alerts" /></p>
<h2>Link Dashboards to Alert Rules and Get Smart Suggestions</h2>
<p>You can now <strong>link dashboards directly to your alert rules</strong>, giving responders an instant visual lens into the metrics or logs that matter most for that alert. No more scrambling to remember which dashboard to check — just click and go.</p>
<p>And we've made this smarter too: Elastic will now <strong>suggest relevant dashboards</strong> based on the alert's source, rule logic, or monitored entities, helping users land on the right view without needing to configure anything upfront.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/elastic-stack-observability-alerting-upgrade/alerting-2.jpg" alt="Related Alerting Dashboards" /></p>
<h2>Investigation Guides Embedded Into Alerts</h2>
<p>Every alert can now be configured with an <strong>investigation guide</strong>, a set of pre-configured, context-aware instructions or next steps tailored to the alert. Think of it as a playbook that's embedded right where and when you need it.</p>
<p>Use it to:</p>
<ul>
<li>Document your team's runbooks and standard triage steps or link to existing runbooks</li>
<li>Guide junior engineers or on-call responders through unfamiliar territory</li>
<li>Automate the first few steps of root cause analysis</li>
</ul>
<p><img src="https://www.elastic.co/observability-labs/assets/images/elastic-stack-observability-alerting-upgrade/alerting-3.jpg" alt="Investigation Guide" /></p>
<h2>Why This Matters</h2>
<p>These changes are all about reducing time to detect (MTTD) and time to resolve (MTTR). By:</p>
<ul>
<li>Grouping alerts more intelligently (and transparently)</li>
<li>Giving you the dashboards you need, when you need them</li>
<li>Embedding action-oriented guides in every alert</li>
</ul>
<p>We're bringing you closer to a truly streamlined incident response workflow; No swivel-chairing, no guesswork, just clarity.</p>
<p>Additionally, look at some of our other articles on Elastic Observability Labs related to analysis:</p>
<ul>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/ai-assistant">Using the AI Assistant in Elastic Observability to Accelerate Root Cause Analysis</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/log-analytics">All of the log analytics features in Elastic Observability</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/opentelemetry">Our latest on OpenTelemetry support in Elastic Observability</a></p>
</li>
</ul>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/elastic-stack-observability-alerting-upgrade/cover-alerting.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Kubernetes observability: SLO templates that turn alerts into error budgets]]></title>
            <link>https://www.elastic.co/observability-labs/blog/kubernetes-observability-slo-error-budget-templates</link>
            <guid isPermaLink="false">kubernetes-observability-slo-error-budget-templates</guid>
            <pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Two bad rollouts burned 88% of a 30-day error budget while the SLI still read 99.56%. This post adds four SLO templates that bring burn-rate tracking to the OTel-based alert rules from Part 1, no new instrumentation required.]]></description>
            <content:encoded><![CDATA[<p>Two bad rollouts on one Deployment burned <strong>88%</strong> of a <strong>30-day</strong> error budget in a day and fired a 26X burn-rate alert while the SLI still read 99.56%. That is the gap <a href="https://www.elastic.co/observability-labs/blog/kubernetes-dashboards-alerts-anomaly-detection">Part 1</a> alert rules cannot close on their own: they page when replicas drop; they do not tell you how much monthly reliability budget the incident cost.</p>
<p>The <strong>Kubernetes OpenTelemetry Assets</strong> package now ships four <strong>Kubernetes SLO templates</strong> for Deployments, StatefulSets, DaemonSets, and Jobs on those OTel metrics. If you already followed <a href="https://www.elastic.co/observability-labs/blog/kubernetes-dashboards-alerts-anomaly-detection">Part 1</a> and have the dashboards and alert rules, create an SLO from a template and you get SLI, remaining budget, and burn rate without new instrumentation.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/kubernetes-observability-slo-error-budget-templates/k8s_integration_extension.png" alt="Kubernetes observability with Elastic, flow diagram of OTel metrics and events into Dashboards, Alert rules with Page, ML jobs with Anomaly, and SLOs with Burn rate, converging on Overview to workload detail to pod logs" /></p>
<p>The diagram above extends the stack from <a href="https://www.elastic.co/observability-labs/blog/kubernetes-dashboards-alerts-anomaly-detection">Part 1</a>. The <strong>Kubernetes OpenTelemetry Assets</strong> package (<code>kubernetes_otel</code>) 2.3.0 includes:</p>
<ul>
<li>Dashboards designed for drill-down (Part 1)</li>
<li>Alert rule templates that fire on known bad states (Part 1)</li>
<li>ML anomaly detection jobs with workload baselines (Part 1)</li>
<li>SLO templates for rolling 30-day budgets (this post)</li>
</ul>
<p>All four use the same OTel metrics. Burn rate alerts on an SLO send you back into Overview, Workloads, and Deployment Details when the number alone is not enough.</p>
<h2>Why Kubernetes observability needs SLO monitoring alongside alerts</h2>
<p><a href="https://www.elastic.co/observability-labs/blog/kubernetes-dashboards-alerts-anomaly-detection">Part 1</a> built the reactive stack for the engineer who gets paged at 3 AM. SLOs serve the planning conversation on a <strong>30-day</strong> horizon: <strong>Are we meeting our reliability commitments?</strong> They give platform and engineering leaders a number for prioritisation: how much error budget remains and which workload is burning it fastest. The table later in this post maps each SLO template to its Part 1 alert counterpart.</p>
<p>The SLO templates in this post are part of the <strong>Kubernetes OpenTelemetry Assets</strong> package (<code>kubernetes_otel</code>). Install the <a href="https://www.elastic.co/docs/reference/integrations/kubernetes_otel">Kubernetes OpenTelemetry Assets package</a> and confirm your cluster is already sending Kubernetes metrics through OpenTelemetry (the same pipeline from Part 1). No additional instrumentation is required.</p>
<h2>Four SLO templates for Kubernetes Deployments, StatefulSets, DaemonSets and Jobs</h2>
<p>In <strong>Integrations → Kubernetes OpenTelemetry → Assets</strong>, enable any of the four templates below. Names match Kibana; each includes the <code>[Kubernetes OTel]</code> prefix in the UI.</p>
<table>
<thead>
<tr>
<th><strong>Template</strong></th>
<th><strong>Rolling objective</strong></th>
<th><strong>Package description</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Deployment Replica Availability 99.5% Rolling 30 Days</strong></td>
<td>99.5% / 30d</td>
<td>Tracks Deployment availability from OTel metrics: 99.5% of intervals should have each Deployment at its desired replica count. When <code>k8s.deployment.available &lt; k8s.deployment.desired</code>, the workload has fewer healthy replicas than configured.</td>
</tr>
<tr>
<td><strong>StatefulSet Replica Availability 99.5% Rolling 30 Days</strong></td>
<td>99.5% / 30d</td>
<td>Same pattern for StatefulSets, where pod identity and ordering matter for databases, queues, and caches.</td>
</tr>
<tr>
<td><strong>DaemonSet Scheduling Availability 99.0% Rolling 30 Days</strong></td>
<td>99.0% / 30d</td>
<td>Tracks whether each DaemonSet runs on all eligible nodes. Covers node-level agents such as log collectors, monitoring, security, and CNI plugins.</td>
</tr>
<tr>
<td><strong>Job Completion Success Rate 99.0% Rolling 30 Days</strong></td>
<td>99.0% / 30d</td>
<td>Tracks batch Jobs (ETL, backups, pipelines, scheduled tasks) completing without failed pods over the rolling window.</td>
</tr>
</tbody>
</table>
<p>Each is a <strong>timeslice-metric SLO</strong>: Elastic marks every five-minute window good or bad, then rolls those results into a <strong>30-day rolling</strong> objective per namespace and workload.</p>
<p>Reliability is scored at two levels. Each five-minute slice gets one verdict: Elastic aggregates OTel metrics in that window, evaluates the template equation, and compares the result to the metric threshold. For Deployments, that is <code>sum(available) / sum(desired) &gt;= 1</code>. At a ~30-second OTel scrape cadence, that is roughly ten measurements per slice, and the slice passes or fails on the aggregated result. The SLO target (99.5% or 99.0%) is the share of slices that must pass across the rolling window. Over 30 days at five-minute slices, that is 8,640 possible slices per workload (30 × 24 × 12). After you create an SLO from a template, the SLO detail view shows how many slices passed and how much error budget remains.</p>
<p>At 99.5%, a workload can miss roughly 43 of those slices (~3.6 hours of bad slices) before breach. At 99.0%, about 86 slices (~7.2 hours).</p>
<h3>How to set SLO targets by Kubernetes workload type</h3>
<p>We picked defaults per workload type, not one number for the whole cluster.</p>
<p><strong>Deployments and StatefulSets at 99.5%:</strong> We considered 99.9% (~43 minutes per month), which fits a single critical API or a formal SLA buffer. For a default integration template across many Deployments, 99.5% (~3.6 hours) leaves room for normal rollout churn: a 20-minute bad image tag is roughly half the monthly budget at 99.9%, but a small fraction at 99.5%. Tune per workload; payment paths often warrant 99.9% or higher.</p>
<p><strong>DaemonSets and Jobs at 99.0%:</strong> We considered 99.5% for DaemonSets, but node additions, replacements, and rolling updates often leave <code>ready_nodes</code> below <code>desired_scheduled_nodes</code> for several minutes per event. At 99.5%, that normal platform churn would burn error budget on infrastructure agents (log collectors, monitoring, CNI) as if they were user-facing outages. 99.0% (~7.2 hours) absorbs that lifecycle noise. Jobs get 99.0% for a different reason: a failed ETL run usually hurts data freshness, not live request availability, and failures can sit unnoticed until downstream teams see stale reports.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/kubernetes-observability-slo-error-budget-templates/k8s-workload-resources.png" alt="Kubernetes observability with Elastic, Workload resources dashboard showing Deployments, DaemonSets, StatefulSets, Jobs, and ReplicaSets with availability and replica metrics" /></p>
<h3>Deployment replica availability (99.5%)</h3>
<pre><code>Metric:     sum(k8s.deployment.available) / sum(k8s.deployment.desired) &gt;= 1
Target:     99.5% of 5-minute timeslices over 30 days
Group by:   resource.attributes.k8s.namespace.name + resource.attributes.k8s.deployment.name
</code></pre>
<p>When <code>available &lt; desired</code>, the application runs fewer healthy replicas than configured. Failed rollouts, crash loops, and node loss all show up here. <strong>99.5%</strong> leaves roughly <strong>3.6 hours</strong> of degradation per deployment per month before breach.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/kubernetes-observability-slo-error-budget-templates/slo-detail-deployment-healthy.png" alt="Kubernetes observability with Elastic, grid of Deployment Replica Availability 99.5% Rolling 30 Days SLO cards at 100% for default and kube-system namespaces" /></p>
<p>Grouping by namespace and deployment name creates one SLO per workload. A cluster-wide average would let a healthy <code>frontend</code> mask a burning <code>checkout</code>. Linked dashboards (<strong>Overview</strong> and <strong>Workloads</strong>) connect the SLO view to investigation context in one click; from Workloads you drill into <strong>Deployment Detail</strong> for the failing deployment.</p>
<h3>StatefulSet replica availability (99.5%)</h3>
<pre><code>Metric:     sum(k8s.statefulset.ready_pods) / sum(k8s.statefulset.desired_pods) &gt;= 1
Target:     99.5% of 5-minute timeslices over 30 days
Group by:   resource.attributes.k8s.namespace.name + resource.attributes.k8s.statefulset.name
</code></pre>
<p>When <code>ready_pods &lt; desired_pods</code>, the StatefulSet reports fewer Ready replicas than configured. Ordered rollouts, stuck pods, and node loss show up here too. Rollouts proceed in order, and each pod keeps its name and volume, so a missing replica can stay below desired longer than a stateless pod would.</p>
<p>Grouping by namespace and StatefulSet name avoids a healthy workload masking another that is burning the SLO budget. </p>
<h3>DaemonSet scheduling availability (99.0%)</h3>
<pre><code>Metric:     sum(k8s.daemonset.ready_nodes) / sum(k8s.daemonset.desired_scheduled_nodes) &gt;= 1
Target:     99.0% of 5-minute timeslices over 30 days
Group by:   resource.attributes.k8s.namespace.name + resource.attributes.k8s.daemonset.name
</code></pre>
<p>DaemonSets run node-level infrastructure: log collectors, monitoring agents, security agents, and network plugins. When <code>ready_nodes &lt; desired_scheduled_nodes</code>, an eligible node lacks a Ready pod, which can leave that node without logs or metrics from that agent. Rolling updates and new nodes drive most gaps; pods that never become Ready show the same signal. Cordoned nodes often still run DaemonSet pods. 99.0% (~7.2 hours per month) reflects that churn. </p>
<p>Group by namespace and DaemonSet name so a healthy <code>fluentd</code> does not mask a broken <code>node-exporter</code> on the same SLO budget.</p>
<h3>Job completion success rate (99.0%)</h3>
<pre><code>Metric:     max(k8s.job.failed_pods) &lt;= 0
Target:     99.0% of 5-minute timeslices over 30 days
Group by:   resource.attributes.k8s.namespace.name + resource.attributes.k8s.job.name
</code></pre>
<p>Jobs cover batch workloads: ETL pipelines, backups, database migrations, and scheduled reports. When <code>failed_pods &gt; 0</code>, at least one pod created by the Job reached the <strong>Failed</strong> phase. Application errors, timeouts, and missing dependencies drive many failures; when retries reach the configured <code>backoffLimit</code>, Kubernetes marks the Job as <strong>Failed</strong>. Missed runs often surface as stale or delayed data, not as a serving outage. 99.0% (~7.2 hours per month) reflects that occasional batch failure is less time-sensitive than a Deployment or StatefulSet breach. </p>
<h2>How do SLOs and alerts work together in Kubernetes observability?</h2>
<p>The SLO templates and the alert rules from <a href="https://www.elastic.co/observability-labs/blog/kubernetes-dashboards-alerts-anomaly-detection">Part 1</a> serve different people asking different questions at different times.</p>
<table>
<thead>
<tr>
<th><strong>SLO Template</strong></th>
<th><strong>Alert rule (Part 1)</strong></th>
<th><strong>Failure consequence</strong></th>
<th><strong>Monthly budget (30d)</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>Deployment Replica Availability</td>
<td>Deployment below the desired replicas</td>
<td>Reduced throughput, degraded UX</td>
<td>~3.6 hours at 99.5%</td>
</tr>
<tr>
<td>StatefulSet Replica Availability</td>
<td>No dedicated rule. Covered by CrashLoopBackOff / OOMKilled at pod level</td>
<td>Split-brain risk, degraded durability</td>
<td>~3.6 hours at 99.5%</td>
</tr>
<tr>
<td>DaemonSet Scheduling Availability</td>
<td>Pod stuck in Pending / node disk pressure</td>
<td>Blind spots: unmonitored nodes and gaps in node-level coverage</td>
<td>~7.2 hours at 99.0%</td>
</tr>
<tr>
<td>Job Completion Success Rate</td>
<td>CrashLoopBackOff / OOMKilled</td>
<td>Stale or incomplete data</td>
<td>~7.2 hours at 99.0%</td>
</tr>
</tbody>
</table>
<p>Alert rules answer: <em>Is something broken right now?</em> They fire within minutes, page the on-call engineer, and expect immediate action.</p>
<p>SLO templates answer: <em>Are we meeting our reliability commitments over time?</em> They accumulate signal across weeks and turn prioritisation debates into a number tied to remaining budget.</p>
<h3>From incident to error budget burn: a Kubernetes walkthrough</h3>
<p>A deployment drops from <code>3/3</code> to <code>2/3</code> available replicas during a rolling update. The new pod fails its readiness probe. Here is what happened in our test cluster, from dashboard signal through alert, SLO impact, and root cause.</p>
<p><strong>Rollout begins.</strong> The Deployment dashboard shows <code>available: 2, desired: 3</code>. The Part 1 <strong>Deployment unavailable replicas</strong> rule has a <strong>5-minute</strong> grace period, so on-call is not paged yet during a short rollout gap. The Deployment Detail view for <code>web-frontend</code> shows available replicas dropping while desired stays at 3. The Deployment replicas over time chart marks where the rollout started to fail.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/kubernetes-observability-slo-error-budget-templates/k8s-workdload-replicaset-drop.png" alt="Kubernetes observability with Elastic, Workload resources view for web-frontend in blog-demo at 66.67% availability with available replicas at 2 of 3 desired and the replicas-over-time chart showing the drop" /></p>
<p><strong>Alert fires, then root cause.</strong> After the grace period, the alert rule triggers: <em>Deployment unavailable replicas</em>. The on-call engineer opens the Workloads dashboard, finds <code>web-frontend</code> at <code>available: 2, desired: 3</code>, and drills into Deployment Detail. The replicas-over-time chart confirms when availability dropped. </p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/kubernetes-observability-slo-error-budget-templates/k8s-replica-alert-trigger.png" alt="Kubernetes observability with Elastic, Deployment unavailable replicas alert rule showing active alerts after the replica drop" /></p>
<p>In <strong>Discover</strong>, filter Kubernetes events for that pod with <code>k8s.object.name: &quot;web-frontend-796fcd55b9-jmlkh&quot;</code>. The event stream shows <code>ImagePullBackOff</code> and <code>Back-off pulling image &quot;nginx:nonexistent-tag-999&quot;</code>. The rollout references an image tag that does not exist.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/kubernetes-observability-slo-error-budget-templates/k8s-discoverview-image-error.png" alt="Kubernetes observability with Elastic, Discover view showing ImagePullBackOff events for the web-frontend pod after a bad image tag" /></p>
<p><strong>Rollback and recovery.</strong> The engineer runs <code>kubectl rollout undo deployment/web-frontend</code>. Replicas return to <code>3/3</code>.</p>
<h3>How two rollouts consumed 88% of a 30-day error budget</h3>
<p>The rollback fixed availability. The SLO still counted the day's failures.</p>
<p>Two rollout failures left <code>web-frontend</code> with <strong>39 failed timeslices</strong> where <code>available &lt; desired</code>. That consumed <strong>88.0%</strong> of the <strong>30-day error budget</strong>. The SLI still read <strong>99.56%</strong>, above the <strong>99.5%</strong> target, but only <strong>12%</strong> of the monthly allowance remained.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/kubernetes-observability-slo-error-budget-templates/k8s-slo-webserver-overview.png" alt="Kubernetes observability with Elastic, Deployment Replica Availability SLO for web-frontend showing SLI above target with most of the error budget already consumed" /></p>
<p>The burn rate alert fired next, even though replicas were healthy again. Over the past day the deployment consumed budget at <strong>26×</strong> the rate a <strong>99.5%</strong> SLO can sustain long term. Each failed 5-minute timeslice uses roughly <strong>2.3%</strong> of the monthly budget (about <strong>43</strong> failures allowed per 30 days). Thirty-nine failures across two rollouts is worth a reliability review, not a one-line postmortem. The burn rate alert often matters more than the raw SLI mid-month because it fires while you still have budget left to spend deliberately.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/kubernetes-observability-slo-error-budget-templates/slo-burnrate-alert.png" alt="Kubernetes observability with Elastic, Alerts page showing an active critical burn rate alert for the web-frontend Deployment Replica Availability SLO" /></p>
<h2>Try it yourself: trigger an error budget burn on a test Deployment</h2>
<p>If you already have <strong>Kubernetes OpenTelemetry Assets</strong> installed, the SLO templates live under <strong>Integrations → Kubernetes OpenTelemetry → Assets</strong>.</p>
<p>Create a <strong>Deployment replica availability</strong> SLO for the deployment you use below. Open the SLO and note the baseline: current SLI, remaining error budget, and existing timeslice history.</p>
<p>Create an isolated namespace and a small deployment so the exercise does not affect production workloads. Wait a few minutes for the OTel collector to scrape metrics before you create the SLO.</p>
<pre><code>kubectl create namespace blog-demo
kubectl create deployment web-frontend --namespace blog-demo --image=nginx:latest --replicas=3
</code></pre>
<p>Trigger a bad rollout with a non-existent image tag:</p>
<pre><code>kubectl get deployment web-frontend -n blog-demo
kubectl set image deployment/web-frontend nginx=nginx:nonexistent-tag-999 --namespace blog-demo
</code></pre>
<p>Within a few minutes a new pod enters <code>ImagePullBackOff</code>, available replicas drop below desired, and the SLO records failed timeslices. Roll back to recover:</p>
<pre><code>kubectl rollout undo deployment/web-frontend -n blog-demo
</code></pre>
<p>Refresh the SLO view. You should see new failed timeslices in the 30-day history and a reduction in remaining error budget.</p>
<p>One failed timeslice consumes about <strong>2.3%</strong> of the monthly error budget at <strong>99.5%</strong>. Repeat that across deployments in a week and the burn rate alert becomes the prioritisation signal.</p>
<p>When you are done, delete the test namespace with:</p>
<pre><code>kubectl delete namespace blog-demo
</code></pre>
<h2>What's next: from SLO monitoring to agentic remediation</h2>
<p>Alerts tell you replicas dropped. SLOs tell you how much monthly budget that cost. In the walkthrough above, the same ImagePullBackOff showed up in Deployment Detail, the unavailable-replicas alert, and failed timeslices on the replica-availability SLO, all from the OTel pipeline you installed in <a href="https://www.elastic.co/observability-labs/blog/kubernetes-dashboards-alerts-anomaly-detection">Part 1</a>. The SLI still read <strong>99.56%</strong> while <strong>88%</strong> of the monthly error budget was gone.</p>
<p><a href="https://www.elastic.co/observability-labs/blog/kubernetes-dashboards-alerts-anomaly-detection">Part 1</a> closed by previewing <strong>Agentic Investigations</strong>: investigation workflows that run when an alert fires, with skills, tools, and MCP views. This post adds the SLO layer on those same metrics so you can quantify reliability debt before automating runbooks. A follow-up post will cover that agentic workflow and propose remediations you review before applying.</p>
<p>Which remediations would you trust a workflow to suggest on a Kubernetes incident, and which would you keep manual? <a href="https://discuss.elastic.co/c/observability">Join the Elastic Community discussion</a>.</p>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/kubernetes-observability-slo-error-budget-templates/kubernetes-observability-slo-error-budget-templates.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Monitoring Proxmox VE deployments with Elastic Observability]]></title>
            <link>https://www.elastic.co/observability-labs/blog/monitoring-proxmox-ve-with-elastic</link>
            <guid isPermaLink="false">monitoring-proxmox-ve-with-elastic</guid>
            <pubDate>Wed, 23 Jul 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Monitoring Proxmox VE deployments, VMs, and Linux Containers with Elastic Observability.]]></description>
            <content:encoded><![CDATA[<p>In this blog post, you will learn how to leverage Elastic Observability to monitor Proxmox VE and the software running on top of it, both in the form of Linux Containers (LXCs) and Virtual Machines (VMs).</p>
<h2>Why use Elastic Observability with Proxmox?</h2>
<p>Here at Elastic, we are passionate about efficiently managing and monitoring infrastructure and applications. Many of us have fun playing with home labs, oftentimes running Proxmox VE, a powerful open-source virtualization platform used to run virtual machines and Linux Containers (LXCs) with ease. While Proxmox provides robust tools for managing virtualized resources, gaining deep insights into the performance and health of your LXCs, VMs, and hosts requires a comprehensive monitoring solution. This blog post will guide you through leveraging the power of Elastic Observability, in conjunction with Elastic Agent, to effectively monitor your Proxmox VE deployment, ensuring optimal performance and proactive issue resolution thanks to Kibana Alerts.</p>
<h2>The homelab setup</h2>
<p>Our homelab setup centers around an Intel N100 mini PC, serving as the host for Proxmox VE. This setup is simple and minimal, yet effective for showcasing a few interesting capabilities. On top of this mini PC, we run several Linux Containers (LXCs) for various services, along with a dedicated virtual machine for Home Assistant.</p>
<h2>Elastic Agent installation and configuration</h2>
<p>Before beginning, it is worth noting that there are numerous ways to install and configure the Elastic Agent. For the sake of simplicity, we will showcase a setup in which only one instance of the Elastic Agent is running on the host machine. The Elastic Agent reports to an Elastic Cloud Observability deployment and is managed via Fleet, which makes it tremendously easy to upgrade and re-configure it whenever needed.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/monitoring-proxmox-ve-with-elastic/fleet-prox.jpg" alt="The Elastic Integrations enabled for our Proxmox host" /></p>
<h2>Diving into the host</h2>
<p>Kibana offers various panes that make it nice and easy to learn about a system's health at a quick glance.</p>
<p>As a first step, let's take a look at the <code>Infrastructure &gt; Hosts</code> page in Kibana:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/monitoring-proxmox-ve-with-elastic/kibana-infrastructure-hosts-proxmox.jpg" alt="The Infrastructure &gt; Hosts Kibana page for our Proxmox host" /></p>
<p>Here we can see various information about our Proxmox VE host (i.e. the mini PC). The top processes running on it are presented, including processes running in LXCs such as <code>pia-daemon</code>. We can also see a <code>kvm</code> process, specifically running a Home Assistant virtual machine, and a Proxmox <code>pve-firewall</code> process.</p>
<p>Let's now take a look at <code>Universal Profiling &gt; Flamegraph</code>. This graph shows how much CPU time is consumed by different stack traces from processes running on the host system. You can drill down into specific processes using the search bar at the top. For instance, you can filter by <code>kvm</code> to only see information regarding this specific process.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/monitoring-proxmox-ve-with-elastic/universal-profiling-flamegraph-kvm.jpg" alt="The Universal Profiling &gt; Flamegraph Kibana page for our Proxmox host" /></p>
<h2>The Observability AI Assistant</h2>
<p>All the Kibana panes we visited so far have proved to be highly interesting, but they struggle to answer urgent questions such as:</p>
<ul>
<li>did anything happen in our mini PC recently?</li>
<li>was there any significant change in functionality?</li>
<li>is there any precious information hidden among the thousands of data points collected?</li>
</ul>
<p>The Elastic Observability AI Assistant helps us by answering these questions in natural language. By default, on Elastic Cloud, it uses the Elastic-managed LLM connector, which means users do not need to configure anything to get started with it. It just works!</p>
<p>Let's go to the <code>Observability &gt; AI Assistant</code> pane in Kibana and let's try to ask a generic prompt such as: &quot;please give me an overview of the health of my <code>prox</code> host&quot;.</p>
<p>Let's then wait a minute so that it can dig into the data... et voilà, here comes lots of relevant information in the form of graphs and natural language explanations. The Observability AI Assistant understood our question, went through all the data for our Proxmox host, ran data analytics on it, and reported back in a matter of seconds!</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/monitoring-proxmox-ve-with-elastic/observability-ai-assistant-1.jpg" alt="The Observability AI Assistant's first reply" /></p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/monitoring-proxmox-ve-with-elastic/observability-ai-assistant-2.jpg" alt="The Observability AI Assistant's second reply" /></p>
<h2>Alerting upon disruption with Kibana Alerts</h2>
<p>As a final step, let's try to define a Kibana Alert to help us understand whether our host is overloaded. Let's head to <code>Observability &gt; Alerts &gt; Rules</code> and create a new rule. We will create a Custom Threshold rule that will fire if CPU usage for the host is higher than 80% on average for the last 15 minutes. Kibana will send us an email in case the rule fires. The rule is also configured to fire if no data appears for the last 15 minutes, which is extremely helpful as it would imply the presence of some issues to be debugged: broken network or no electricity in the house, a faulty Agent deployment, or even a hardware issue with the mini PC.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/monitoring-proxmox-ve-with-elastic/rule-cpu-over-80.jpg" alt="The Kibana Alerting Rule for CPU being over 80 percent" /></p>
<h2>Conclusion</h2>
<p>In this blog post we showcased how to effectively use the Elastic Stack to monitor Proxmox VE deployments. If you would like to try out such a setup first-hand, you are more than welcome to enjoy <a href="https://www.elastic.co/cloud/cloud-trial-overview">Elastic Cloud's 14-days free trial</a>.</p>
<p>In future blog posts, we will investigate how to dig deeper into LXCs and VMs to gather even more information from our home lab and create more tailored alerts. Stay tuned!</p>]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/monitoring-proxmox-ve-with-elastic/article-image.jpg" length="0" type="image/jpg"/>
        </item>
    </channel>
</rss>