<?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 - SLO</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 - SLO</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[Contextual AI: Stop pinging the SRE: three MCP tools that turn Elastic Agent Builder into your team's runbook]]></title>
            <link>https://www.elastic.co/observability-labs/blog/mcp-tools-elastic-agent-builder</link>
            <guid isPermaLink="false">mcp-tools-elastic-agent-builder</guid>
            <pubDate>Thu, 04 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Build three MCP tools in Elastic Agent Builder that read endpoint health, recent deploys and SLO burn rate directly in your editor. Encode your platform team's runbook once; every developer gets self-serve production context without pinging an SRE.]]></description>
            <content:encoded><![CDATA[<p>A developer asks their editor, &quot;Is it safe to merge this PR?&quot; and gets a real answer in seconds, not a 10–15 minute dashboard hunt or a Slack ping to an SRE. This post shows how to build three MCP tools in Elastic Agent Builder that read endpoint health, recent deploys, and SLO burn rate, and encode the platform team's interpretation rules, error rate thresholds, deploy warm-up windows, and burn rate limits directly into the tool descriptions. The result is contextual AI: an agent that reasons over production signals using the runbook the platform team wrote once.</p>
<h2>Prerequisites for Elastic Agent Builder MCP tools</h2>
<ul>
<li>An <a href="https://cloud.elastic.co/registration">Elastic Cloud</a> deployment with Elastic Stack 9.3+ (or Elastic Cloud Serverless) with Agent Builder enabled.</li>
<li>An APM-ingested service. If your cluster does not already have APM data, the companion notebook includes instructions to generate synthetic traffic using <a href="https://github.com/elastic/apm-integration-testing">elastic/apm-integration-testing</a> with the <code>opbeans-node</code> demo app.</li>
<li>An MCP-compatible client: <a href="https://docs.anthropic.com/en/docs/claude-code/overview">Claude Code</a>, <a href="https://www.cursor.com/">Cursor</a>, or VS Code with an MCP extension.</li>
<li>Basic familiarity with <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html">ES|QL</a> syntax.</li>
<li><a href="https://nodejs.org/">Node.js</a> 18+ (for the <code>mcp-remote</code> bridge).</li>
</ul>
<p>If you are new to MCP or need to set up the Elastic MCP server for the first time, check out <a href="https://www.elastic.co/search-labs/blog/elastic-mcp-server-agent-builder-tools">Connect Agent Builder tools to any AI agent with Elastic MCP server</a> for the full setup walkthrough. This article assumes the MCP server is already configured.</p>
<h2>The problem: why developers fly blind</h2>
<p>A developer is about to merge a pull request. The change looks simple: increasing the timeout for the downstream <code>recommendations</code> service call from 2 seconds to 5 seconds. But before hitting the merge button, a question lingers: <em>is the service healthy enough to absorb this change right now?</em></p>
<p>To answer that question today, the developer has two options:</p>
<ol>
<li><strong>Check dashboards manually.</strong> Open the APM UI, look at error rates, scan latency charts, find the SLO page, and look for recent deploys. This takes 10-15 minutes and requires knowing what to look for and how to interpret it.</li>
<li><strong>Ask an SRE.</strong> Ping the platform team on Slack: &quot;Hey, is checkout healthy? I want to merge something.&quot; This creates an interruption, adds latency to the decision, and doesn't scale.</li>
</ol>
<p>The core problem is not the data. Elastic already collects everything: traces, metrics, error logs, deploy markers, and SLO budgets. The problem is that <strong>correlating multiple signals requires mental overhead and domain knowledge that most developers don't have</strong>.</p>
<p>An SRE knows that a p99 spike after a deploy is normal for 5 minutes, that an error rate under 0.5% is acceptable during a release window, and that merging when the SLO budget is below 20% is risky. That knowledge lives in runbooks, tribal memory, and experience.</p>
<p>What if the platform engineer could encode that knowledge into tools that any developer can query from their editor?</p>
<h2>How MCP tools in Elastic Agent Builder encode your runbook</h2>
<p>The key insight is this: <strong>a tool is not just a query; it is a query plus interpretation</strong>. A dashboard shows you a p99 of 450ms. A well-designed tool tells you &quot;p99 is 450ms, which is within normal range for this service, and has been stable since the last deploy 2 hours ago.&quot;</p>
<p>The difference is that the tool description carries the domain knowledge. When a platform engineer creates a tool in <a href="https://www.elastic.co/search-labs/blog/elastic-ai-agent-builder-context-engineering-introduction">Agent Builder</a>, they write descriptions like: &quot;Error rate above 1% typically indicates a regression. If this coincides with a recent deploy, the deploy is the likely cause.&quot; That description becomes part of the context the AI agent uses when reasoning across multiple tool results.</p>
<p>This is what we mean by <em>contextual AI</em>: the AI agent does not just fetch data; it reasons over it using the interpretation rules that the platform team encoded.</p>
<p>Here is the architecture:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/mcp-tools-elastic-agent-builder/image-02.png" alt="Architecture: developer editor with MCP client connecting to Elastic Agent Builder tools authored by the platform engineer" /></p>
<p>The platform engineer authors the tools once. Every developer on the team benefits from their own editor, without needing to learn ES|QL or understand APM data models.</p>
<h2>Setting up the Elastic Agent Builder sample environment</h2>
<p>The full end-to-end setup (traffic generation with <a href="https://github.com/elastic/opbeans-node">opbeans-node</a>, deploy annotations, SLO creation, and the three Agent Builder tools) is available as a runnable notebook at this repository: <a href="https://github.com/Delacrobix/OART-Contextual-AI-Bridging-the-Gap-between-Platform-Engineering-and-Product-Development/blob/main/notebook.ipynb"><code>notebook.ipynb</code></a>. The sections below focus on the ES|QL queries and tool descriptions: the <em>why</em> behind each tool, not the mechanics of posting them.</p>
<h2>Building Tool 1: get_endpoint_health</h2>
<p>This tool answers the question: &quot;How is this endpoint performing right now?&quot; It returns error rate, latency percentiles (p50, p95, p99), and throughput for a given service and endpoint within a time window.</p>
<p>Here is the full <a href="https://www.elastic.co/docs/explore-analyze/ai-features/agent-builder/tools/esql-tools">tool configuration</a> as created in Agent Builder:</p>
<pre><code class="language-json">{
  &quot;id&quot;: &quot;get_endpoint_health&quot;,
  &quot;type&quot;: &quot;esql&quot;,
  &quot;description&quot;: &quot;Returns the current health of a service endpoint: error rate, latency percentiles (p50/p95/p99), and throughput. Use this tool to assess whether a service is healthy before making changes. Interpretation guide: error rate below 0.5% is healthy, 0.5-1% is elevated (check for recent deploys), above 1% indicates a problem. For latency, compare p99 against the service baseline: checkout is typically under 500ms, product-search under 200ms. A sudden p99 spike within 15 minutes of a deploy suggests the deploy caused a regression.&quot;,
  &quot;tags&quot;: [&quot;apm&quot;, &quot;reliability&quot;, &quot;health&quot;],
  &quot;configuration&quot;: {
    &quot;query&quot;: &quot;FROM traces-apm-* | WHERE service.name == ?serviceName AND @timestamp &gt;= NOW() - ?timeWindow AND transaction.duration.us IS NOT NULL | STATS total_transactions = COUNT(*), error_count = SUM(CASE(event.outcome == \&quot;failure\&quot;, 1, 0)), p50_latency_ms = PERCENTILE(transaction.duration.us, 50) / 1000, p95_latency_ms = PERCENTILE(transaction.duration.us, 95) / 1000, p99_latency_ms = PERCENTILE(transaction.duration.us, 99) / 1000 BY service.name | EVAL error_rate_pct = ROUND(error_count / total_transactions * 100, 2) | EVAL throughput_per_min = ROUND(total_transactions / ?windowMinutes, 1)&quot;,
    &quot;params&quot;: {
      &quot;serviceName&quot;: {
        &quot;type&quot;: &quot;keyword&quot;,
        &quot;description&quot;: &quot;The APM service name to check (e.g., opbeans-node)&quot;
      },
      &quot;timeWindow&quot;: {
        &quot;type&quot;: &quot;keyword&quot;,
        &quot;description&quot;: &quot;Time window to analyze, in ES|QL duration format (e.g., 30 minutes, 1 hour, 6 hours)&quot;
      },
      &quot;windowMinutes&quot;: {
        &quot;type&quot;: &quot;integer&quot;,
        &quot;description&quot;: &quot;Time window in minutes, used to calculate throughput per minute&quot;
      }
    }
  }
}
</code></pre>
<p>The query uses the <a href="https://www.elastic.co/observability-labs/blog/elastic-discover-traces-apm"><code>traces-apm-*</code></a> data stream, which contains raw transaction data. We filter with <code>transaction.duration.us IS NOT NULL</code> to select only transaction events (excluding spans). Using <code>traces-apm-*</code> is more portable than the pre-aggregated <code>metrics-apm.transaction.1m-*</code> stream, which only populates after sustained traffic.</p>
<p>Notice the <code>description</code> field. It is not just &quot;returns health metrics.&quot; It includes <strong>interpretation rules</strong>: what error rate thresholds mean, what latency baselines look like, and how to correlate spikes with deploys. This is the runbook encoded in the tool.</p>
<h2>Building Tool 2: get_recent_deploys</h2>
<p>This tool answers: &quot;What has been deployed recently?&quot; Deploy history is a critical context because most production issues correlate with code changes. The agent needs this to reason about whether current metrics are normal or reflect a recent deployment.</p>
<p>Deploy annotations are stored in the <code>observability-annotations</code> index. Here is the full tool configuration:</p>
<pre><code class="language-json">{
  &quot;id&quot;: &quot;get_recent_deploys&quot;,
  &quot;type&quot;: &quot;esql&quot;,
  &quot;description&quot;: &quot;Returns the deployment history for a service over the last 24 hours, including version numbers, timestamps, and deploy messages. Use this tool to understand the deployment timeline when assessing service health. Key patterns: if a deploy happened within the last 15 minutes, elevated error rates or latency may be expected (warm-up period). If metrics degraded immediately after a deploy, the deploy is the likely cause. Multiple deploys in a short window (under 2 hours) increase risk because it becomes harder to isolate which change caused an issue.&quot;,
  &quot;tags&quot;: [&quot;apm&quot;, &quot;deploys&quot;, &quot;change-tracking&quot;],
  &quot;configuration&quot;: {
    &quot;query&quot;: &quot;FROM observability-annotations | WHERE service.name == ?serviceName AND @timestamp &gt;= NOW() - 24 hours | SORT @timestamp DESC | KEEP @timestamp, service.version, service.environment, message | LIMIT 10&quot;,
    &quot;params&quot;: {
      &quot;serviceName&quot;: {
        &quot;type&quot;: &quot;keyword&quot;,
        &quot;description&quot;: &quot;The APM service name to check deploy history for&quot;
      }
    }
  }
}
</code></pre>
<p>Again, the <code>description</code> encodes domain knowledge: the 15-minute warm-up window, the correlation between deploys and metric changes, and the risk of multiple rapid deploys. This is how a platform engineer transfers their intuition into something an AI agent can reason with.</p>
<h2>Building Tool 3: get_slo_status</h2>
<p>This tool answers: &quot;How much error budget do we have left?&quot; <a href="https://www.elastic.co/docs/solutions/observability/incident-management/service-level-objectives-slos">SLO budget</a> is the platform team's quantified way of expressing risk tolerance. If the budget is nearly spent, even a small change could cause a violation.</p>
<p>Unlike the previous tools that query APM data, this one queries the internal SLO indices where Elastic stores pre-computed SLI data. The query calculates the current burn rate, that is, how fast the service is consuming error budget relative to the allowed threshold:</p>
<pre><code class="language-json">{
  &quot;id&quot;: &quot;get_slo_status&quot;,
  &quot;type&quot;: &quot;esql&quot;,
  &quot;description&quot;: &quot;Returns the current SLO burn rate for a service over the last hour. The response includes: SLI value (current performance), error budget target, and burn rate percentage. The burn rate tells you how fast the service is consuming error budget relative to the allowed threshold. Interpretation: a burn rate below 100% means the service is consuming budget slower than the limit (sustainable). Between 100-200%, the service is burning budget faster than planned (proceed with caution). Above 200%, the service is burning budget at double the allowed rate (delay non-critical changes). Above 500%, investigate immediately. Note: this measures the current burn rate over the last hour, not cumulative budget consumption over the full SLO window. A temporarily high burn rate does not mean the overall budget is exhausted.&quot;,
  &quot;tags&quot;: [&quot;slo&quot;, &quot;reliability&quot;, &quot;budget&quot;],
  &quot;configuration&quot;: {
    &quot;query&quot;: &quot;FROM .slo-observability.sli-v* | WHERE slo.id == ?sloId AND @timestamp &gt;= NOW() - 1 hour | STATS sli_value = AVG(slo.numerator) / AVG(slo.denominator) BY slo.id, slo.name | EVAL error_budget_target = 0.995 | EVAL burn_rate_pct = ROUND((1 - sli_value) / (1 - error_budget_target) * 100, 1)&quot;,
    &quot;params&quot;: {
      &quot;sloId&quot;: {
        &quot;type&quot;: &quot;keyword&quot;,
        &quot;description&quot;: &quot;The SLO identifier. Use the SLO ID for the service you are evaluating.&quot;
      }
    }
  }
}
</code></pre>
<blockquote>
<p><strong>Note on the SLI index:</strong> the version suffix in <code>.slo-observability.sli-v*</code> depends on your Stack release (e.g., <code>v3.6</code> in Stack 9.3). Verify with <code>GET _cat/indices/.slo-observability.*?v</code> and adjust the pattern if your cluster uses a different version.</p>
</blockquote>
<p>The burn rate interpretation rules in the <code>description</code> are the most valuable part. A raw number like &quot;burn rate 85%&quot; means nothing to a developer without context. The tool description translates that into actionable guidance: &quot;below 100% means sustainable, above 200% means delay non-critical changes.&quot;</p>
<h2>Connecting to your editor via MCP</h2>
<p>With all three tools created in Agent Builder, they are automatically available through the <a href="https://www.elastic.co/docs/solutions/search/agent-builder/mcp-server">MCP server endpoint</a>. Configure your MCP client to connect.</p>
<h3>Claude Code configuration</h3>
<p>Add the Elastic MCP server to your Claude Code settings:</p>
<pre><code class="language-json">{
  &quot;mcpServers&quot;: {
    &quot;elastic-agent-builder&quot;: {
      &quot;command&quot;: &quot;npx&quot;,
      &quot;args&quot;: [
        &quot;mcp-remote&quot;,
        &quot;https://your-kibana-url/api/agent_builder/mcp&quot;,
        &quot;--header&quot;,
        &quot;Authorization: ApiKey your-base64-api-key&quot;
      ]
    }
  }
}
</code></pre>
<h3>Cursor configuration</h3>
<p>For Cursor, add the server in <strong>Settings &gt; MCP Servers</strong>:</p>
<pre><code class="language-json">{
  &quot;mcpServers&quot;: {
    &quot;elastic-agent-builder&quot;: {
      &quot;command&quot;: &quot;npx&quot;,
      &quot;args&quot;: [
        &quot;mcp-remote&quot;,
        &quot;https://your-kibana-url/api/agent_builder/mcp&quot;,
        &quot;--header&quot;,
        &quot;Authorization: ApiKey your-base64-api-key&quot;
      ]
    }
  }
}
</code></pre>
<p>Once connected, your editor's AI agent will discover all three tools automatically. You can verify by asking: &quot;What Elastic tools do you have available?&quot; The agent should list <code>get_endpoint_health</code>, <code>get_recent_deploys</code>, and <code>get_slo_status</code>.</p>
<p><strong>API key permissions:</strong> the API key needs the <a href="https://www.elastic.co/docs/solutions/search/agent-builder/kibana-api"><code>feature_agentBuilder.read</code></a> Kibana privilege and read access to the relevant indices (<code>traces-apm.*</code>, <code>observability-annotations</code>, <code>.slo-observability.*</code>). For production use, set the key expiry to 30-90 days and follow the principle of least privilege.</p>
<h2>The scenario: &quot;Is it safe to merge this PR?&quot;</h2>
<p>A developer on the team has a pull request that increases the timeout for the downstream <code>recommendations</code> service call from 2 seconds to 5 seconds in <code>opbeans-node</code>. Before merging, they ask the agent:</p>
<blockquote>
<p><strong>Developer:</strong> &quot;I'm about to merge PR #42, which increases the recommendations service timeout from 2s to 5s in opbeans-node. Is it safe to merge right now?&quot;</p>
</blockquote>
<p>The agent begins its multi-signal reasoning chain. Here is what happens.</p>
<h3>Step 1: the agent calls get_endpoint_health</h3>
<p>The agent checks the current health of the service:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/mcp-tools-elastic-agent-builder/image-03.png" alt="Agent calls get_endpoint_health and returns latency percentiles, error rate, and throughput" /></p>
<h3>Step 2: the agent calls get_recent_deploys</h3>
<p>Next, it checks for recent deployments:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/mcp-tools-elastic-agent-builder/image-04.png" alt="Agent calls get_recent_deploys and returns the recent deploy timeline for the service" /></p>
<h3>Step 3: the agent calls get_slo_status</h3>
<p><img src="https://www.elastic.co/observability-labs/assets/images/mcp-tools-elastic-agent-builder/image-05.png" alt="Agent calls get_slo_status and returns the current SLO burn rate" /></p>
<h3>The agent's response</h3>
<p>After correlating all three results, the agent produces a recommendation:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/mcp-tools-elastic-agent-builder/image-06.png" alt="Final agent recommendation correlating endpoint health, recent deploys, and SLO burn rate to flag the merge as risky" /></p>
<p>The agent pulled the current p99, checked recent deploys, and read the SLO burn rate. It combined those signals with the timeout change in the PR, flagged the merge as risky, and recommended next steps.</p>
<h2>Conclusion: when to use MCP tools instead of pinging an SRE</h2>
<p>With Elasticsearch, Agent Builder, and MCP, a developer can answer questions like &quot;is it safe to merge this PR?&quot; from inside their editor, in seconds, without pinging an SRE. Elasticsearch holds the signals: traces, deploy markers, and SLO budgets. Agent Builder is where the platform team encodes how to read those signals: the thresholds, the warm-up windows, the correlation rules. MCP is what carries those tools into the developer's editor.</p>
<p>The query pulls the data. The description tells the agent how to read it. The platform engineer writes the runbook once, and every developer on the team gets to use it.</p>
<h2>Next steps: extend Elastic Agent Builder MCP tools to CI/CD</h2>
<ul>
<li>Explore the <a href="https://www.elastic.co/docs/solutions/search/elastic-agent-builder">Elastic Agent Builder documentation</a> for more tool types and configuration options.</li>
<li>See <a href="https://www.elastic.co/observability-labs/blog/agentic-cicd-kubernetes-mcp-server">Agentic CI/CD: Kubernetes Deployment Gates with Elastic MCP Server</a> for extending this pattern into your CI/CD pipeline.</li>
<li>Check out <a href="https://www.elastic.co/observability-labs/blog/elastic-agent-skills-observability-workflows">Agent Skills for Elastic Observability</a> for a complementary approach using pre-packaged observability skills.</li>
</ul>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/mcp-tools-elastic-agent-builder/header.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[How to enable Kubernetes alerting with Elastic Observability]]></title>
            <link>https://www.elastic.co/observability-labs/blog/enable-kubernetes-alerting-observability</link>
            <guid isPermaLink="false">enable-kubernetes-alerting-observability</guid>
            <pubDate>Tue, 30 May 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[In the Kubernetes world, different personas demand different kinds of insights. In this post, we’ll focus on alerting and provide an overview of how alerts in Elastic Observability can help users quickly identify Kubernetes problems.]]></description>
            <content:encoded><![CDATA[<p>In the Kubernetes world, different personas demand different kinds of insights. Developers are interested in granular metrics and debugging information. <a href="https://www.elastic.co/blog/elastic-observability-sre-incident-response">SREs</a> are interested in seeing everything at once to quickly get notified when a problem occurs and spot where the root cause is. In this post, we’ll focus on alerting and provide an overview of how alerts in Elastic Observability can help users quickly identify Kubernetes problems.</p>
<h2>Why do we need alerts?</h2>
<p>Logs, metrics, and traces are just the base to build a complete <a href="https://www.elastic.co/blog/kubernetes-cluster-metrics-logs-monitoring">monitoring solution for Kubernetes clusters</a>. Their main goal is to provide debugging information and historical evidence for the infrastructure.</p>
<p>While out-of-the-box dashboards, infrastructure topology, and logs exploration through Kibana are already quite handy to perform ad-hoc analyses, adding notifications and active monitoring of infrastructure allows users to deal with problems detected as early as possible and even proactively take actions to prevent their Kubernetes environments from facing even more serious issues.</p>
<h3>How can this be achieved?</h3>
<p>By building alerts on top of their infrastructure, users can leverage the data and effectively correlate it to a specific notification, creating a wide range of possibilities to dynamically monitor and observe their Kubernetes cluster.</p>
<p>In this blog post, we will explore how users can leverage Elasticsearch’s search powers to define alerting rules in order to be notified when a specific condition occurs.</p>
<h2>SLIs, alerts, and SLOs: Why are they important for SREs?</h2>
<p>For site reliability engineers (SREs), the <a href="https://www.elastic.co/blog/elastic-observability-sre-incident-response">incident response time</a> is tightly coupled with the success of everyday work. Monitoring, alerting, and actions will help to discover, resolve, or prevent issues in their systems.</p>
<blockquote>
<ul>
<li><em>An SLA (Service Level Agreement) is an agreement you create with your users to specify the level of service they can expect.</em></li>
<li><em>An SLO (Service Level Objective) is an agreement within an SLA about a specific metric like uptime or response time.</em></li>
<li><em>An SLI (Service Level Indicator) measures compliance with an SLO.</em></li>
</ul>
</blockquote>
<p>SREs’ day-to-day tasks and projects are driven by SLOs. By ensuring that SLOs are defended in the short term and that they can be maintained in the medium to long term, we lay the basis of a stable working infrastructure.</p>
<p>Having said this, identifying the high-level categories of SLOs is crucial in order to organize the work of an SRE. Then in each category of SLOs, SREs will need the corresponding SLIs that can cover the most important cases of their system under observation. Therefore, the decision of which SLIs we will need demands additional knowledge of the underlying system infrastructure.</p>
<p>One widely used approach to categorize SLIs and SLOs is the <a href="https://landing.google.com/sre/sre-book/chapters/monitoring-distributed-systems/#xref_monitoring_golden-signals">Four Golden Signals</a> method. The categories defined are Latency, Traffic, Errors, and Saturation.</p>
<p>A more specific approach is the <a href="https://thenewstack.io/monitoring-microservices-red-method/">The RED method</a> developed by Tom Wilkie, who was an SRE at Google and used the Four Golden Signals. The RED method drops the saturation category because this one is mainly used for more advanced cases — and people remember better things that come in threes.</p>
<p>Focusing on Kubernetes infrastructure operators, we will consider the following groups of infrastructure SLIs/SLOs:</p>
<ul>
<li>Group 1: Latency of control plane (apiserver,</li>
<li>Group 2: Resource utilization of the nodes/pods (how much cpu, memory, etc. is consumed)</li>
<li>Group 3: Errors (errors on logs or events or error count from components, network, etc.)</li>
</ul>
<h2>Creating alerts for a Kubernetes cluster</h2>
<p>Now that we have a complete outline of our goal to define alerts based on SLIs/SLOs, we will dive into defining the proper alerting. Alerts can be built using <a href="https://www.elastic.co/guide/en/kibana/current/alerting-getting-started.html">Kibana</a>.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/enable-kubernetes-alerting-observability/blog-elastic-create-rule.png" alt="kubernetes create rule" /></p>
<p>See Elastic <a href="https://www.elastic.co/guide/en/kibana/current/alerting-getting-started.html">documentation</a>.</p>
<p>In this blog, we will define more complex alerts based on complex Elasticsearch queries provided by <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-getting-started.html">Watcher</a>’s functionality. <a href="https://www.elastic.co/guide/en/kibana/8.8/watcher-ui.html">Read more about Watcher</a> and how to properly use it in addition to the examples in this blog.</p>
<h3>Latency alerts</h3>
<p>For this kind of alert, we want to define the basic SLOs for a Kubernetes control plane, which will ensure that the basic control plane components can service the end users without an issue. For instance, facing high latencies in queries against the Kubernetes API Server is enough of a signal that action needs to be taken.</p>
<h3>Resource saturation</h3>
<p>The next group of alerting will be resource utilization. Node’s CPU utilization or changes in Node’s condition is something critical for a cluster to ensure the smooth servicing of the workloads provisioned to run the applications that end users will interact with.</p>
<h3>Error detection</h3>
<p>Last but not least, we will define alerts based on specific errors like the network error rate or Pods’ failures like the OOMKilled situation. It’s a very useful indicator for SRE teams to either detect issues on the infrastructure level or just be able to notify developer teams about problematic workloads. One example that we will examine later is having an application running as a Pod and constantly getting restarted because it hits its memory limit. In that case, the owners of this application will need to get notified to act properly.</p>
<h2>From Kubernetes data to Elasticsearch queries</h2>
<p>Having a solid plan about the alerts that we want to implement, it's time to explore the data we have collected from the Kubernetes cluster and stored in Elasticsearch. For this we will consult the list of the available data fields that are ingested using the Elastic Agent Kubernetes <a href="https://docs.elastic.co/en/integrations/kubernetes">integration</a> (the full list of fields can be found <a href="https://www.elastic.co/guide/en/beats/metricbeat/current/exported-fields-kubernetes.html">here</a>). Using these fields we can create various alerts like:</p>
<ul>
<li>Node CPU utilization</li>
<li>Node Memory utilization</li>
<li>BW utilization</li>
<li>Pod restarts</li>
<li>Pod CPU/memory utilization</li>
</ul>
<h3>CPU utilization alert</h3>
<p>Our first example will use the CPU utilization fields to calculate the Node’s CPU utilization and create an alert. For this alert, we leverage the metrics:</p>
<pre><code class="language-yaml">kubernetes.node.cpu.usage.nanocores
kubernetes.node.cpu.capacity.cores.
</code></pre>
<p>The following calculation (nodeUsage / 1000000000 ) /nodeCap grouped by node name will give us the CPU utilization of our cluster’s nodes.</p>
<p>The Watcher definition that implements this query can be created with the following API call to Elasticsearch:</p>
<pre><code class="language-bash">curl -X PUT &quot;https://elastic:changeme@localhost:9200/_watcher/watch/Node-CPU-Usage?pretty&quot; -k -H 'Content-Type: application/json' -d'
{
  &quot;trigger&quot;: {
    &quot;schedule&quot;: {
      &quot;interval&quot;: &quot;10m&quot;
    }
  },
  &quot;input&quot;: {
    &quot;search&quot;: {
      &quot;request&quot;: {
        &quot;body&quot;: {
          &quot;size&quot;: 0,
          &quot;query&quot;: {
            &quot;bool&quot;: {
              &quot;must&quot;: [
                {
                  &quot;range&quot;: {
                    &quot;@timestamp&quot;: {
                      &quot;gte&quot;: &quot;now-10m&quot;,
                      &quot;lte&quot;: &quot;now&quot;,
                      &quot;format&quot;: &quot;strict_date_optional_time&quot;
                    }
                  }
                },
                {
                  &quot;bool&quot;: {
                    &quot;must&quot;: [
                      {
                        &quot;query_string&quot;: {
                          &quot;query&quot;: &quot;data_stream.dataset: kubernetes.node OR data_stream.dataset: kubernetes.state_node&quot;,
                          &quot;analyze_wildcard&quot;: true
                        }
                      }
                    ],
                    &quot;filter&quot;: [],
                    &quot;should&quot;: [],
                    &quot;must_not&quot;: []
                  }
                }
              ],
              &quot;filter&quot;: [],
              &quot;should&quot;: [],
              &quot;must_not&quot;: []
            }
          },
          &quot;aggs&quot;: {
            &quot;nodes&quot;: {
              &quot;terms&quot;: {
                &quot;field&quot;: &quot;kubernetes.node.name&quot;,
                &quot;size&quot;: &quot;10000&quot;,
                &quot;order&quot;: {
                  &quot;_key&quot;: &quot;asc&quot;
                }
              },
              &quot;aggs&quot;: {
                &quot;nodeUsage&quot;: {
                  &quot;max&quot;: {
                    &quot;field&quot;: &quot;kubernetes.node.cpu.usage.nanocores&quot;
                  }
                },
                &quot;nodeCap&quot;: {
                  &quot;max&quot;: {
                    &quot;field&quot;: &quot;kubernetes.node.cpu.capacity.cores&quot;
                  }
                },
                &quot;nodeCPUUsagePCT&quot;: {
                  &quot;bucket_script&quot;: {
                    &quot;buckets_path&quot;: {
                      &quot;nodeUsage&quot;: &quot;nodeUsage&quot;,
                      &quot;nodeCap&quot;: &quot;nodeCap&quot;
                    },
                    &quot;script&quot;: {
                      &quot;source&quot;: &quot;( params.nodeUsage / 1000000000 ) / params.nodeCap&quot;,
                      &quot;lang&quot;: &quot;painless&quot;,
                      &quot;params&quot;: {
                        &quot;_interval&quot;: 10000
                      }
                    },
                    &quot;gap_policy&quot;: &quot;skip&quot;
                  }
                }
              }
            }
          }
        },
        &quot;indices&quot;: [
          &quot;metrics-kubernetes*&quot;
        ]
      }
    }
  },
  &quot;condition&quot;: {
    &quot;array_compare&quot;: {
      &quot;ctx.payload.aggregations.nodes.buckets&quot;: {
        &quot;path&quot;: &quot;nodeCPUUsagePCT.value&quot;,
        &quot;gte&quot;: {
          &quot;value&quot;: 80
        }
      }
    }
  },
  &quot;actions&quot;: {
    &quot;log_hits&quot;: {
      &quot;foreach&quot;: &quot;ctx.payload.aggregations.nodes.buckets&quot;,
      &quot;max_iterations&quot;: 500,
      &quot;logging&quot;: {
        &quot;text&quot;: &quot;Kubernetes node found with high CPU usage: {{ctx.payload.key}} -&gt; {{ctx.payload.nodeCPUUsagePCT.value}}&quot;
      }
    }
  },
  &quot;metadata&quot;: {
    &quot;xpack&quot;: {
      &quot;type&quot;: &quot;json&quot;
    },
    &quot;name&quot;: &quot;Node CPU Usage&quot;
  }
}
</code></pre>
<h3>OOMKilled Pods detection and alerting</h3>
<p>Another Watcher that we will explore is the one that detects Pods that have been restarted due to an OOMKilled error. This error is quite common in Kubernetes workloads and is useful to detect this early on to inform the team that owns this workload, so they can either investigate issues that could cause memory leaks or just consider increasing the required resources for the workload itself.</p>
<p>This information can be retrieved from a query like the following:</p>
<pre><code class="language-yaml">kubernetes.container.status.last_terminated_reason: OOMKilled
</code></pre>
<p>Here is how we can create the respective Watcher with an API call:</p>
<pre><code class="language-bash">curl -X PUT &quot;https://elastic:changeme@localhost:9200/_watcher/watch/Pod-Terminated-OOMKilled?pretty&quot; -k -H 'Content-Type: application/json' -d'
{
  &quot;trigger&quot;: {
    &quot;schedule&quot;: {
      &quot;interval&quot;: &quot;1m&quot;
    }
  },
  &quot;input&quot;: {
    &quot;search&quot;: {
      &quot;request&quot;: {
        &quot;search_type&quot;: &quot;query_then_fetch&quot;,
        &quot;indices&quot;: [
          &quot;*&quot;
        ],
        &quot;rest_total_hits_as_int&quot;: true,
        &quot;body&quot;: {
          &quot;size&quot;: 0,
          &quot;query&quot;: {
            &quot;bool&quot;: {
              &quot;must&quot;: [
                {
                  &quot;range&quot;: {
                    &quot;@timestamp&quot;: {
                      &quot;gte&quot;: &quot;now-1m&quot;,
                      &quot;lte&quot;: &quot;now&quot;,
                      &quot;format&quot;: &quot;strict_date_optional_time&quot;
                    }
                  }
                },
                {
                  &quot;bool&quot;: {
                    &quot;must&quot;: [
                      {
                        &quot;query_string&quot;: {
                          &quot;query&quot;: &quot;data_stream.dataset: kubernetes.state_container&quot;,
                          &quot;analyze_wildcard&quot;: true
                        }
                      },
                      {
                        &quot;exists&quot;: {
                          &quot;field&quot;: &quot;kubernetes.container.status.last_terminated_reason&quot;
                        }
                      },
                      {
                        &quot;query_string&quot;: {
                          &quot;query&quot;: &quot;kubernetes.container.status.last_terminated_reason: OOMKilled&quot;,
                          &quot;analyze_wildcard&quot;: true
                        }
                      }
                    ],
                    &quot;filter&quot;: [],
                    &quot;should&quot;: [],
                    &quot;must_not&quot;: []
                  }
                }
              ],
              &quot;filter&quot;: [],
              &quot;should&quot;: [],
              &quot;must_not&quot;: []
            }
          },
          &quot;aggs&quot;: {
            &quot;pods&quot;: {
              &quot;terms&quot;: {
                &quot;field&quot;: &quot;kubernetes.pod.name&quot;,
                &quot;order&quot;: {
                  &quot;_key&quot;: &quot;asc&quot;
                }
              }
            }
          }
        }
      }
    }
  },
  &quot;condition&quot;: {
    &quot;array_compare&quot;: {
      &quot;ctx.payload.aggregations.pods.buckets&quot;: {
        &quot;path&quot;: &quot;doc_count&quot;,
        &quot;gte&quot;: {
          &quot;value&quot;: 1,
          &quot;quantifier&quot;: &quot;some&quot;
        }
      }
    }
  },
  &quot;actions&quot;: {
    &quot;ping_slack&quot;: {
      &quot;foreach&quot;: &quot;ctx.payload.aggregations.pods.buckets&quot;,
      &quot;max_iterations&quot;: 500,
      &quot;webhook&quot;: {
        &quot;method&quot;: &quot;POST&quot;,
        &quot;url&quot;: &quot;https://hooks.slack.com/services/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&quot;,
        &quot;body&quot;: &quot;{\&quot;channel\&quot;: \&quot;#k8s-alerts\&quot;, \&quot;username\&quot;: \&quot;k8s-cluster-alerting\&quot;, \&quot;text\&quot;: \&quot;Pod {{ctx.payload.key}} was terminated with status OOMKilled.\&quot;}&quot;
      }
    }
  },
  &quot;metadata&quot;: {
    &quot;xpack&quot;: {
      &quot;type&quot;: &quot;json&quot;
    },
    &quot;name&quot;: &quot;Pod Terminated OOMKilled&quot;
  }
}
</code></pre>
<h3>From Kubernetes data to alerts summary</h3>
<p>So far we saw how we can start from plain Kubernetes fields, use them in ES queries, and build Watchers and alerts on top of them.</p>
<p>One can explore more possible data combinations and build queries and alerts following the examples we provided here. A <a href="https://github.com/elastic/integrations/tree/main/packages/kubernetes/docs">full list of alerts</a> is available, as well as a <a href="https://github.com/elastic/k8s-integration-infra/tree/main/scripts/alerting">basic scripted way of installing them</a>.</p>
<p>Of course, these examples come with simple actions defined that only log messages into the Elasticsearch logs. However, one can use more advanced and useful outputs like Slack’s webhooks:</p>
<pre><code class="language-json">&quot;actions&quot;: {
    &quot;ping_slack&quot;: {
      &quot;foreach&quot;: &quot;ctx.payload.aggregations.pods.buckets&quot;,
      &quot;max_iterations&quot;: 500,
      &quot;webhook&quot;: {
        &quot;method&quot;: &quot;POST&quot;,
        &quot;url&quot;: &quot;https://hooks.slack.com/services/T04SW3JHXasdfasdfasdfasdfasdf&quot;,
        &quot;body&quot;: &quot;{\&quot;channel\&quot;: \&quot;#k8s-alerts\&quot;, \&quot;username\&quot;: \&quot;k8s-cluster-alerting\&quot;, \&quot;text\&quot;: \&quot;Pod {{ctx.payload.key}} was terminated with status OOMKilled.\&quot;}&quot;
      }
    }
  }
</code></pre>
<p>The result would be a Slack message like the following:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/enable-kubernetes-alerting-observability/blog-elastic-k8s-cluster-alerting.png" alt="" /></p>
<h2>Next steps</h2>
<p>In our next steps, we would like to make these alerts part of our Kubernetes integration, which would mean that the predefined alerts would be installed when users install or enable the Kubernetes integration. At the same time, we plan to implement some of these as Kibana’s native SLIs, providing the option to our users to quickly define SLOs on top of the SLIs through a nice user interface. If you’re interested to learn more about these, follow the public GitHub issues for more information and feel free to provide your feedback:</p>
<ul>
<li><a href="https://github.com/elastic/package-spec/issues/484">https://github.com/elastic/package-spec/issues/484</a></li>
<li><a href="https://github.com/elastic/kibana/issues/150050">https://github.com/elastic/kibana/issues/150050</a></li>
</ul>
<p>For those who are eager to start using Kubernetes alerting today, here is what you need to do:</p>
<ol>
<li>Make sure that you have an Elastic cluster up and running. The fastest way to deploy your cluster is to spin up a <a href="https://www.elastic.co/elasticsearch/service">free trial of Elasticsearch Service</a>.</li>
<li>Install the latest Elastic Agent on your Kubernetes cluster following the respective <a href="https://www.elastic.co/guide/en/fleet/master/running-on-kubernetes-managed-by-fleet.html">documentation</a>.</li>
<li>Install our provided alerts that can be found at <a href="https://github.com/elastic/integrations/tree/main/packages/kubernetes/docs">https://github.com/elastic/integrations/tree/main/packages/kubernetes/docs</a> or at <a href="https://github.com/elastic/k8s-integration-infra/tree/main/scripts/alerting">https://github.com/elastic/k8s-integration-infra/tree/main/scripts/alerting</a>.</li>
</ol>
<p>Of course, if you have any questions, remember that we are always happy to help on the Discuss <a href="https://discuss.elastic.co/">forums</a>.</p>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/enable-kubernetes-alerting-observability/alert-management.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 service performance: An overview of SLA calculation for Elastic Observability]]></title>
            <link>https://www.elastic.co/observability-labs/blog/observability-sla-calculations-transforms</link>
            <guid isPermaLink="false">observability-sla-calculations-transforms</guid>
            <pubDate>Mon, 24 Apr 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic Stack provides many valuable insights for different users, such as reports on service performance and if the service level agreement (SLA) is met. In this post, we’ll provide an overview of calculating an SLA for Elastic Observability.]]></description>
            <content:encoded><![CDATA[<p>Elastic Stack provides many valuable insights for different users. Developers are interested in low-level metrics and debugging information. <a href="https://www.elastic.co/blog/elastic-observability-sre-incident-response">SREs</a> are interested in seeing everything at once and identifying where the root cause is. Managers want reports that tell them how good service performance is and if the service level agreement (SLA) is met. In this post, we’ll focus on the service perspective and provide an overview of calculating an SLA.</p>
<p><em>Since version 8.8, we have a built in functionality to calculate SLOs —</em> <a href="https://www.elastic.co/guide/en/observability/current/slo.html"><em>check out our guide</em></a><em>!</em></p>
<h2>Foundations of calculating an SLA</h2>
<p>There are many ways to calculate and measure an SLA. The most important part is the definition of the SLA, and as a consultant, I’ve seen many different ways. Some examples include:</p>
<ul>
<li>Count of HTTP 2xx must be above 98% of all HTTP status</li>
<li>Response time of successful HTTP 2xx requests must be below x milliseconds</li>
<li>Synthetic monitor must be up at least 99%</li>
<li>95% of all batch transactions from the billing service need to complete within 4 seconds</li>
</ul>
<p>Depending on the origin of the data, calculating the SLA can be easier or more difficult. For uptime (Synthetic Monitoring), we automatically provide SLA values and offer out-of-the-box alerts to simply define alert when availability below 98% for the last 1 hour.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/observability-sla-calculations-transforms/blog-elastic-overview-monitor-details.png" alt="overview monitor details" /></p>
<p>I personally recommend using <a href="https://www.elastic.co/blog/new-synthetic-monitoring-observability">Elastic Synthetic Monitoring</a> whenever possible to monitor service performance. Running HTTP requests and verifying the answers from the service, or doing fully fledged browser monitors and clicking through the website as a real user does, ensures a better understanding of the health of your service.</p>
<p>Sometimes this is impossible because you want to calculate the uptime of a specific Windows Service that does not offer any TCP port or HTTP interaction. Here the caveat applies that just because the service is running, it does not necessarily imply that the service is working fine.</p>
<h2>Transforms to the rescue</h2>
<p>We have identified our important service. In our case, it is the Steam Client Helper. There are two ways to solve this.</p>
<h3>Lens formula</h3>
<p>You can use Lens and formula (for a deep dive into formulas, <a href="https://www.elastic.co/blog/how-tough-was-your-workout-take-a-closer-look-at-strava-data-through-kibana-lens">check out this blog</a>). Use the Search bar to filter down the data you want. Then use the formula option in Lens. We are dividing all counts of records with Running as a state and dividing it by the overall count of records. This is a nice solution when there is a need to calculate quickly and on the fly.</p>
<pre><code class="language-sql">count(kql='windows.service.state: &quot;Running&quot; ')/count()
</code></pre>
<p>Using the formula posted above as the bar chart's vertical axis calculates the uptime percentage. We use an annotation to mark why there is a dip and why this service was below the threshold. The annotation is set to reboot, which indicates a reboot happening, and thus, the service was down for a moment. Lastly, we add a reference line and set this to our defined threshold at 98%. This ensures that a quick look at the visualization allows our eyes to gauge if we are above or below the threshold.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/observability-sla-calculations-transforms/blog-elastic-visualization.png" alt="visualization" /></p>
<h3>Transform</h3>
<p>What if I am not interested in just one service, but there are multiple services needed for your SLA? That is where Transforms can solve this problem. Furthermore, the second issue is that this data is only available inside the Lens. Therefore, we cannot create any alerts on this.</p>
<p>Go to Transforms and create a pivot transform.</p>
<ol>
<li>
<p>Add the following filter to narrow it to only services data sets: data_stream.dataset: &quot;windows.service&quot;. If you are interested in a specific service, you can always add it to the search bar if you want to know if a specific remote management service is up in your entire fleet!</p>
</li>
<li>
<p>Select data histogram(@timestamp) and set it to your chosen unit. By default, the Elastic Agent only collects service states every 60 seconds. I am going with 1 hour.</p>
</li>
<li>
<p>Select agent.name and windows.service.name as well.</p>
</li>
</ol>
<p><img src="https://www.elastic.co/observability-labs/assets/images/observability-sla-calculations-transforms/blog-elastic-transform-configuration.png" alt="transform configuration" /></p>
<ol start="4">
<li>Now we need to define an aggregation type. We will use a value_count of windows.service.state. That just counts how many records have this value.</li>
</ol>
<p><img src="https://www.elastic.co/observability-labs/assets/images/observability-sla-calculations-transforms/blog-elastic-aggregations.png" alt="aggregations" /></p>
<ol start="5">
<li>
<p>Rename the value_count to total_count.</p>
</li>
<li>
<p>Add value_count for windows.service.state a second time and use the pencil icon to edit it to terms, which aggregates for running.</p>
</li>
</ol>
<p><img src="https://www.elastic.co/observability-labs/assets/images/observability-sla-calculations-transforms/blog-elastic-aggregations-apply.png" alt="aggregations apply" /></p>
<ol start="7">
<li>
<p>This opens up a sub-aggregation. Once again, select value_count(windows.service.state) and rename it to values.</p>
</li>
<li>
<p>Now, the preview shows us the count of records with any states and the count of running.</p>
</li>
</ol>
<p><img src="https://www.elastic.co/observability-labs/assets/images/observability-sla-calculations-transforms/blog-elastic-transform-configuration-next.png" alt="transform configuration" /></p>
<ol start="9">
<li>
<p>Here comes the tricky part. We need to write some custom aggregations to calculate the percentage of uptime. Click on the copy icon next to the edit JSON config.</p>
</li>
<li>
<p>In a new tab, go to Dev Tools. Paste what you have in the clipboard.</p>
</li>
<li>
<p>Press the play button or use the keyboard shortcut ctrl+enter/cmd+enter and run it. This will create a preview of what the data looks like. It should give you the same information as in the table preview.</p>
</li>
<li>
<p>Now, we need to calculate the percentage of up, which means doing a bucket script where we divide running.values by total_count, just like we did in the Lens visualization. Suppose you name the columns differently or use more than a single value. In that case, you will need to adapt accordingly.</p>
</li>
</ol>
<pre><code class="language-json">&quot;availability&quot;: {
        &quot;bucket_script&quot;: {
          &quot;buckets_path&quot;: {
            &quot;up&quot;: &quot;running&gt;values&quot;,
            &quot;total&quot;: &quot;total_count&quot;
          },
          &quot;script&quot;: &quot;params.up/params.total&quot;
        }
      }
</code></pre>
<ol start="13">
<li>This is the entire transform for me:</li>
</ol>
<pre><code class="language-bash">POST _transform/_preview
{
  &quot;source&quot;: {
    &quot;index&quot;: [
      &quot;metrics-*&quot;
    ]
  },
  &quot;pivot&quot;: {
    &quot;group_by&quot;: {
      &quot;@timestamp&quot;: {
        &quot;date_histogram&quot;: {
          &quot;field&quot;: &quot;@timestamp&quot;,
          &quot;calendar_interval&quot;: &quot;1h&quot;
        }
      },
      &quot;agent.name&quot;: {
        &quot;terms&quot;: {
          &quot;field&quot;: &quot;agent.name&quot;
        }
      },
      &quot;windows.service.name&quot;: {
        &quot;terms&quot;: {
          &quot;field&quot;: &quot;windows.service.name&quot;
        }
      }
    },
    &quot;aggregations&quot;: {
      &quot;total_count&quot;: {
        &quot;value_count&quot;: {
          &quot;field&quot;: &quot;windows.service.state&quot;
        }
      },
      &quot;running&quot;: {
        &quot;filter&quot;: {
          &quot;term&quot;: {
            &quot;windows.service.state&quot;: &quot;Running&quot;
          }
        },
        &quot;aggs&quot;: {
          &quot;values&quot;: {
            &quot;value_count&quot;: {
              &quot;field&quot;: &quot;windows.service.state&quot;
            }
          }
        }
      },
      &quot;availability&quot;: {
        &quot;bucket_script&quot;: {
          &quot;buckets_path&quot;: {
            &quot;up&quot;: &quot;running&gt;values&quot;,
            &quot;total&quot;: &quot;total_count&quot;
          },
          &quot;script&quot;: &quot;params.up/params.total&quot;
        }
      }
    }
  }
}
</code></pre>
<ol start="14">
<li>The preview in Dev Tools should work and be complete. Otherwise, you must debug any errors. Most of the time, it is the bucket script and the path to the values. You might have called it up instead of running. This is what the preview looks like for me.</li>
</ol>
<pre><code class="language-json">{
  &quot;running&quot;: {
    &quot;values&quot;: 1
  },
  &quot;agent&quot;: {
    &quot;name&quot;: &quot;AnnalenasMac&quot;
  },
  &quot;@timestamp&quot;: &quot;2021-12-07T19:00:00.000Z&quot;,
  &quot;total_count&quot;: 1,
  &quot;availability&quot;: 1,
  &quot;windows&quot;: {
    &quot;service&quot;: {
      &quot;name&quot;: &quot;InstallService&quot;
    }
  }
},
</code></pre>
<ol start="15">
<li>Now we only paste the bucket script into the transform creation UI after selecting Edit JSON. It looks like this:</li>
</ol>
<p><img src="https://www.elastic.co/observability-labs/assets/images/observability-sla-calculations-transforms/blog-elastic-transform-configuration-pivot-configuration-object.png" alt="transform configuration pivot configuration object" /></p>
<ol start="16">
<li>Give your transform a name, set the destination index, and run it continuously. When selecting this, please also make sure not to use @timestamp. Instead, opt for event.ingested. <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/transform-checkpoints.html">Our documentation explains this in detail</a>.</li>
</ol>
<p><img src="https://www.elastic.co/observability-labs/assets/images/observability-sla-calculations-transforms/blog-elastic-transform-details.png" alt="transform details" /></p>
<ol start="17">
<li>Click next and create and start. This can take a bit, so don’t worry.</li>
</ol>
<p>To summarize, we have now created a pivot transform using a bucket script aggregation to calculate the running time of a service in percentage. There is a caveat because Elastic Agent, per default, only collects the every 60 seconds the services state. It can be that a service is up exactly when collected and down a few seconds later. If it is that important and no other monitoring possibilities, such as <a href="https://www.elastic.co/blog/what-can-elastic-synthetics-tell-us-about-kibana-dashboards">Elastic Synthetics</a> are possible, you might want to reduce the collection time on the Agent side to get the services state every 30 seconds, 45 seconds. Depending on how important your thresholds are, you can create multiple policies having different collection times. This ensures that a super important server might collect the services state every 10 seconds because you need as much granularity and insurance for the correctness of the metric. For normal workstations where you just want to know if your remote access solution is up the majority of the time, you might not mind having a single metric every 60 seconds.</p>
<p>After you have created the transform, one additional feature you get is that the data is stored in an index, similar to in Elasticsearch. When you just do the visualization, the metric is calculated for this visualization only and not available anywhere else. Since this is now data, you can create a threshold alert to your favorite connection (Slack, Teams, Service Now, Mail, and so <a href="https://www.elastic.co/guide/en/kibana/current/action-types.html">many more to choose from</a>).</p>
<h2>Visualizing the transformed data</h2>
<p>The transform created a data view called windows-service. The first thing we want to do is change the format of the availability field to a percentage. This automatically tells Lens that this needs to be formatted as a percentage field, so you don’t need to select it manually as well as do calculations. Furthermore, in Discover, instead of seeing 0.5 you see 50%. Isn’t that cool? This is also possible for durations, like event.duration if you have it as nanoseconds! No more calculations on the fly and thinking if you need to divide by 1,000 or 1,000,000.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/observability-sla-calculations-transforms/blog-elastic-edit-field-availability.png" alt="edit field availability" /></p>
<p>We get this view by using a simple Lens visualization with a timestamp on the vertical axis with the minimum interval for 1 day and an average of availability. Don’t worry — the other data will be populated once the transformation finishes. We can add a reference line using the value 0.98 because our target is 98% uptime of the service.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/observability-sla-calculations-transforms/blog-elastic-line.png" alt="line" /></p>
<h2>Summary</h2>
<p>This blog post covered the steps needed to calculate the SLA for a specific data set in Elastic Observability, as well as how to visualize it. Using this calculation method opens the door to a lot of interesting use cases. You can change the bucket script and start calculating the number of sales, and the average basket size. Interested in learning more about Elastic Synthetics? Read <a href="https://www.elastic.co/guide/en/observability/current/monitor-uptime-synthetics.html">our documentation</a> or check out our free <a href="https://www.elastic.co/training/synthetics-quick-start">Synthetic Monitoring Quick Start training</a>.</p>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/observability-sla-calculations-transforms/illustration-analytics-report-1680x980.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Build better Service Level Objectives (SLOs) from logs and metrics]]></title>
            <link>https://www.elastic.co/observability-labs/blog/service-level-objectives-slos-logs-metrics</link>
            <guid isPermaLink="false">service-level-objectives-slos-logs-metrics</guid>
            <pubDate>Fri, 23 Feb 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[To help manage operations and business metrics, Elastic Observability's SLO (Service Level Objectives) feature was introduced in 8.12. This blog reviews this feature and how you can use it with Elastic's AI Assistant to meet SLOs.]]></description>
            <content:encoded><![CDATA[<p>In today's digital landscape, applications are at the heart of both our personal and professional lives. We've grown accustomed to these applications being perpetually available and responsive. This expectation places a significant burden on the shoulders of developers and operations teams.</p>
<p>Site reliability engineers (SREs) face the challenging task of sifting through vast quantities of data, not just from the applications themselves but also from the underlying infrastructure. In addition to data analysis, they are responsible for ensuring the effective use and development of operational tools. The growing volume of data, the daily resolution of issues, and the continuous evolution of tools and processes can detract from the focus on business performance.</p>
<p>Elastic Observability offers a solution to this challenge. It enables SREs to integrate and examine all telemetry data (logs, metrics, traces, and profiling) in conjunction with business metrics. This comprehensive approach to data analysis fosters operational excellence, boosts productivity, and yields critical insights, all of which are integral to maintaining high-performing applications in a demanding digital environment.</p>
<p>To help manage operations and business metrics, Elastic Observability's SLO (Service Level Objectives) feature was introduced in <a href="https://www.elastic.co/guide/en/observability/8.12/slo.html">8.12</a>. This feature enables setting measurable performance targets for services, such as <a href="https://sre.google/sre-book/monitoring-distributed-systems/">availability, latency, traffic, errors, and saturation or define your own</a>. Key components include:</p>
<ul>
<li>
<p>Defining and monitoring SLIs (Service Level Indicators)</p>
</li>
<li>
<p>Monitoring error budgets indicating permissible performance shortfalls</p>
</li>
<li>
<p>Alerting on burn rates showing error budget consumption</p>
</li>
</ul>
<p>Users can monitor SLOs in real-time with dashboards, track historical performance, and receive alerts for potential issues. Additionally, SLO dashboard panels offer customized visualizations.</p>
<p>Service Level Objectives (SLOs) are generally available for our Platinum and Enterprise subscription customers.</p>
&lt;Video vidyardUuid=&quot;ngfY9mrkNEkjmpRY4Qd5Pb&quot; /&gt;
<p>In this blog, we will outline the following:</p>
<ul>
<li>
<p>What are SLOs? A Google SRE perspective</p>
</li>
<li>
<p>Several scenarios of defining and managing SLOs</p>
</li>
</ul>
<h2>Service Level Objective overview</h2>
<p>Service Level Objectives (SLOs) are a crucial component for Site Reliability Engineering (SRE), as detailed in <a href="https://sre.google/sre-book/table-of-contents/">Google's SRE Handbook</a>. They provide a framework for quantifying and managing the reliability of a service. The key elements of SLOs include:</p>
<ul>
<li>
<p><strong>Service Level Indicators (SLIs):</strong> These are carefully selected metrics, such as uptime, latency, throughput, error rates, or other important metrics, that represent the aspects of the service and are important from an operations or business perspective. Hence, an SLI is a measure of the service level provided (latency, uptime, etc.), and it is defined as a ratio of good over total events, with a range between 0% and 100%.</p>
</li>
<li>
<p><strong>Service Level Objective (SLO):</strong> An SLO is the target value for a service level measured as a percentage by an SLI. Above the threshold, the service is compliant. As an example, if we want to use service availability as an SLI, with the number of successful responses at 99.9%, then any time the number of failed responses is &gt; .1%, the SLO will be out of compliance.</p>
</li>
<li>
<p><strong>Error budget:</strong> This represents the threshold of acceptable errors, balancing the need for reliability with practical limits. It is defined as 100% minus the SLO quantity of errors that is tolerated.</p>
</li>
<li>
<p><strong>Burn rate:</strong> This concept relates to how quickly the service is consuming its error budget, which is the acceptable threshold for unreliability agreed upon by the service providers and its users.</p>
</li>
</ul>
<p>Understanding these concepts and effectively implementing them is essential for maintaining a balance between innovation and reliability in service delivery. For more detailed information, you can refer to <a href="https://sre.google/workbook/slo-document/">Google's SRE Handbook</a>.</p>
<p>One main thing to remember is that SLO monitoring is <em>not</em> incident monitoring. SLO monitoring is a proactive, strategic approach designed to ensure that services meet established performance standards and user expectations. It involves tracking Service Level Objectives, error budgets, and the overall reliability of a service over time. This predictive method helps in preventing issues that could impact users and aligns service performance with business objectives.</p>
<p>In contrast, incident monitoring is a reactive process focused on detecting, responding to, and mitigating service incidents as they occur. It aims to address unexpected disruptions or failures in real time, minimizing downtime and impact on service. This includes monitoring system health, errors, and response times during incidents, with a focus on rapid response to minimize disruption and preserve the service's reputation.</p>
<p>Elastic®’s SLO capability is based directly off the Google SRE Handbook. All the definitions and semantics are utilized as described in Google’s SRE handbook. Hence users can perform the following on SLOs in Elastic:</p>
<ul>
<li>
<p>Define an SLO on an SLI such as KQL (log based query), service availability, service latency, custom metric, histogram metric, or a timeslice metric. Additionally, set the appropriate threshold.</p>
</li>
<li>
<p>Utilize occurrence versus time slice based budgeting. Occurrences is the number of good events over the number of total events to compute the SLO. Timeslices break the overall time window into slammer slices of a defined duration and compute the number of good slices over the total slices to compute the SLO. Timeslice targets are more accurate and useful when calculating things like a service’s SLO when trying to meet agreed upon customer targets.</p>
</li>
<li>
<p>Manage all the SLOs in a singular location.</p>
</li>
<li>
<p>Trigger alerts from the defined SLO, whether the SLI is off, burn rate is used up, or the error rate is X.</p>
</li>
<li>
<p>Create unique service level dashboards with SLO information for a more comprehensive view of the service.</p>
</li>
</ul>
<p><img src="https://www.elastic.co/observability-labs/assets/images/service-level-objectives-slos-logs-metrics/1-slo-blog.png" alt="Create alerts" /></p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/service-level-objectives-slos-logs-metrics/2-slo-blog.png" alt="Create dashboards" /></p>
<p>SREs need to be able to manage business metrics.</p>
<h2>SLOs based on logs: NGINX availability</h2>
<p>Defining SLOs does not always mean metrics need to be used. Logs are a rich form of information, even when they have metrics embedded in them. Hence it’s useful to understand your business and operations status based on logs.</p>
<p>Elastic allows you to create an SLO based on specific fields in the log message, which don’t have to be metrics. A simple example is a simple multi-tier app that has a web server layer (nginx), a processing layer, and a database layer.</p>
<p>Let’s say that your processing layer is managing a significant number of requests. You want to ensure that the service is up properly. The best way is to ensure that all http.response.status_code are less than 500. Anything less ensures the service is up and any errors (like 404) are all user or client errors versus server errors.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/service-level-objectives-slos-logs-metrics/3-slo-blog.png" alt="expanded document" /></p>
<p>If we use Discover in Elastic, we see that there are close to 2M log messages over a seven-day time frame.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/service-level-objectives-slos-logs-metrics/4-slo-blog.png" alt="17k" /></p>
<p>Additionally, the number of messages with http.response.status_code &gt; 500 is minimal, like 17K.</p>
<p>Rather than creating an alert, we can create an SLO with this query:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/service-level-objectives-slos-logs-metrics/5-slo-blog.png" alt="edit SLO" /></p>
<p>We chose to use occurrences as the budgeting method to keep things simple.</p>
<p>Once defined, we can see how well our SLO is performing over a seven-day time frame. We can see not only the SLO, but also the burn rate, the historical SLI, and error budget, and any specific alerts against the SLO.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/service-level-objectives-slos-logs-metrics/6-slo-blog.png" alt="SLOs" /></p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/service-level-objectives-slos-logs-metrics/7-slo-blog.png" alt="nginx server availability " /></p>
<p>Not only do we get information about the violation, but we also get:</p>
<ul>
<li>
<p>Historical SLI (7 days)</p>
</li>
<li>
<p>Error budget burn down</p>
</li>
<li>
<p>Good vs. bad events (24 hours)</p>
</li>
</ul>
<p><img src="https://www.elastic.co/observability-labs/assets/images/service-level-objectives-slos-logs-metrics/8-slo-blog.png" alt="Percentages" /></p>
<p>We can see how we’ve easily burned through our error budget.</p>
<p>Hence something must be going on with nginx. To investigate, all we need to do is utilize the <a href="https://www.elastic.co/blog/context-aware-insights-elastic-ai-assistant-observability">AI Assistant</a>, and use its natural language interface to ask questions to help analyze the situation.</p>
<p>Let’s use Elastic’s AI Assistant to analyze the breakdown of http.response.status_code across all the logs from the past seven days. This helps us understand how many 50X errors we are getting.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/service-level-objectives-slos-logs-metrics/9-slo-blog.png" alt="count of http response status code" /></p>
<p>As we can see, the number of 502s is minimal compared to the number of overall messages, but it is affecting our SLO.</p>
<p>However, it seems like Nginx is having an issue. In order to reduce the issue, we also ask the AI Assistant how to work on this error. Specifically, we ask if there is an internal runbook the SRE team has created.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/service-level-objectives-slos-logs-metrics/10-slo-blog.png" alt="ai assistant thread" /></p>
<p>AI Assistant gets a runbook the team has added to its knowledge base. I can now analyze and try to resolve or reduce the issue with nginx.</p>
<p>While this is a simple example, there are an endless number of possibilities that can be defined based on KQL. Some other simple examples:</p>
<ul>
<li>
<p>99% of requests occur under 200ms</p>
</li>
<li>
<p>99% of log message are not errors</p>
</li>
</ul>
<h2>Application SLOs: OpenTelemetry demo cartservice</h2>
<p>A common application developers and SREs use to learn about OpenTelemetry and test out Observability features is the <a href="https://github.com/elastic/opentelemetry-demo">OpenTelemetry demo</a>.</p>
<p>This demo has <a href="https://opentelemetry.io/docs/demo/feature-flags/">feature flags</a> to simulate issues. With Elastic’s alerting and SLO capability, you can also determine how well the entire application is performing and how well your customer experience is holding up when these feature flags are used.</p>
<p><a href="https://www.elastic.co/blog/opentelemetry-observability">Elastic supports OpenTelemetry by taking OTLP directly with no need for an Elastic specific agent</a>. You can send in OpenTelemetry data directly from the application (through OTel libraries) and through the collector.</p>
<p>We’ve brought up the OpenTelemetry demo on a K8S cluster (AWS EKS) and turned on the cartservice feature flag. This inserts errors into the cartservice. We’ve also created two SLOs to monitor the cartservice’s availability and latency.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/service-level-objectives-slos-logs-metrics/11-slo-blog.png" alt="SLOs" /></p>
<p>We can see that the cartservice’s availability is violated. As we drill down, we see that there aren’t as many successful transactions, which is affecting the SLO.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/service-level-objectives-slos-logs-metrics/12-slo-blog.png" alt="cartservice-otel" /></p>
<p>As we drill into the service, we can see in Elastic APM that there is a higher than normal failure rate of about 5.5% for the emptyCart service.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/service-level-objectives-slos-logs-metrics/13-slo-blog.png" alt="apm" /></p>
<p>We can investigate this further in APM, but that is a discussion for another blog. Stay tuned to see how we can use Elastic’s machine learning, AIOps, and AI Assistant to understand the issue.</p>
<h2>Conclusion</h2>
<p>SLOs allow you to set clear, measurable targets for your service performance, based on factors like availability, response times, error rates, and other key metrics. Hopefully with the overview we’ve provided in this blog, you can see that:</p>
<ul>
<li>
<p>SLOs can be based on logs. In Elastic, you can use KQL to essentially find and filter on specific logs and log fields to monitor and trigger SLOs.</p>
</li>
<li>
<p>AI Assistant is a valuable, easy-to-use capability to analyze, troubleshoot, and even potentially resolve SLO issues.</p>
</li>
<li>
<p>APM Service based SLOs are easy to create and manage with integration to Elastic APM. We also use OTel telemetry to help monitor SLOs.</p>
</li>
</ul>
<p>For more information on SLOs in Elastic, check out <a href="https://www.elastic.co/guide/en/observability/current/slo.html">Elastic documentation</a> and the following resources:</p>
<ul>
<li>
<p><a href="https://www.elastic.co/guide/en/observability/8.12/slo.html">What’s new in Elastic Observability 8.12</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/blog/context-aware-insights-elastic-ai-assistant-observability">Introducing the Elastic AI Assistant</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/blog/opentelemetry-observability">Elastic OpenTelemetry support</a></p>
</li>
</ul>
<p>Ready to get started? Sign up for <a href="https://cloud.elastic.co/registration">Elastic Cloud</a> and try out the features and capabilities I’ve outlined above to get the most value and visibility out of your SLOs.</p>
<p><em>The release and timing of any features or functionality described in this post remain at Elastic's sole discretion. Any features or functionality not currently available may not be delivered on time or at all.</em></p>
<p><em>In this blog post, we may have used or referred to third party generative AI tools, which are owned and operated by their respective owners. Elastic does not have any control over the third party tools and we have no responsibility or liability for their content, operation or use, nor for any loss or damage that may arise from your use of such tools. Please exercise caution when using AI tools with personal, sensitive or confidential information. Any data you submit may be used for AI training or other purposes. There is no guarantee that information you provide will be kept secure or confidential. You should familiarize yourself with the privacy practices and terms of use of any generative AI tools prior to use.</em></p>
<p><em>Elastic, Elasticsearch, ESRE, Elasticsearch Relevance Engine and associated marks are trademarks, logos or registered trademarks of Elasticsearch N.V. in the United States and other countries. All other company and product names are trademarks, logos or registered trademarks of their respective owners.</em></p>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/service-level-objectives-slos-logs-metrics/139686_-_Elastic_-_Headers_-_V1_3.jpg" length="0" type="image/jpg"/>
        </item>
    </channel>
</rss>