<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Agi K Thomas - Elastic Observability Labs]]></title>
    <description><![CDATA[Trusted security news & research from the team at Elastic.]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Agi K Thomas - Elastic Observability Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltad972c1c27dbefc6/6a88d9782904ea5e8511d473/observability-labs-thumbnail.png</url>
      <link>https://www.elastic.co/observability-labs/author/agi-thomas</link>
    </image>
    <link>https://www.elastic.co/observability-labs/author/agi-thomas</link>
    <atom:link href="https://www.elastic.co/observability-labs/rss/author/agi-thomas.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[en]]></language>
    <lastBuildDate>Fri, 11 Sep 2026 12:15:35 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Kubernetes observability: SLO templates that turn alerts into error budgets]]></title>
    <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://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4df618f6b39dd743/6a8ea15cf59d7c22f6c9386f/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 id="whykubernetesobservabilityneedsslomonitoringalongsidealerts">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 id="fourslotemplatesforkubernetesdeploymentsstatefulsetsdaemonsetsandjobs">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>
<p>| <strong>Template</strong>                                                | <strong>Rolling objective</strong> | <strong>Package description</strong>                                                                                                                                                                                                                           |
| ----------------------------------------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <strong>Deployment Replica Availability 99.5% Rolling 30 Days</strong>   | 99.5% / 30d           | 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. |
| <strong>StatefulSet Replica Availability 99.5% Rolling 30 Days</strong>  | 99.5% / 30d           | Same pattern for StatefulSets, where pod identity and ordering matter for databases, queues, and caches.                                                                                                                                          |
| <strong>DaemonSet Scheduling Availability 99.0% Rolling 30 Days</strong> | 99.0% / 30d           | Tracks whether each DaemonSet runs on all eligible nodes. Covers node-level agents such as log collectors, monitoring, security, and CNI plugins.                                                                                                 |
| <strong>Job Completion Success Rate 99.0% Rolling 30 Days</strong>       | 99.0% / 30d           | Tracks batch Jobs (ETL, backups, pipelines, scheduled tasks) completing without failed pods over the rolling window.                                                                                                                              |</p>
<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 id="howtosetslotargetsbykubernetesworkloadtype">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://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0b8c0979458feafa/6a8ea15fd98b5fb81fb15483/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 id="deploymentreplicaavailability995">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://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd80a6e2a042b37b6/6a8ea162cf026e84110c9d16/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 id="statefulsetreplicaavailability995">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 id="daemonsetschedulingavailability990">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 id="jobcompletionsuccessrate990">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 id="howdoslosandalertsworktogetherinkubernetesobservability">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>
<p>| <strong>SLO Template</strong>                  | <strong>Alert rule (Part 1)</strong>                                                 | <strong>Failure consequence</strong>                                          | <strong>Monthly budget (30d)</strong> |
| --------------------------------- | ----------------------------------------------------------------------- | ---------------------------------------------------------------- | ------------------------ |
| Deployment Replica Availability   | Deployment below the desired replicas                                   | Reduced throughput, degraded UX                                  | ~3.6 hours at 99.5%     |
| StatefulSet Replica Availability  | No dedicated rule. Covered by CrashLoopBackOff / OOMKilled at pod level | Split-brain risk, degraded durability                            | ~3.6 hours at 99.5%     |
| DaemonSet Scheduling Availability | Pod stuck in Pending / node disk pressure                               | Blind spots: unmonitored nodes and gaps in node-level coverage   | ~7.2 hours at 99.0%     |
| Job Completion Success Rate       | CrashLoopBackOff / OOMKilled                                            | Stale or incomplete data                                         | ~7.2 hours at 99.0%     |</p>
<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 id="fromincidenttoerrorbudgetburnakuberneteswalkthrough">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://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2d6ad2f74e0a59bd/6a8ea166f65645658a54b8e7/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://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdb63a9993f704b20/6a8ea169b4c43ed5190f14ae/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: "web-frontend-796fcd55b9-jmlkh"</code>. The event stream shows <code>ImagePullBackOff</code> and <code>Back-off pulling image "nginx:nonexistent-tag-999"</code>. The rollout references an image tag that does not exist.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt154dbe907e7b8e68/6a8ea16c76e02a2ba5fd5485/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 id="howtworolloutsconsumed88ofa30dayerrorbudget">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://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdc7ae205fd2e6375/6a8ea16fbc5bb344a3f93c7e/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://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9e36052030c8b486/6a8ea1723a56ed4c1938fc79/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 id="tryityourselftriggeranerrorbudgetburnonatestdeployment">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 id="whatsnextfromslomonitoringtoagenticremediation">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>
    <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>
    <category><![CDATA[OpenTelemetry]]></category>
    <category><![CDATA[Metrics]]></category>
    <dc:creator><![CDATA[Agi K Thomas]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltaf5fe3ce01efa1f7/6a8ea17576e02a4eccfd5489/kubernetes-observability-slo-error-budget-templates.png" length="0" type="image/png"/>
    <pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Observability for Amazon MQ with Elastic: Demystifying Messaging Flows with Real-Time Insights]]></title>
    <description><![CDATA[RabbitMQ, managed by Amazon MQ, enables asynchronous communication in distributed architectures but introduces operational risks such as retries, processing delays, and queue backlogs. Elastic’s Amazon MQ integration for RabbitMQ delivers deep observability into broker health, queue performance, message flow, and resource usage through Amazon CloudWatch metrics and logs. This blog outlines key operational risks associated with RabbitMQ and explains how Elastic observability helps maintain system reliability and optimize message delivery at scale.]]></description>
    <content:encoded><![CDATA[<h2 id="managingthehiddencomplexityofmessagedrivenarchitectures">Managing the Hidden Complexity of Message-Driven Architectures</h2>
<p>Amazon MQ is a managed message broker service for <a href="http://activemq.apache.org/">Apache ActiveMQ</a> Classic and <a href="https://www.rabbitmq.com/">RabbitMQ</a> that manages the setup, operation, and maintenance of message brokers. Messaging systems like RabbitMQ, managed by <a href="https://aws.amazon.com/amazon-mq/">Amazon MQ</a>, are pivotal in modern decoupled, event-driven applications. By serving as an intermediary between services, RabbitMQ facilitates asynchronous communication through message queuing, routing, and reliable delivery, making it an ideal fit for microservices, real-time pipelines, and event-driven architectures. However, this flexibility introduces operational challenges, such as retries, processing delays, consumer failures, and queue backlogs, which can gradually impact downstream performance and system reliability.</p>
<p>With Elastic’s <a href="https://www.elastic.co/docs/reference/integrations/aws_mq">Amazon MQ integration</a>, users gain deep visibility into message flow patterns, queue performance, and consumer health. This integration allows for the proactive detection of bottlenecks, helps optimize system behaviour, and ensures reliable message delivery at scale.</p>
<p>In this blog, we'll dive into the operational challenges of RabbitMQ in modern architectures, while also examining the common gaps and strategies for overcoming them.</p>
<h2 id="whyobservabilityforrabbitmqonamazonmqmatters">Why Observability for RabbitMQ on Amazon MQ Matters?</h2>
<p>RabbitMQ brokers are integral to distributed systems, handling tasks ranging from order processing to payment workflows and notification delivery. Any disruption can cascade into significant downstream issues. Observability into RabbitMQ helps answer critical operational questions like:​</p>
<ul>
<li>Is CPU and memory utilization increasing over time?</li>
<li>What are the trends in the message publish rate, message confirmation rate?</li>
<li>Are consumers failing to acknowledge messages?</li>
<li>Which queues are experiencing abnormal growth?</li>
<li>Are there an increasing number of messages being dead-lettered over time?</li>
</ul>
<h2 id="enhancedobservabilitywithamazonmqintegration">Enhanced Observability with Amazon MQ Integration</h2>
<p>Elastic provides a dedicated <a href="https://www.elastic.co/docs/reference/integrations/aws_mq">Amazon MQ integration</a> for RabbitMQ that utilizes Amazon CloudWatch metrics and logs to deliver comprehensive observability data. This integration enables the ingestion of metrics related to connections, nodes, queues, exchanges, and system logs.</p>
<p>By deploying <a href="https://www.elastic.co/elastic-agent">Elastic Agent</a> with this integration, the users can monitor:​</p>
<ul>
<li><strong>Queue performance and Dead-letter queue (DLQ) metrics</strong> include total message count (<code>MessageCount.max</code>), messages ready for delivery (<code>MessageReadyCount.max</code>), and unacknowledged messages (<code>MessageUnacknowledgedCount.max</code>). <code>MessageCount.max</code> metric tracks the total number of messages in a queue, including those that have been dead-lettered, and monitoring this over time can help identify trends in message accumulation, which may suggest issues leading to dead-lettering.</li>
<li><strong>Consumer behaviour</strong> through metrics like consumer count (<code>ConsumerCount.max</code>) and acknowledgement rate (<code>AckRate.max</code>), which help identify underperforming consumers or potential backlogs.</li>
<li><strong>Messaging throughput</strong> by tracking publish (<code>PublishRate.max</code>), confirm (<code>ConfirmRate.max</code>), and acknowledgement rates in real time. These are crucial for understanding application messaging patterns and flow.</li>
<li><strong>Broker and node-level health,</strong> including memory usage (<code>RabbitMQMemUsed.max</code>), CPU utilization (<code>SystemCpuUtilization.max</code>), disk availability (<code>RabbitMQDiskFree.min</code>), and file descriptor usage (<code>RabbitMQFdUsed.max</code>). These indicators are essential for diagnosing resource saturation and avoiding service disruption.</li>
</ul>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc24f4a23bb4ba33e/6a85c765501a8507cdfbb290/amazonmq-rabbitmq-dashboard-overview.png" alt="" /></p>
<h2 id="integratingamazonmqmetricsintoelasticobservability">Integrating Amazon MQ Metrics into Elastic Observability</h2>
<p>Elastic's Amazon MQ integration facilitates the ingestion of CloudWatch metrics and logs into Elastic Observability, delivering near real-time insights into RabbitMQ. The prebuilt Amazon MQ dashboard visualizes this data, providing a centralized view of broker health, messaging activity, and resource usage, helping users quickly detect and resolve issues. Elastic's <a href="https://www.elastic.co/docs/solutions/observability/incident-management/alerting">alerting</a> for Observability enables proactive notifications based on custom conditions, while its <a href="https://www.elastic.co/docs/solutions/observability/incident-management/service-level-objectives-slos">SLO</a> capabilities allow users to define and track key performance targets, strengthening system reliability and service commitments. </p>
<p>Elastic brings together logs and metrics from Amazon MQ alongside data from a wide range of other services and applications, whether running in AWS, on-premises, or across multi-cloud environments, offering unified observability from a single platform.</p>
<h3 id="prerequisites">Prerequisites</h3>
<p>To follow along, ensure you have:</p>
<ul>
<li>An account on <a href="http://cloud.elastic.co/">Elastic Cloud</a> and a deployed stack in AWS (<a href="https://www.elastic.co/guide/en/elastic-stack/current/installing-elastic-stack.html">see instructions here</a>). Ensure you are using version 8.16.5 or higher. Alternatively, you can use <a href="https://www.elastic.co/cloud/serverless">Elastic Cloud Serverless</a>, a fully managed solution that eliminates infrastructure management, automatically scales based on usage, and lets you focus entirely on extracting value from your data.</li>
<li>An AWS account with permissions to pull the necessary data from AWS. <a href="https://docs.elastic.co/en/integrations/aws#aws-permissions">See details in our documentation</a>.</li>
</ul>
<h3 id="architecture">Architecture</h3>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc7e5165fe435a3cd/6a85c7689bf994127a0a04bc/rabbitmq_lambda_messageflow.png" alt="" /></p>
<h2 id="tracingauditflowsfromrabbitmqtoawslambda">Tracing Audit Flows from RabbitMQ to AWS Lambda</h2>
<p>Consider a financial audit trail use case, where every user action, such as a funds transfer, is published to RabbitMQ. A Python-based AWS Lambda function consumes these messages, deduplicates them using the <strong>id</strong> field, and logs structured audit events for downstream analysis.</p>
<p>Sample payload sent through RabbitMQ:</p>
<pre><code>{
&amp;nbsp;&amp;nbsp;"id": "txn-849302",
&amp;nbsp;&amp;nbsp;"type": "audit",
&amp;nbsp;&amp;nbsp;"payload": {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"user_id": "u-10245",
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"event": "funds.transfer",
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"amount": 1200.75,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"currency": "USD",
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"timestamp": "T14:20:15Z",
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"ip": "192.168.0.8",
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"location": "New York, USA"
&amp;nbsp;&amp;nbsp;}
}
</code></pre>
<p>You can now correlate message publishing activity from RabbitMQ with AWS Lambda invocation logs, track processing latency, and configure alerts for conditions like drops in consumer throughput or an unexpected surge in RabbitMQ queue depth.</p>
<h3 id="awslambdafunctionprocessingrabbitmqmessages">AWS Lambda Function: Processing RabbitMQ Messages</h3>
<p>This Python-based AWS Lambda function processes audit events received from RabbitMQ. It deduplicates messages based on the <strong>id</strong> field and logs structured event data for downstream analysis or compliance. Save the code below in a file named <strong>app.py</strong>.</p>
<pre><code>import json
import logging
import base64
# Configure logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
# In-memory set to track processed message IDs for deduplication
processed_ids = set()
def lambda_handler(event, context):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.info("Lambda triggered by RabbitMQ event")
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if 'rmqMessagesByQueue' not in event:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.warning("Invalid event: missing 'rmqMessagesByQueue'")
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return {'statusCode': 400, 'body': 'Invalid RabbitMQ event'}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for queue_name, messages in event['rmqMessagesByQueue'].items():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.info(f"Processing queue: {queue_name}, Messages count: {len(messages)}")
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for msg in messages:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raw_data = msg['data']
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;decoded_json = base64.b64decode(raw_data).decode('utf-8')
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;message = json.loads(decoded_json)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.info(f"Decoded message: {json.dumps(message)}")
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;message_id = message.get('id')
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if not message_id:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.warning("Message missing 'id', skipping.")
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;continue
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if message_id in processed_ids:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.warning(f"Duplicate message detected: {message_id}")
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;continue
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;payload = message.get('payload', {})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.info(f"Processing message ID: {message_id}")
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.info(f"Event Type: {message.get('type')}")
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.info(f"User ID: {payload.get('user_id')}")
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.info(f"Event: {payload.get('event')}")
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.info(f"Amount: {payload.get('amount')} {payload.get('currency')}")
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.info(f"Timestamp: {payload.get('timestamp')}")
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.info(f"IP Address: {payload.get('ip')}")
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.info(f"Location: {payload.get('location')}")
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;processed_ids.add(message_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except Exception as e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logger.error(f"Error processing message: {str(e)}")
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return {'statusCode': 200, 'body': 'Messages processed successfully'}
</code></pre>
<h3 id="settingupawssecretsmanager">Setting up AWS Secrets Manager</h3>
<p>To securely store and manage your RabbitMQ credentials, use AWS Secrets Manager.​</p>
<ol>
<li><strong>Create a New Secret:</strong></li>
</ol>
<ul>
<li>Navigate to the<a href="https://console.aws.amazon.com/secretsmanager/"> AWS Secrets Manager console</a>.</li>
<li>Choose <strong>Store a new secret</strong>.</li>
<li>Select <strong>Other type of secret</strong>.</li>
<li>Enter the following key-value pairs:<ul>
<li><code>username</code>: Your RabbitMQ username</li>
<li><code>password</code>: Your RabbitMQ password</li></ul></li>
</ul>
<ol>
<li><strong>Configure the Secret:</strong></li>
</ol>
<ul>
<li>Provide a meaningful name, such as <code>RabbitMQAccess</code>.</li>
<li>Optionally, add tags and set rotation if needed.​</li>
</ul>
<ol>
<li><strong>Store the Secret:</strong></li>
</ol>
<ul>
<li>Review the settings and store the secret. Note the ARN of the secret you have created.
 <img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt08666b47e1f94017/6a85c76b2d64d51bca081caa/aws-secret-manager-configuration.png" alt="" /></li>
</ul>
<h3 id="settingupamazonmqforrabbitmq">Setting up Amazon MQ for RabbitMQ</h3>
<p>To get started with RabbitMQ on Amazon MQ, follow these steps to set up your broker.</p>
<ul>
<li><p>Open the <a href="https://console.aws.amazon.com/amazonmq/">Amazon MQ console</a>.</p></li>
<li><p>Create a new broker with the <strong>RabbitMQ</strong> engine.</p></li>
<li><p>Choose your preferred deployment option—<strong>single-instance</strong> or <strong>clustered</strong></p></li>
<li><p>Use the same <strong>username</strong> and <strong>password</strong> that you previously stored in <strong>AWS Secrets Manager</strong>.</p></li>
<li><p>Under <strong>Additional settings</strong>, enable <strong>CloudWatch Logs</strong> for observability.
<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt167e5c95f8e3f76e/6a85c76eeaf245dce0a49ec8/amazonmq-cloudwatch-enable.png" alt="" /></p></li>
<li><p>Configure access and security settings, ensuring that the broker is accessible to your AWS Lambda function.</p></li>
<li><p>After the broker is created, note the following important details:</p></li>
<li><p>ARN of the RabbitMQ broker.</p></li>
<li><p>RabbitMQ web console URL.
<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb73efc6fdb659c87/6a85c77043c0b728ac2f057d/amazonmq-rabbitmq-configuration-summary.png" alt="" /></p></li>
<li><p>You’ll need the RabbitMQ log group ARN to set up Elastic’s Amazon MQ integration for RabbitMQ. Follow these steps to locate it:</p></li>
<li><p>Go to the <strong>General – Enabled Logs</strong> section of the broker. </p></li>
<li><p>Copy the <strong>CloudWatch log group ARN</strong>.
<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt02016bdb2becda09/6a85c77333f244cd0b49f454/amazonmq-rabbitmq-loggroup-arn.png" alt="" /></p></li>
</ul>
<h3 id="createarabbitmqqueue">Create a RabbitMQ Queue</h3>
<p>Now that the RabbitMQ broker is configured, use the management console to create a queue where messages will be published.</p>
<ul>
<li>Access the RabbitMQ management console using the web console URL.</li>
<li>Create a new queue (example: <strong>myQueue</strong>) to receive messages.
<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbecef240548d449b/6a85c77511893c2658a7aae8/rabbitmq-create-queue.png" alt="" /></li>
</ul>
<h3 id="buildanddeploytheawslambdafunction">Build and deploy the AWS Lambda function</h3>
<p>In this section, we'll set up the Lambda function using AWS SAM, add the message processing logic, and deploy it to AWS. This Lambda function will be responsible for consuming messages from RabbitMQ and logging audit events.</p>
<p>Before continuing, make sure you have completed the following prerequisites.</p>
<ul>
<li><p><a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/prerequisites.html">AWS SAM prerequisites</a></p></li>
<li><p><a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html">Install the AWS SAM CLI</a></p></li>
</ul>
<p>Next, follow the steps outlined below to continue with the setup.</p>
<ol>
<li>In your command line, run the command <code>sam init</code> from a directory of your choice.</li>
<li>The AWS SAM CLI will walk you through the setup.<ul>
<li>Select <strong>AWS Quick Start Templates</strong>.</li>
<li>Choose the <strong>Hello World Example</strong> </li>
<li>Use the <strong>Python</strong> runtime and <strong>zip</strong> package type.</li>
<li>Proceed with the default options.</li>
<li>Name your application as <strong>sample-rabbitmq-app</strong>.</li>
<li>The AWS SAM CLI downloads your starting template and creates the application project directory structure.</li></ul></li>
<li>From your command line, move to the newly created sample-rabbitmq-app directory.<ul>
<li>Replace the content of the <strong>hello_world/app.py</strong> file with the lambda function code for rabbitmq message processing.</li>
<li>In the <strong>template.yaml</strong> file, use the values mentioned below to update the file content.
<code>yaml
Resources:
&amp;nbsp;SampleRabbitMQApp:
&amp;nbsp;&amp;nbsp;&amp;nbsp;Type: AWS::Serverless::Function
&amp;nbsp;&amp;nbsp;&amp;nbsp;Properties:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CodeUri: hello_world/
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Description: A starter AWS Lambda function.
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MemorySize: 128
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Timeout: 3
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Handler: app.lambda_handler
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Runtime: python3.10
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PackageType: Zip
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Policies:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Statement:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Effect: Allow
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Resource: '*'
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Action:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- mq:DescribeBroker
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- secretsmanager:GetSecretValue
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- ec2:CreateNetworkInterface
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- ec2:DescribeNetworkInterfaces
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- ec2:DescribeVpcs
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- ec2:DeleteNetworkInterface
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- ec2:DescribeSubnets
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- ec2:DescribeSecurityGroups
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Events:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MQEvent:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Type: MQ
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Properties:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Broker: &lt;ARN of the Broker&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Queues:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- myQueue
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SourceAccessConfigurations:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- Type: BASIC_AUTH
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;URI: &lt;ARN of the secret&gt;
</code></li></ul></li>
<li>Run the command <code>sam deploy --guided</code> and wait for the confirmation message. This deploys all of the resources.</li>
</ol>
<h3 id="sendingauditeventstorabbitmqandtriggeringlambda">Sending Audit Events to RabbitMQ and Triggering Lambda</h3>
<p>To test the end-to-end setup, simulate the flow by publishing audit event data into RabbitMQ using its web UI. Once the message is sent, it triggers the Lambda function. </p>
<ol>
<li>Navigate to the <a href="https://console.aws.amazon.com/amazon-mq/home">Amazon MQ console</a> and select your newly created broker.</li>
<li>Locate and open the Rabbit web console URL<br />
<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8eab69977143aaac/6a85c77811893c0963a7aaec/amazonmq-rabbitmq-webconsole-details.png" alt="" /></li>
<li>Under the <strong>Queues and Streams</strong> tab, select the target queue (example: <strong>myQueue</strong>).</li>
<li>Enter the message payload, and click <strong>Publish message</strong> to send it to the queue.<br />
Here’s a sample payload published via RabbitMQ:</li>
</ol>
<pre><code>   {
     "id": "txn-849302",
     "type": "audit",
     "payload": {
       "user_id": "u-10245",
       "event": "funds.transfer",
       "amount": 1200.75,
       "currency": "USD",
       "timestamp": "T14:20:15Z",
       "ip": "192.168.0.8",
       "location": "New York, USA"
     }
   }
</code></pre>
<ol>
<li>Navigate to the AWS Lambda function created earlier.</li>
<li>Under the <strong>Monitor</strong> tab, click <strong>View CloudWatch logs</strong>.</li>
<li>Check the latest log stream to confirm that the Lambda was triggered by Amazon MQ and that the message was processed successfully.
<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6745896b03a43a58/6a85c77b80984c3844668f47/amazonmq-lambda-logstream.png" alt="" /></li>
</ol>
<h2 id="configuringamazonmqintegrationformetricsandlogscollection">Configuring Amazon MQ integration for Metrics and Logs collection</h2>
<p>Elastic’s <a href="https://www.elastic.co/docs/reference/integrations/aws_mq">Amazon MQ integration</a> simplifies the collection of logs and metrics from RabbitMQ brokers managed by Amazon MQ. Logs are ingested via <strong>Amazon CloudWatch Logs</strong>, while metrics are fetched from the specified AWS region at a defined interval.</p>
<p>Elastic provides a default configuration for metrics collection. You can accept these defaults or adjust settings such as the <strong>Collection Period</strong> to better fit your needs.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt84b7cd1485929dc9/6a85c77dd7b2e743e7fe843e/amazonmq-metrics-configuration.png" alt="" /></p>
<p>To enable the collection of logs:</p>
<ol>
<li>Navigate to the <a href="https://console.aws.amazon.com/amazon-mq/home">Amazon MQ console</a> and select the newly created broker.</li>
<li>Click the <strong>Logs</strong> hyperlink under the <strong>General – Enabled Logs</strong> section to open the detailed log settings page.</li>
<li>From this page, copy the <strong>CloudWatch log group ARN</strong>.
<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt02016bdb2becda09/6a85c77333f244cd0b49f454/amazonmq-rabbitmq-loggroup-arn.png" alt="" /></li>
<li>In <strong>Elastic</strong>, set up the <strong>Amazon MQ integration</strong> and paste the CloudWatch log group ARN.
<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6f9312d1eeac7165/6a85c78199083f572540f947/amazonmq-logs-configuration.png" alt="" /></li>
<li><strong>Accept Defaults or Customize Settings</strong> – Elastic provides a <strong>default configuration</strong> for logs collection. You can accept these defaults or adjust settings such as <strong>collection intervals</strong> to better fit your needs.</li>
</ol>
<h3 id="visualizingrabbitmqworkloadswiththeprebuiltamazonmqdashboard">Visualizing RabbitMQ Workloads with the Pre-Built Amazon MQ Dashboard</h3>
<p>You can access the RabbitMQ dashboard by:</p>
<ol>
<li><p>Navigate to the Dashboard Menu – Select the Dashboard menu option in Elastic and search for <strong>[Amazon MQ] RabbitMQ Overview</strong> to open the dashboard.</p></li>
<li><p>Navigate to the Integrations Menu – Open the <strong>Integrations</strong> menu in Elastic, select <strong>Amazon MQ</strong>, go to the <strong>Assets</strong> tab, and choose <strong>[Amazon MQ] RabbitMQ Overview</strong> from the dashboard assets</p></li>
</ol>
<p>The Amazon MQ RabbitMQ dashboard in the Elastic integration delivers a comprehensive overview of broker health and messaging activity. It provides real-time insights into broker resource utilization, queue and topic performance, connection trends, and messaging throughput. The dashboard helps users track system behaviour, detect performance bottlenecks, and ensure reliable message delivery across distributed applications.</p>
<h4 id="brokermetrics">Broker Metrics</h4>
<p>This section provides a centralised view of the overall health and performance of the RabbitMQ broker on Amazon MQ. The visualizations highlights the number of configured exchanges and queues, active broker connections, producers, consumers, and total messages in flight. System-level metrics such as CPU utilization, memory consumption, and free disk space help assess whether the broker has sufficient resources to handle current workloads.</p>
<p>Message flow metrics such as publish rate, confirmation rate, and acknowledgement rate are displayed to provide visibility into how messages are processed through the broker. Monitoring trends in these values helps detect message delivery issues, throughput degradation, or potential saturation of the broker under load.</p>
<h4 id="nodemetrics">Node Metrics</h4>
<p>Node-level visibility helps identify resource imbalances across nodes in clustered RabbitMQ setups. This section includes per-node CPU usage, memory consumption, and available disk space, offering insight into the underlying infrastructure's ability to support broker operations.</p>
<h4 id="queuemetrics">Queue Metrics</h4>
<p>Queue-specific insights are critical for understanding message delivery patterns and backlog conditions. This section details total messages, ready messages, and unacknowledged messages, segmented by broker, virtual host, and queue.</p>
<p>By observing how these counts change over time, users can identify slow consumers, message build-ups, or delivery issues that may affect application performance or lead to dropped messages under pressure.</p>
<h4 id="logs">Logs</h4>
<p>This section displays log level, process ID, and raw message content. These logs provide immediate visibility into events such as connection failures, resource thresholds being hit, or unexpected queue behaviors.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt08bdcf335184796a/6a85c784331d7a8019c316d0/amazonmq-rabbitmq-dashboard.png" alt="" /></p>
<h3 id="detectingqueuebacklogswithalertingrules">Detecting Queue Backlogs with Alerting Rules</h3>
<p>Elastic’s <a href="https://www.elastic.co/docs/solutions/observability/incident-management/alerting">alert</a> framework allows you to define rules that monitor critical RabbitMQ metrics and automatically trigger actions when specific thresholds are breached. </p>
<h4 id="alertqueuebacklogmessagereadyorunacknowledgedmessages">Alert: Queue Backlog (Message Ready or Unacknowledged Messages)</h4>
<p>This alert helps detect queue backlog in Amazon MQ by evaluating two metrics </p>
<ul>
<li><code>MessageUnacknowledgedCount.max</code> and </li>
<li><code>MessageReadyCount.max</code>. </li>
</ul>
<p>The alert is triggered if either condition persists for more than <strong>10 minutes</strong>:</p>
<ul>
<li><code>MessageUnacknowledgedCount.max</code> exceeds <strong>5,000</strong></li>
<li><code>MessageReadyCount.max</code> exceeds <strong>7,000</strong></li>
</ul>
<p>These thresholds should be adjusted based on typical message volume and consumer throughput. Sustained high values can indicate that consumers are not keeping up or message delivery pipelines are congested, potentially causing delays or dropped messages. Sustained high values may result in processing delays or dropped messages if not addressed.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt50e0eb4b370c9c66/6a85c78799083f279d40f94b/amazonmq-alert-configuration.png" alt="" /></p>
<h3 id="trackingresourceutilizationtomaintainrabbitmqperformance">Tracking Resource Utilization to Maintain RabbitMQ Performance</h3>
<p>Elastic’s <a href="https://www.elastic.co/docs/solutions/observability/incident-management/service-level-objectives-slos">Service-level objectives (SLOs)</a> capabilities allow you to define and monitor performance targets using key indicators like latency, availability, and error rates. Once configured, Elastic continuously evaluates these SLOs in real time, offering intuitive dashboards, alerts for threshold violations, and insights into error budget consumption. This enables teams to stay ahead of issues, ensuring service reliability and consistent performance.</p>
<h4 id="slonoderesourcehealthcpumemorydisk">SLO: Node Resource Health (CPU, Memory, Disk)</h4>
<p>This SLO focuses on ensuring RabbitMQ brokers and nodes have sufficient resources to process messages without performance degradation. It tracks CPU, memory, and disk usage across RabbitMQ brokers and nodes to prevent resource exhaustion that could lead to service interruptions.</p>
<p><strong>Target thresholds:</strong></p>
<ul>
<li><code>SystemCpuUtilization.max</code> remains below <strong>85%</strong> for <strong>99%</strong> of the time.</li>
<li><code>RabbitMQMemUsed.max</code> remains below <strong>80%</strong> of <code>RabbitMQMemLimit.max</code> for <strong>99%</strong> of the time.</li>
<li><code>RabbitMQDiskFree.min</code> remains above <strong>25%</strong> of <code>RabbitMQDiskFreeLimit.max</code> for <strong>99%</strong> of the time.</li>
</ul>
<p>Sustained high values in CPU or memory usage can signal resource contention, which may result in slower message processing or downtime. Low disk availability may cause the broker to stop accepting messages, risking message loss. These thresholds are designed to catch early signs of resource saturation and ensure smooth, uninterrupted message flow across RabbitMQ deployments.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5b36bd4f9f3fc9bb/6a85c78a18249ca4e818f70d/amazonmq-slo-configuration.png" alt="" /></p>
<h2 id="conclusion">Conclusion</h2>
<p>As RabbitMQ-based messaging architectures scale and become more complex, the need for in-depth visibility into system performance and potential issues deepens. Elastic’s <a href="https://www.elastic.co/docs/reference/integrations/aws_mq">Amazon MQ integration</a> brings that visibility front and center—helping you go beyond basic health checks to understand real-time messaging throughput, queue backlog trends, and resource saturation across your brokers and consumers.</p>
<p>By leveraging the prebuilt dashboards, configuring alerts and SLOs, you can proactively detect anomalies, fine-tune consumer performance, and ensure reliable delivery across your event-driven applications.</p>]]></content:encoded>
    <link>https://www.elastic.co/observability-labs/blog/amazonmq-observability-rabbitmq-integration</link>
    <guid isPermaLink="false">amazonmq-observability-rabbitmq-integration</guid>
    <category><![CDATA[Infrastructure Monitoring]]></category>
    <category><![CDATA[Metrics]]></category>
    <dc:creator><![CDATA[Agi K Thomas,Udayasimha Theepireddy]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9a221b8b9fa36929/6a85c78d43c0b790d62f058e/AmazonMQ-observability-RabbitMQ.jpg" length="0" type="image/jpeg"/>
    <pubDate>Fri, 02 May 2025 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>