<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Honeycomb.io</title>
    <description>The latest articles on DEV Community by Honeycomb.io (@honeycombio).</description>
    <link>https://dev.to/honeycombio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F2037%2F81a225aa-09c0-48ce-9977-b7308f2119a1.jpg</url>
      <title>DEV Community: Honeycomb.io</title>
      <link>https://dev.to/honeycombio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/honeycombio"/>
    <language>en</language>
    <item>
      <title>The Future of Developer Careers</title>
      <dc:creator>Christine Yen</dc:creator>
      <pubDate>Wed, 12 May 2021 21:15:26 +0000</pubDate>
      <link>https://dev.to/honeycombio/the-future-of-developer-careers-gp3</link>
      <guid>https://dev.to/honeycombio/the-future-of-developer-careers-gp3</guid>
      <description>&lt;p&gt;While JavaScript frameworks come and go, a change has been brewing over the last several years that will permanently change what it means to be a modern developer: how our code goes from our laptops to the wild. The widespread adoption of containers, microservices and orchestration have made it easier than ever to take a small bit of software and push it live in front of users — and, in doing so, push a whole bunch of comfortable tasks (debugging, profiling) into uncomfortable territory: production.&lt;/p&gt;

&lt;p&gt;I hate to be the bearer of bad news (not really), but the reality for developers is that it’s only getting more complicated to ensure the code you write still works. Assuming operational responsibility for the code you write is becoming a larger and larger part of the developer role — even as “where it runs” gets further and further away from “where it was written.”&lt;/p&gt;

&lt;p&gt;The first wave of DevOps primarily embodied Ops folks learning how to Dev: to “automate everything” through code. The second wave, naturally, is now about Dev folks learning how to Ops: now, we own the running of our code in production. But while the two shifting waves typically come together in cross-functional DevOps teams, “understanding production” has historically carried with it a heavy Ops bias.&lt;/p&gt;

&lt;p&gt;It’s almost ironic, really — recent trends in platform abstractions have turned everything into code. (Hi, serverless! And thanks, Heroku.) What that should have meant is that understanding what’s happening in production would be easier for devs, not harder. Let’s take a look at why that hasn’t been the case, and how it should be instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shoehorning Devs into Ops: What Could Go Wrong?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Leading software engineering organizations are increasingly asking developers to &lt;a href="https://increment.com/on-call/who-owns-on-call/"&gt;own their code in production&lt;/a&gt;. Software engineers are being asked to &lt;a href="https://copyconstruct.medium.com/on-call-b0bd8c5ea4e0"&gt;join on-call rotations&lt;/a&gt;, with varying levels of support.&lt;/p&gt;

&lt;p&gt;And yet, conventional “production monitoring” tools are inherently hostile to how developers think and work with their code. Traditional approaches to understanding “production” are tied to an application’s underlying infrastructure. Graphs of data like CPU utilization, network throughput, or database load are very infrastructure-centric ways to understand the world. Just because the lines continue to blur between dev and ops doesn’t mean we simply transfer over previous mental models of the world — the goal of DevOps isn’t to simply swap out responsibilities. The goal of shifting into DevOps is to get the most out of the varied skills, background and mindsets that comprise these new cross-functional teams.&lt;/p&gt;

&lt;p&gt;Traditional production monitoring tools were written long before the era of DevOps — they speak the language of Ops, not Devs. Unfortunately, that sets up an artificial barrier to entry for developers to think about production as a place they own. We’ve done nothing to help developers see their world as it exists in production. Developers often get handed a dashboard full of Cassandra read/write throughput graphs, thread counts and memtable sizes, as if that somehow inducts them into the club of production ownership.&lt;/p&gt;

&lt;p&gt;Sure, those metrics and graphs look cool — but there’s often no way to connect that information back to the code, business logic or customer needs that are the world of software development. When problems occur, there’s a big mental leap that exists between seeing that information and tying it back to “what really happened.” And even if that leap can somehow be made, there’s certainly no path at all that leads toward reproducing any observed phenomenon, much less writing the code to fix it.&lt;/p&gt;

&lt;p&gt;The cognitive leap that traditional production monitoring tools require developers to make doesn’t get a lot of attention, because that’s simply how things are done for Ops engineers. In some corners of engineering, there’s a smug satisfaction that devs now have to make that leap. Feel our pain, devs! How do you not know that when both of these lines trend down and that graph turns red, it means your application has run out of memory? Welcome to production.&lt;/p&gt;

&lt;p&gt;That cavalier attitude reinforces the hostility reflected by the approach taken by traditional monitoring tools. In practice, that approach inadvertently leads to situations where devs simply follow the breadcrumbs and do their best to replicate production debugging patterns they don’t fully understand. Culturally, it creates a moat between the approaches that Ops values and the approaches that Dev values — and reinforces the illusion that production is a hostile place for developers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enhance Existing Dev Behaviors&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead, a more welcoming approach is to tap into what we Devs do naturally when debugging: allow us to quickly compare our expected outcome against the actual outcome (e.g. this code should handle 10K req/sec, but seems to only handle 100 req/sec). Devs share this part of the investigative journey with their Ops comrades. However, where Ops and Dev patterns deviate is when digging into understanding why that deviation occurs.&lt;/p&gt;

&lt;p&gt;For Devs, we compare “expected” against “actual” all the time in test suites. Investigating test failures means digging into the code, walking through the logic, and questioning our assumptions. Being able to capture business logic-level metadata in production (often high cardinality, often across many dimensions) is a baseline requirement for being able to tap into Dev experience for production problems.&lt;/p&gt;

&lt;p&gt;We need a specific replicable test case. Being able to tap into the specificity of custom attributes like userID, partitionID, etc, is what enables production to feel like an extension of development and test workflows, as opposed to some new foreign and hostile environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Developer Approach to Production&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With the advent of PaaS, IaaS, and serverless, our world is increasingly abstracting infrastructure away. That’s paved the way for both waves of DevOps and it has made room to redefine priorities. For software development teams that own running their code in prod, that means they’ve shifted toward aligning their definition of successful operation with what ultimately matters to the business — whether the users of that software are having a good customer experience.&lt;/p&gt;

&lt;p&gt;That shift works very well for developers who are accustomed to having functions, endpoints, customer IDs, and other business-level identifiers naturally live in their various tests. Those types of identifiers will only continue to become more critical when investigating and understanding the behavior of production systems. (In contrast, traditional monitoring systems focus on the aggregate behavior of an overall system and almost never include these types of identifiers.)&lt;/p&gt;

&lt;p&gt;All of the questions that developers should ask about production boil down to two basic forms:&lt;/p&gt;

&lt;p&gt;Is my code running in the first place?&lt;br&gt;
Is my code behaving as expected in production?&lt;/p&gt;

&lt;p&gt;As a developer in a world with frequent deploys, the first few things I want to know about a production issue are: When did it start happening? Which build is, or was, live? Which code changes were new at that time? And is there anything special about the conditions under which my code is running?&lt;/p&gt;

&lt;p&gt;The ability to correlate some signal to a specific build or code release is table stakes for developers looking to grok production. Not coincidentally, “build ID” is precisely the sort of “unbounded source” of metadata that traditional monitoring tools warn against including. In metrics-based monitoring systems, doing so commits to an infinitely increasing set of metrics captured, negatively impacting the performance of that monitoring system AND with the added “benefit” of paying your monitoring vendor substantially more for it.&lt;/p&gt;

&lt;p&gt;Feature flags — and the combinatorial explosion of possible parameters when multiple live feature flags intersect — throw additional wrenches into answering Question 1. And yet, feature flags are here to stay; so our tooling and techniques simply have to level up to support this more flexibly defined world.&lt;/p&gt;

&lt;p&gt;Question 2, on the other hand, is the same question we ask anytime we run a test suite: “Does my code’s actual execution match what I expect?” The same signals that are useful to us when digging into a failing test case are what help us understand, reproduce and resolve issues identified in production.&lt;/p&gt;

&lt;p&gt;A developer approach to debugging prod means being able to isolate the impact of the code by endpoint, by function, by payload type, by response status, or by any other arbitrary metadata used to define a test case. Developers should be able to take those pieces and understand the real-world workload handled by their systems, and then &lt;a href="https://thenewstack.io/a-next-step-beyond-test-driven-development/"&gt;adjust their code accordingly&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Way Forward: A Developer-Friendly Prod&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The future of Dev careers isn’t about having different bespoke ways of approaching debugging your production environment. DevOps is about getting the most out of your new cross-functional teams and, luckily — when it comes to using tools to get answers to the questions you care about in production — there’s an opportunity to all get on the same page. Whether your team labels itself Devs, Ops, Devops, or SRE, you can all use tools that speak the same language.&lt;/p&gt;

&lt;p&gt;In today’s abstracted world — one full of ephemeral instances, momentary containers and serverless functions — classic infrastructure metrics are quickly fading into obsolescence. This is happening so quickly that it even calls into question the &lt;a href="https://thenewstack.io/the-future-of-ops-careers/"&gt;future of ops careers&lt;/a&gt;. A fundamentally better approach to understanding production is necessary — for everyone.&lt;/p&gt;

&lt;p&gt;A good first step is shifting focus away from metrics like CPU and memory and instead embracing &lt;a href="https://www.weave.works/blog/the-red-method-key-metrics-for-microservices-architecture/"&gt;RED metrics&lt;/a&gt; as the primary signal of service health. That can substantially lower the barrier for entry to production for most developers. Devs can then be armed with the metadata necessary to understand the impact of any given graph, by tagging those metrics with customer ID, API endpoint, resource type, customer action, etc. It bridges the gap between capturing metrics in prod and tying them back to code and tests.&lt;/p&gt;

&lt;p&gt;One step better is the reason that observability has seen an explosion in popularity. Observability is &lt;a href="https://www.honeycomb.io/blog/observability-whats-in-a-name/"&gt;not a synonym for monitoring&lt;/a&gt;. Observability takes an event-based approach that still allows you to &lt;a href="https://www.honeycomb.io/blog/getting-metrics-into-honeycomb/"&gt;incorporate infrastructure metrics&lt;/a&gt; to understand the behavior of your production systems. It’s an entirely different approach to the Ops-centric world of monitoring that enables understanding the behavior of production systems in ways that makes them accessible to engineers from all backgrounds.&lt;/p&gt;

&lt;p&gt;The future of dev careers should be defined by struggling to understand the correlations between traditional monitoring tools and where that ties into your code. By breaking away from traditional monitoring tools, the future of dev careers instead becomes one where understanding what’s happening in prod feels every bit as natural as understanding why code failed in your development or test environments.&lt;/p&gt;

&lt;p&gt;Over the last decade and change, as an industry, we’ve all gotten really good at taking code and shipping it to the user. That was Heroku’s promise, after all: simply and magically hooking a production environment up to a developer’s natural workflow. And because of this — because of how much closer we’ve brought production to the development environment — the developer skill set has to follow the same trajectory… or risk being left behind.&lt;/p&gt;

&lt;p&gt;Learn more about making production more approachable to devs and to ops in &lt;a href="https://www.honeycomb.io/developing-a-culture-of-observability/?&amp;amp;utm_source=tns&amp;amp;utm_medium=blog-links&amp;amp;utm_campaign=referral&amp;amp;utm_content=developing-a-culture-of-observability-tns"&gt;Honeycomb’s Guide to Developing a Culture of Observability&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Want to know how Honeycomb.io helps software developers? &lt;a href="https://www.honeycomb.io/get-a-demo?&amp;amp;utm_source=Devto&amp;amp;utm_Devto=blog&amp;amp;utm_campaign=referral&amp;amp;utm_keyword=%7Bkeyword%7D&amp;amp;utm_content=the-future-of-developer-careers"&gt;Schedule 1:1 time&lt;/a&gt; with our technical experts.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A Culture of Observability Helps Engineers Hit the Spot (Instance)</title>
      <dc:creator>honeycomb</dc:creator>
      <pubDate>Mon, 11 Jan 2021 17:47:25 +0000</pubDate>
      <link>https://dev.to/honeycombio/a-culture-of-observability-helps-engineers-hit-the-spot-instance-16nf</link>
      <guid>https://dev.to/honeycombio/a-culture-of-observability-helps-engineers-hit-the-spot-instance-16nf</guid>
      <description>&lt;p&gt;At Honeycomb, we’re big fans of AWS Spot Instances. During a &lt;a href="https://www.honeycomb.io/blog/treading-in-haunted-graveyards/"&gt;recent bill reduction exercise&lt;/a&gt;, we found significant savings in running our API service on Spot, and now look to use it wherever we can. Not all services fit the mold for Spot, though. While a lot of us are comfortable running services atop on-demand EC2 instances by now, with hosts that could be terminated or fail at any time, this is relatively rare when compared with using Spot, where sudden swings in the Spot market can result in your instances going away with only two minutes of warning. When we considered running a brand-new, stateful, and time-sensitive service on Spot, it seemed like a non-starter, but the potential upside was too good to not give it a try.&lt;/p&gt;

&lt;p&gt;Our strong culture of observability and the environment it enables means we have the ability to experiment safely. With a bit of engineering thoughtfulness, modern deployment processes, and good instrumentation we were able to make the switch with confidence. Here's how we did it:&lt;/p&gt;

&lt;h2&gt;What we needed to support&lt;/h2&gt;

&lt;p&gt;We're working on a feature that enables you to do trace-aware sampling with just a few clicks in our UI. The backend service (internal name Dalmatian) is responsible for buffering trace events and making sampling decisions on the complete trace. To work correctly, it must:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;process a continuous, unordered stream of events from the API as quickly as possible&lt;/li&gt;
    &lt;li&gt;group and buffer related events long enough to make a decision&lt;/li&gt;
    &lt;li&gt;avoid re-processing the same traces, and make consistent decisions for the same trace ID for spans that arrive late&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To accomplish grouping, we use a deterministic mapping function to route trace IDs to the same Kafka partition, with each partition getting processed by one Dalmatian host. To keep track of traces we’ve already processed, we also need this pesky little thing called state. Specifically:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;the current offset in the event stream,&lt;/li&gt;
    &lt;li&gt;the offset of the oldest seen trace not yet processed,&lt;/li&gt;
    &lt;li&gt;recent history of processed trace IDs and their sampling decision.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This state is persisted to a combination of Redis and S3, so Dalmatian doesn’t need to store anything locally between restarts. Instead, state is regularly flushed to external storage. That’s easy. Startup is more complex, however, as there are some precise steps that need to happen to resume event processing correctly. There’s also a lot of state fetching to do, which adds time and can fail. In short, once the service is running, it’s better to not rock the boat and just let it run. Introducing additional chaos with hosts that come and go more frequently was something to consider before running this service on Spot.&lt;/p&gt;

&lt;h2&gt;Chaos by default&lt;/h2&gt;

&lt;p&gt;As part of the observability-centric culture we strive for at Honeycomb, we &lt;a href="https://www.honeycomb.io/blog/working-on-hitting-a-release-cadence-ci-cd-observability-can-help-you-get-there/"&gt;embrace CI/CD&lt;/a&gt;. Deploys go out every hour. Among the many benefits of this approach is that our deploy system is regularly exercised, and our services undergo restarts all the time. Building a stateful service with a complex startup and shutdown sequence in this environment means that bugs in those sequences are going to show themselves very quickly. By the time we considered running Dalmatian on Spot (queue the puns), we’d already made our state management stable through restarts, and most of the problems Spot might have introduced were already handled.&lt;/p&gt;

&lt;h2&gt;Hot spare Spots&lt;/h2&gt;

&lt;p&gt;There was one lingering issue with using Spot though: having hosts regularly go away means we need to wait on new hosts to come up. Between ASG response times, Chef, and our deploy process, it averages 10 minutes for a new host to come online. It’s something we hope to improve one day, but we’re not there yet. With one processing host per partition, that means losing a host can result in at least a 10 minute delay in event processing. That’s a bad experience for our customers, and one we’d like to avoid. Fortunately, Spot instances are cheap, and since we’re averaging a 70% savings on instance costs, we can afford to run with extra hosts in standby mode. This is accomplished with a bit of extra terraform code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;min_size&lt;/span&gt;                  &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dalmatian_instance_count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ceil&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dalmatian_instance_count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="err"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;max_size&lt;/span&gt;                  &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dalmatian_instance_count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ceil&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dalmatian_instance_count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="err"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a small modification in our process startup code, instances will wait for a partition to become free and immediately pick up that partition’s workload.&lt;/p&gt;

&lt;h2&gt;Spot how we're doing&lt;/h2&gt;

&lt;p&gt;We’ve made a significant change to how we run this service. How do we know if things are working as intended? Well, let’s define &lt;b&gt;working&lt;/b&gt;, aka our &lt;a href="https://www.honeycomb.io/blog/working-toward-service-level-objectives-slos-part-1/"&gt;Service Level Objective&lt;/a&gt;. We think that significant ingestion delays break our core product experience, so for Dalmatian and the new feature, we set an SLO that events should be processed and delivered in under five minutes, 99.9% of the time.&lt;/p&gt;

&lt;p&gt;With the SLO for context, we can restate our question as: Can we move this new functionality onto Spot Fleets and still maintain our Service Level Objective despite the extra host churn?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KHt38xKR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2019/10/replacing-hosts.png" class="article-body-image-wrapper"&gt;&lt;img class="aligncenter size-full wp-image-5251" src="https://res.cloudinary.com/practicaldev/image/fetch/s--KHt38xKR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2019/10/replacing-hosts.png" alt="screenshot of heatmap with trailing edges showing added hosts" width="767" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the last month in our production environment, we have observed at least 10 host replacements. This is higher than usual churn than we’ve had in the past, but also what we expected with Spot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ENmsXp5t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2019/10/slo-compliance.png" class="article-body-image-wrapper"&gt;&lt;img class="aligncenter size-full wp-image-5252" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ENmsXp5t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2019/10/slo-compliance.png" alt="screenshot showing 100% SLO compliance graph" width="683" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In that same month, we stayed above our threshold for SLO compliance (99.9%). From this perspective, it looks like a successful change - one we’re excited about because it saves us a significant amount in operational expenses.&lt;/p&gt;

&lt;h2&gt;New firefighting capabilities must be part of the plan&lt;/h2&gt;

&lt;p&gt;Things are working fine now, but they might break in the future. Inevitably, we will find ourselves running behind in processing events. One set of decisions we had to make for this service was “what kind of instance do we run on, and how large?”. When we’re keeping up with incoming traffic, we can run on smaller instance types. If we ever fall behind, though, we need more compute to catch up as quickly as we can, but that’s expensive to run all the time when we may only need it once a year. Since we have a one processor per partition model, we can’t really scale out dynamically. But we can scale up!&lt;/p&gt;

&lt;p&gt;Due to the previously mentioned 10 min host bootstrapping time, swapping out every host with a larger instance is not ideal. We’ll fall further behind while we wait to bring the instances up, and once we decide to scale down, we’ll fall behind again. What if we stood up an identically sized fleet with larger instances and cut over to that? This Terraform spec defines what we call our “catch-up fleet”. The ASG exists only when &lt;code&gt;dalmatian_catchup_instance_count&lt;/code&gt; is greater than 0. In an emergency, a one-line diff can bring this online.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_autoscaling_group"&lt;/span&gt; &lt;span class="s2"&gt;"dalmatian_catchup_asg"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dalmatian_catchup_${var.env}"&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dalmatian_catchup_instance_count&lt;/span&gt; &lt;span class="err"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;gt&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

  &lt;span class="c1"&gt;# ...&lt;/span&gt;

  &lt;span class="nx"&gt;launch_template&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;launch_template_specification&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;launch_template_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_launch_template&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dalmatian_lt&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"$Latest"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;dynamic&lt;/span&gt; &lt;span class="s2"&gt;"override"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dalmatian_catchup_instance_types&lt;/span&gt;
      &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;override&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the hosts are ready, we can cut over to them by stopping all processes on the smaller fleet, enabling the “hot spares” logic to kick in on the backup fleet. When we’re caught up, we can repeat the process in reverse: start the processes on the smaller fleet, and stop the larger fleet. Using Honeycomb, of course, we were able to verify that this solution works with a fire drill in one of our smaller environments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZACynbFF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2019/10/cutover.png" class="article-body-image-wrapper"&gt;&lt;img class="aligncenter size-full wp-image-5250" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZACynbFF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2019/10/cutover.png" alt="screenshot of the cutover timeframe, validating low latency" width="726" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Spot the benefits of an observability-centric culture&lt;/h2&gt;

&lt;p&gt;Ok maybe that's enough spot-related puns, but the point here is that our ability to experiment with new architectures and make significant changes to how services operate is predicated on our ability to deploy rapidly and find out how those changes impact the behavior of the system. Robust CI/CD processes, thoughtful and context-rich instrumentation, and attention to what we as software owners will need to do to support this functionality in the future makes it easier and safer to build and ship software our users love and benefit from.&lt;/p&gt;




&lt;p&gt;Ready to take the sting out of shipping new software? Honeycomb helps you spot outliers and find out how your users experience your service. &lt;a href="https://www.honeycomb.io/product-trial/"&gt; &lt;/a&gt;&lt;a href="https://ui.honeycomb.io/signup?&amp;amp;utm_source=Devto&amp;amp;utm_Devto=blog&amp;amp;utm_campaign=referral&amp;amp;utm_keyword=%7Bkeyword%7D&amp;amp;utm_content=a-culture-of-observability-helps-engineers-hit-the-spot-instance"&gt;Get started for free!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>observability</category>
      <category>aws</category>
      <category>devops</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Instrumenting Lambda with Traces: A Complete Example in Python</title>
      <dc:creator>honeycomb</dc:creator>
      <pubDate>Mon, 04 Jan 2021 22:02:15 +0000</pubDate>
      <link>https://dev.to/honeycombio/instrumenting-lambda-with-traces-a-complete-example-in-python-gnk</link>
      <guid>https://dev.to/honeycombio/instrumenting-lambda-with-traces-a-complete-example-in-python-gnk</guid>
      <description>&lt;p&gt;We’re big fans of AWS Lambda at Honeycomb. As you &lt;a href="https://www.honeycomb.io/blog/secondary-storage-to-just-storage/"&gt;may have read&lt;/a&gt;, we recently made some major improvements to our storage engine by leveraging Lambda to process more data in less time. Making a change to a complex system like our storage engine is daunting, but can be made less so with good instrumentation and tracing. For this project, that meant getting instrumentation out of Lambda and into Honeycomb. Lambda has some unique constraints that make this more complex than you might think, so in this post we’ll look at instrumenting an app from scratch.&lt;/p&gt;

&lt;h2&gt;Bootstrapping the app&lt;/h2&gt;

&lt;p&gt;Before we begin, you’ll want to ensure you have the &lt;a href="https://serverless.com/framework/docs/getting-started/"&gt;Serverless&lt;/a&gt; framework installed and a recent Python version (I’m using 3.6). For this example, I picked a Serverless Python TODO API template in the Serverless &lt;a href="https://github.com/serverless/examples"&gt;Examples&lt;/a&gt; repo. I like this particular template for demonstration because it sets up an external dependency (DynamoDB), which gives us something interesting to look at when we’re tracing. To install the demo app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sls &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--url&lt;/span&gt; https://github.com/serverless/examples/tree/master/aws-python-rest-api-with-dynamodb &lt;span class="nt"&gt;--name&lt;/span&gt; my-sls-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see a project directory with some contents like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-sls-app &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;span class="go"&gt;README.md    package.json    serverless.yml    todos
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There’s just a bit more to add before we get going. We want to install &lt;code&gt;honeycomb-beeline&lt;/code&gt; in our app, so we’ll need to package the Python requirements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;install &lt;/span&gt;the serverless-python-requirements module
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; serverless-python-requirements
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;install &lt;/span&gt;beeline-python &lt;span class="k"&gt;in &lt;/span&gt;a venv, &lt;span class="k"&gt;then &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;the requirements.txt
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;virtualenv venv &lt;span class="nt"&gt;--python&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;python3
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;honeycomb-beeline
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;pip freeze &amp;amp;gt&lt;span class="p"&gt;;&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now edit &lt;code&gt;serverless.yml&lt;/code&gt; and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# essentially, this injects your python requirements into the package&lt;/span&gt;
&lt;span class="c1"&gt;# before deploying. This runs in docker if you're not deploying from a linux host&lt;/span&gt;
&lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-python-requirements&lt;/span&gt;

&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pythonRequirements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;dockerizePip&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;non-linux&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can deploy using &lt;code&gt;sls deploy&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;Serverless: Packaging service...
[...]
endpoints:
  POST - https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos
  GET - https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos
  GET - https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos/{id}
  PUT - https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos/{id}
  DELETE - https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos/{id}
functions:
  create: my-sls-app-dev-create
  list: my-sls-app-dev-list
  get: my-sls-app-dev-get
  update: my-sls-app-dev-update
  delete: my-sls-app-dev-delete
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few curl calls against the new endpoints confirm we’re in good shape!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;db is empty initially
&lt;span class="go"&gt;[]
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"text": "write a blog post"}'&lt;/span&gt; https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos
&lt;span class="go"&gt;{"id": "267199de-25c0-11ea-82d7-e6f595c02494", "text": "write a blog post", "checked": false, "createdAt": "1577131779.711644", "updatedAt": "1577131779.711644"}
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos
&lt;span class="go"&gt;[{"checked": false, "createdAt": "1577131779.711644", "text": "write a blog post", "id": "267199de-25c0-11ea-82d7-e6f595c02494", "updatedAt": "1577131779.711644"}]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;Implementing tracing&lt;/h2&gt;

&lt;p&gt;The first step is to initialize the beeline. The &lt;code&gt;todos/&lt;strong&gt;init&lt;/strong&gt;.py&lt;/code&gt; file is a great place to drop that init code so that it gets pulled in by all of the Lambda handlers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;beeline&lt;/span&gt;
&lt;span class="n"&gt;beeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writekey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'YOURWRITEKEY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;service_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'todo-app'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'my-sls-app'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s look at that curl we ran earlier. That’s hitting the &lt;code&gt;list&lt;/code&gt; function on the API. Let’s open this up and add some instrumentation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ...
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;beeline&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;beeline.middleware.awslambda&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;beeline_wrapper&lt;/span&gt;

&lt;span class="c1"&gt;# The beeline_wrapper decorator wraps the Lambda handler here in a span. By default,
# this also starts a new trace. The span and trace are finished when the function exits
# (but before the response is returned)
&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;beeline_wrapper&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'DYNAMODB_TABLE'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;beeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_context_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"table_name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# This call to our db dependency is worth knowing about - let's wrap it in a span.
&lt;/span&gt;    &lt;span class="c1"&gt;# That's easy to do with a context manager.
&lt;/span&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;beeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"db-scan"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# fetch all todos from the database
&lt;/span&gt;        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# .. capture any results we want to include from this function call
&lt;/span&gt;    &lt;span class="n"&gt;beeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_context&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="s"&gt;'status_code'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'num_items'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'Items'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;# create a response
&lt;/span&gt;    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'Items'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;decimalencoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DecimalEncoder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another &lt;code&gt;sls deploy&lt;/code&gt; gets our instrumentation out there. Once deployed, I can re-run that curl again. Now I have a trace in my dataset!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aQftfGW6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/01/example-trace1.png" class="article-body-image-wrapper"&gt;&lt;img class="alignnone size-full wp-image-5765" src="https://res.cloudinary.com/practicaldev/image/fetch/s--aQftfGW6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/01/example-trace1.png" alt="screenshot of an individual trace in honeycomb" width="804" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The trace shows me a Lambda runtime of 6.7ms, but from the client, it seemed slow, so I check the Lambda execution logs and see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REPORT RequestId: def28374-1e35-429b-8667-3ab481b61ad4 Duration: 37.27 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why the discrepancy?&lt;/p&gt;

&lt;h2&gt;The instrumentation performance tax&lt;/h2&gt;

&lt;p&gt;The lifecycle of a Lambda container is tricky. You may already know about cold starts. That is, your code isn’t really running until it is invoked, and when it does run, the container has to start up and this can add latency to your initial invocation(s). Once your function returns a response, it goes into a frozen state, and execution of any running threads is suspended. From there, the container may be reused (without the cold start penalty) by subsequent requests, or terminated. This termination is not done gracefully, and thus the running function isn't given a chance to do housekeeping.&lt;/p&gt;

&lt;p&gt;What does that mean if you’re trying to send telemetry?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Typical client patterns using delayed batching, like those used in our SDKs, are unreliable in Lambda, since the batch transmission thread(s) may never get a chance to run after the function exits.&lt;/li&gt;
  &lt;li&gt;Anything that needs to be sent reliably must be sent before the function returns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s why if you crack open the Beeline middleware code for Lambda, you’ll see this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;beeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_beeline&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is our way of ensuring event batches are sent before the function exits. But it isn't free. The effect of this is that it delays response to the client by the round-trip time from your Lambda to our API. For many use cases, that's an acceptable tradeoff for getting instrumentation out of Lambda. But what if your application (or your user) is latency-sensitive?&lt;/p&gt;

&lt;h2&gt;Cloudwatch logs to the rescue&lt;/h2&gt;

&lt;p&gt;There is one way to synchronously ship data from a Lambda function without significant blocking: logging.&lt;br&gt;
If you want detailed telemetry without a performance hit, this is the currently the only way to go. Each Lambda function writes to its own Cloudwatch Log stream, and AWS makes it relatively easy to subscribe to those streams with other Lambda functions. Here’s where we introduce the &lt;a href="https://github.com/honeycombio/agentless-integrations-for-aws#honeycomb-publisher-for-lambda"&gt;Honeycomb Publisher for Lambda&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Publisher can subscribe to one or more Cloudwatch Log streams, pulling in event data in JSON format and shipping it to the correct dataset. To use it, you need to deploy it and subscribe it to your Lambda function(s) log streams, then configure your app to emit events via logs.&lt;/p&gt;

&lt;h3&gt;Switching to log output&lt;/h3&gt;

&lt;p&gt;The Python Beeline makes it &lt;a href="https://docs.honeycomb.io/getting-data-in/python/beeline/#customizing-event-transmission"&gt;easy&lt;/a&gt; to override the event transmission mechanism. For our purpose here, we’ll use the built-in &lt;code&gt;FileTransmission&lt;/code&gt; with output to sys.stdout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;beeline&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;libhoney&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;libhoney.transmission&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FileTransmission&lt;/span&gt;
&lt;span class="n"&gt;beeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;writekey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'can be anything'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;service_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'todo-app'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'my-sls-app'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;transmission_impl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FileTransmission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s all we need to do to have events flow to Cloudwatch instead of the Honeycomb API. Note that you do not need to set a valid writekey when using the FileTransmission. The Publisher will have responsibility for authenticating API traffic.&lt;/p&gt;

&lt;p&gt;If you execute your app after deploying this, you should see span data in the Cloudwatch Logs for the Lambda function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"time"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2019-12-17T16:54:20.355317Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"samplerate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"dataset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-sls-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"service_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"todo-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"meta.beeline_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.11.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"duration_ms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;6.47&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also note the shorter Lambda run time, now that we aren’t blocking on an API call before exiting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REPORT RequestId: 30ff2be3-2c0b-4869-8da3-7af280dfc76c Duration: 9.41 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;Deploying the Publisher&lt;/h3&gt;

&lt;p&gt;The Publisher is another Lambda function, so if you are familiar with integrating third-party Lambda functions in your stack, you should use the tools and methods that work best for you. We provide a helpful, generic &lt;a href="https://github.com/honeycombio/agentless-integrations-for-aws#honeycomb-publisher-for-lambda"&gt;Cloudformation Template&lt;/a&gt; to walk you through installation of it and to document its AWS dependencies. Since we’re using Serverless in this tutorial, though, let’s see if we can make a it a “native” part of our project!&lt;/p&gt;

&lt;p&gt;Serverless allows you to describe ancillary AWS resources to spin up alongside your stack. In our case, we want to bolt on the publisher and its dependencies whenever we deploy our app. In the &lt;code&gt;serverless.yml&lt;/code&gt;, append the following to the &lt;code&gt;resources&lt;/code&gt; block of the sample app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;TodosDynamoDbTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# ...&lt;/span&gt;
    &lt;span class="na"&gt;PublisherLambdaHandler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AWS::Lambda::Function'&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;S3Bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;honeycomb-integrations-${opt:region, self:provider.region}&lt;/span&gt;
          &lt;span class="na"&gt;S3Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;agentless-integrations-for-aws/LATEST/ingest-handlers.zip&lt;/span&gt;
        &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lambda function for publishing asynchronous events from Lambda&lt;/span&gt;
        &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;HONEYCOMB_WRITE_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;YOURHONEYCOMBKEY'&lt;/span&gt;
            &lt;span class="na"&gt;DATASET&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-sls-app'&lt;/span&gt;
        &lt;span class="na"&gt;FunctionName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PublisherLambdaHandler-${self:service}-${opt:stage, self:provider.stage}&lt;/span&gt;
        &lt;span class="na"&gt;Handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;publisher&lt;/span&gt;
        &lt;span class="na"&gt;MemorySize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;128&lt;/span&gt;
        &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fn::GetAtt"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;LambdaIAMRole&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Arn&lt;/span&gt;
        &lt;span class="na"&gt;Runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;go1.x&lt;/span&gt;
        &lt;span class="na"&gt;Timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
    &lt;span class="na"&gt;ExecutePermission&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::Lambda::Permission"&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;lambda:InvokeFunction'&lt;/span&gt;
        &lt;span class="na"&gt;FunctionName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fn::GetAtt"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PublisherLambdaHandler&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Arn&lt;/span&gt;
        &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;logs.amazonaws.com'&lt;/span&gt;
    &lt;span class="na"&gt;LambdaIAMRole&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::IAM::Role"&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;AssumeRolePolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
          &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;
              &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lambda.amazonaws.com"&lt;/span&gt;
              &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sts:AssumeRole"&lt;/span&gt;
    &lt;span class="na"&gt;LambdaLogPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::IAM::Policy"&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;PolicyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lambda-create-log"&lt;/span&gt;
        &lt;span class="na"&gt;Roles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LambdaIAMRole&lt;/span&gt;
        &lt;span class="na"&gt;PolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
          &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
              &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;logs:CreateLogGroup&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;logs:CreateLogStream&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;logs:PutLogEvents&lt;/span&gt;
              &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;arn:aws:logs:*:*:*'&lt;/span&gt;
    &lt;span class="c1"&gt;# add one of me for each function in your app&lt;/span&gt;
    &lt;span class="na"&gt;CloudwatchSubscriptionFilterList&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::Logs::SubscriptionFilter"&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;DestinationArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fn::GetAtt"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PublisherLambdaHandler&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Arn&lt;/span&gt;
        &lt;span class="na"&gt;LogGroupName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/aws/lambda/${self:service}-${opt:stage, self:provider.stage}-list&lt;/span&gt;
        &lt;span class="na"&gt;FilterPattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
      &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ExecutePermission&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s a lot of boilerplate! The main things you’ll want to take note of is setting a valid value for &lt;code&gt;HONEYCOMB_WRITE_KEY&lt;/code&gt; and add &lt;code&gt;SubscriptionFilter&lt;/code&gt; resources for each function in your stack. Run &lt;code&gt;sls deploy&lt;/code&gt; one more time and you should now see a new function, &lt;code&gt;PublisherLambdaHandler-my-sls-app-dev&lt;/code&gt;, deployed alongside your Lambda functions. The Publisher will be subscribed to your app’s Cloudwatch Log Streams and will forward events to Honeycomb.&lt;/p&gt;

&lt;h2&gt;Leveling up with distributed tracing&lt;/h2&gt;

&lt;p&gt;Lambda functions don’t always run in a vacuum - often they are executed as part of a larger chain of events. You can link your Lambda instrumentation with your overall application instrumentation with distributed traces. To do this, you need to pass trace context from the calling app to your Lambda-backed service. Let’s look at a practical example by building on our existing app. We already have a todo API implemented in Lambda. Let’s assume we’re building a UI on top of that. We have some code that fetches the list of items from the API and then renders them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;beeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;traced&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"todo_list_view"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;todo_list_view&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;beeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"requests_get"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;todo_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;render_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todo_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;beeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;traced&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"render_list"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;render_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The HTTP request to fetch the list of todo items is done using the &lt;code&gt;requests&lt;/code&gt; lib. This &lt;code&gt;get&lt;/code&gt; call is wrapped in a trace span to measure the request time. We know that &lt;code&gt;list&lt;/code&gt; is instrumented with tracing, so it would be nice if we could link those spans to our trace!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;beeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;traced&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"todo_list_view"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;todo_list_view&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;beeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"requests_get"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;beeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_beeline&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;tracer_impl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;marshal_trace_context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;todo_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'https://mtd8iptz1m.execute-api.us-east-2.amazonaws.com/dev/todos'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                                &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'X-Honeycomb-Trace'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;render_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todo_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;marshal_trace_context&lt;/code&gt; builds a serialized trace context object, which can be passed to other applications via request header or payload. The Lambda middleware automatically looks for a header named &lt;code&gt;X-Honeycomb-Trace&lt;/code&gt; and extracts the context object, adopting the trace ID and caller’s span ID as its parent rather than starting an all-new trace. All we need to do is pass this context object as a request header before we call the &lt;code&gt;list&lt;/code&gt; endpoint. Adding the header is demonstrated manually here, but the beeline provides a patch for the requests lib that will do this for you. Simply import &lt;code&gt;beeline.patch.requests&lt;/code&gt; into your application after importing the &lt;code&gt;requests&lt;/code&gt; lib.&lt;/p&gt;

&lt;p&gt;When we call &lt;code&gt;todo_list_view&lt;/code&gt; in our UI app, we now see one trace with spans from both services:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6h_wrk8r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/01/example-trace2.png" class="article-body-image-wrapper"&gt;&lt;img class="alignnone size-full wp-image-5766" src="https://res.cloudinary.com/practicaldev/image/fetch/s--6h_wrk8r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/01/example-trace2.png" alt="screenshot of an individual trace in the honeycomb ui" width="792" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Go Serverless with confidence&lt;/h2&gt;

&lt;p&gt;Building and running apps with Lambda can be complex and is not without challenges, but with distributed tracing and rich instrumentation, there’s no need to fumble around in the dark.&lt;/p&gt;

&lt;p&gt;Ready to instrument your serverless apps? Get started with &lt;a href="https://ui.honeycomb.io/signup?&amp;amp;utm_source=Devto&amp;amp;utm_Devto=blog&amp;amp;utm_campaign=referral&amp;amp;utm_keyword=%7Bkeyword%7D&amp;amp;utm_content=instrumenting-lambda-with-traces-a-complete-example-in-python"&gt;Honeycomb for free&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>observability</category>
      <category>tracing</category>
      <category>aws</category>
    </item>
    <item>
      <title>Getting At The Good Stuff: How To Sample Traces in Honeycomb</title>
      <dc:creator>Irving Popovetsky</dc:creator>
      <pubDate>Wed, 30 Dec 2020 19:07:11 +0000</pubDate>
      <link>https://dev.to/honeycombio/getting-at-the-good-stuff-how-to-sample-traces-in-honeycomb-1ijm</link>
      <guid>https://dev.to/honeycombio/getting-at-the-good-stuff-how-to-sample-traces-in-honeycomb-1ijm</guid>
      <description>&lt;p&gt;Sampling is a must for applications at scale; it’s a technique for reducing the burden on your infrastructure and telemetry systems by only keeping data on a &lt;a href="https://en.wikipedia.org/wiki/Sample_(statistics)"&gt;statistical sample &lt;/a&gt;of requests rather than 100% of requests. Large systems may produce large volumes of similar requests which can be de-duplicated.&lt;/p&gt;

&lt;p&gt;This article is for developers and operators who have added &lt;a href="https://docs.honeycomb.io/getting-data-in/"&gt;Honeycomb instrumentation&lt;/a&gt; into their applications and wish to learn more about sampling as a technique for controlling costs and resource utilization while maximizing the value of your telemetry data. In this article, you’ll learn about the various sampling techniques and decision strategies as well as their benefits, drawbacks, and use-cases. Finally, there are some tips on where to look in case you’re running into trouble.&lt;/p&gt;

&lt;h2&gt;Instrumentation isn't free&lt;/h2&gt;

&lt;p&gt;&lt;b&gt;Instrumentation always has a cost.&lt;/b&gt; Sampling can reduce this cost but will not entirely eliminate it.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;There are, of course, costs associated with sending and storing the additional data (in Honeycomb or any platform).&lt;/li&gt;
    &lt;li&gt;There’s also an &lt;b&gt;infrastructure cost&lt;/b&gt; to capture instrumentation data, handle it, make decisions about what to do with it (like sampling) and transmit it somewhere.
&lt;ul&gt;
    &lt;li&gt;This cost is typically paid with an incremental amount of CPU usage, memory allocation and/or network bandwidth.&lt;/li&gt;
    &lt;li&gt;If your application and infrastructure are not CPU-bound or Network IO-bound, the impact on request latency is likely negligible.&lt;/li&gt;
&lt;/ul&gt;




&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b&gt;These costs vary by programming language.&lt;/b&gt; All instrumentation tooling vendors and projects work hard to minimize impact, typically by processing+sending data in different threads so as to not block applications while they serve requests. Latency may be more impacted in runtimes that were not designed for native parallelism (see: the &lt;a href="https://en.wikipedia.org/wiki/Global_interpreter_lock"&gt;GIL&lt;/a&gt; in Ruby and Python, NodeJS &lt;a href="https://nodejs.org/en/docs/guides/blocking-vs-non-blocking/#concurrency-and-throughput"&gt;is essentially single threaded&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Although you can't eliminate the overhead, &lt;strong&gt;you can move the overhead around in (and out) of your infrastructure&lt;/strong&gt;. For example, Honeycomb provides the &lt;a href="https://github.com/honeycombio/samproxy"&gt;samproxy&lt;/a&gt; (currently in alpha) which you can run in your infrastructure for the buffering and sending of traces or our new &lt;a href="https://docs.honeycomb.io/working-with-your-data/tracing/sampling/#honeycomb-refinery-at-ingestion-time"&gt;Refinery&lt;/a&gt; feature (currently in beta) for handling this on the collection side.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Sampling traces is trickier than sampling individual events.&lt;/b&gt; You want to avoid situations where traces aren’t completely collected (some spans thrown away) because this is frustrating for developers trying to debug their code. Not all event-sampling techniques will work since trace spans can be distributed among multiple threads, processes, or even servers and processed asynchronously. More on this below.&lt;/p&gt;

&lt;h2&gt;How sampling works&lt;/h2&gt;

&lt;p&gt;Honeycomb can decide which request traces or events to keep and which ones to drop in a number of different ways:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;
&lt;b&gt;Random sampling&lt;/b&gt; evaluates each event (whether it is a trace span or not) for sampling on a simple probabilistic basis - this means that each event has an equal chance of being selected, there is no further selection criteria other than the probability (for instance, 1 in 10). This is not good for tracing because it doesn’t guarantee you’ll get all the spans of a trace!&lt;/li&gt;
    &lt;li&gt;
&lt;b&gt;Deterministic sampling&lt;/b&gt; is a probabilistic technique that works by taking a hash of the trace ID and converting the first 4 bytes of the hash to a numeric value, for easy and fast decision-making based on a target sample rate. Consistent sampling is ensured for all spans in the trace because the trace ID is propagated to all child spans and the sampling decision is made the same way.&lt;/li&gt;
    &lt;li&gt;
&lt;b&gt;Target rate sampling&lt;/b&gt; delivers a given rate of collected telemetry (e.g. 500 collected spans per minute), decreasing the sample probability if there’s an increase in traffic, and increasing the sample probability if traffic drops off.&lt;/li&gt;
    &lt;li&gt;
&lt;b&gt;Rule-based sampling&lt;/b&gt; is a variant of deterministic sampling, but you can make your sampling decision based on properties of the request. Think of this as the data contained in the HTTP header: endpoint (URL), user-agent, or any arbitrary header value that you known will exist. This is cool because it allows you to fine-tune sampling rates based on your needs. For instance, keeping all write-path data but sampling the higher traffic read-path data.
&lt;ul&gt;
    &lt;li&gt;Rule-based sampling is compatible with both traces and events, however in the case of trace data that isn’t known at the start of the request it needs to consider the entire request including status codes which means it is only compatible with &lt;b&gt;tail-based sampling.&lt;/b&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;/li&gt;

    &lt;li&gt;
&lt;b&gt;Dynamic sampling&lt;/b&gt; combines rule-based and target rate sampling. It&lt;b&gt; &lt;/b&gt;delivers a given sample rate, weighting rare traffic and frequent traffic (for example by status code or endpoint) differently so as to end up with the correct average. Frequent traffic is sampled more heavily, while rarer events are kept or sampled at a lower rate. This is the strategy you want to use if you are concerned about keeping high-resolution data about unusual events while maintaining an a representative sample of your application’s behavior.&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;How sampling works for traces&lt;/h3&gt;

&lt;ul&gt;
    &lt;li&gt;
&lt;b&gt;Head-based sampling&lt;/b&gt; - a sampling decision is made when the root span is created - this is typically when the request is first seen by a tracing-aware service. At this point only metadata is known about the request (e.g. information in the HTTP header fields). The sampling decision is then propagated to child spans, typically with the addition of an HTTP header denoting the request is to be captured. This is most compatible with &lt;b&gt;Deterministic&lt;/b&gt; and &lt;b&gt;Rule-based&lt;/b&gt; sampling where the rules are the same on all services and the fields are known in advance.&lt;/li&gt;
    &lt;li&gt;
&lt;b&gt;Tail-based sampling&lt;/b&gt; is where the sampling decision is made upon the completion of the entire request and all of the spans have been collected. This is much more expensive than Head-based sampling because all trace spans must be collected, buffered and then processed for sampling decisions. This is best combined with &lt;b&gt;Dynamic sampling&lt;/b&gt; because all of the information is available to identify the “interesting” traces by type (including status code) and volume.
&lt;ul&gt;
    &lt;li&gt;We advise against performing dynamic tail-based sampling in your app (in-process) because it’s impossible to buffer downstream trace spans, and the overhead may adversely affect performance.&lt;/li&gt;
&lt;/ul&gt;




&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;&lt;b&gt;Troubleshooting your sampling implementation&lt;/b&gt;&lt;/h2&gt;

&lt;p&gt;&lt;b&gt;Seeing increased request latency?&lt;/b&gt;&lt;br&gt;
If your existing metrics systems have picked up a significant increase in request latency, it’s important to quantify and isolate the sources of the latency. Is the effect on latency different when the system is under periods of high load? If so, this is most likely a sign of infrastructure contention. Increasing the sampling rate (sending fewer traces) may help in some cases, as well as using feature flags to introduce finer granularity and control over sample rates.&lt;/p&gt;

&lt;p&gt;If the increase in request latency is visible even when the system is idle, this is very rare and might be an issue with the instrumentation itself or how it was integrated. Reach out to Honeycomb support and we can help.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Missing trace spans?&lt;/b&gt;&lt;br&gt;
If you’ve enabled sampling and see missing trace spans, there are several potential avenues of investigation:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;If you’ve customized your sampling logic, ensure you’re using a sampling decision that is compatible with your sampling technique. For example, don’t combine Head-based sampling with Random or Dynamic sampling techniques.&lt;/li&gt;
    &lt;li&gt;If trace spans are coming from different services, ensure that consistent sampling rules are being applied to all services and that there are no network issues preventing any services from sending events.&lt;/li&gt;
    &lt;li&gt;If you see the whole trace but it claims a missing root span, be sure you're not setting the &lt;code&gt;Parent ID&lt;/code&gt; field on the root span - its absence is what indicates the root span. (Note: this only applies to users of the libhoney SDK, the Honeycomb Beelines take care of this for you automatically.)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Want more information?&lt;/h2&gt;

&lt;p&gt;For more information on sampling, check out the following resources:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://docs.honeycomb.io/getting-data-in/"&gt;Getting data in (Honeycomb docs)&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://docs.honeycomb.io/working-with-your-data/tracing/sampling/"&gt;Sampling traces (Honeycomb docs)&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://www.honeycomb.io/blog/dynamic-sampling-by-example/"&gt;Dynamic Sampling by Example&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://www.honeycomb.io/wp-content/uploads/2019/05/the_new_rules_of_sampling_-_typeset_final.pdf"&gt;The New Rules of Sampling (whitepaper)&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/honeycombio/samproxy"&gt;Honeycomb samproxy (Github)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Need this kind of flexibility for your instrumentation and logs? Get started with &lt;a href="https://ui.honeycomb.io/signup?&amp;amp;utm_source=Devto&amp;amp;utm_Devto=blog&amp;amp;utm_campaign=referral&amp;amp;utm_keyword=%7Bkeyword%7D&amp;amp;utm_content=getting-at-the-good-stuff-how-to-sample-traces-in-honeycomb/"&gt;Honeycomb for free&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>tracing</category>
      <category>sampling</category>
      <category>observability</category>
      <category>devops</category>
    </item>
    <item>
      <title>They Aren’t Pillars, They’re Lenses</title>
      <dc:creator>Danyel Fisher</dc:creator>
      <pubDate>Tue, 22 Dec 2020 23:40:29 +0000</pubDate>
      <link>https://dev.to/honeycombio/they-aren-t-pillars-they-re-lenses-opf</link>
      <guid>https://dev.to/honeycombio/they-aren-t-pillars-they-re-lenses-opf</guid>
      <description>&lt;p&gt;To have Observability is to have the ability to understand your system’s internal state based on signals and externally-visible output. Honeycomb’s approach to Observability is to strive toward this: every feature of the product attempts to move closer to a unified vision of figuring out what your system did, and how it got there. Our approach is to let people smoothly move between aggregated views of their data, like heat-maps and line charts, into views that emphasize collections of events, like traces and BubbleUp, into views that emphasize single events, like raw data.&lt;/p&gt;

&lt;p&gt;In the broader marketplace, though, Observability is often promoted as “three pillars” — separating logging, monitoring, and tracing (aka logs, metrics &amp;amp; traces) as three distinct capabilities. We believe that separating these capabilities misses out on the true power of solving a problem with rich observability.&lt;/p&gt;

&lt;p&gt;The metaphor I like is to think of each feature as a lens on your data. Like a lens, they remove some wavelengths of information in exchange for emphasizing others. To debug in hi-res, you need to be able to see all the vivid colors.&lt;/p&gt;

&lt;p&gt;Let’s say, for example, that you’re tracking a service that seems to be acting up. An alert has gone off, saying that some users are having a poor experience. &lt;strong&gt;Monitoring tools &lt;/strong&gt;that track &lt;strong&gt;metrics&lt;/strong&gt;—the first pillar-- will interpret data as a time series of numbers and gauges — and that’s really important, because it’s useful to know such things as how long a process takes to launch or how long a web page takes to load. Using a metrics monitoring tool (e.g. Prometheus) will help generate that alert. If the monitoring tool supports &lt;a href="https://www.vividcortex.com/blog/what-is-cardinality-in-monitoring" rel="noopener noreferrer"&gt;high cardinality&lt;/a&gt; — the ability to track hundreds or thousands of different values — you can even find out which endpoints those users are encountering and, perhaps, some information about which users.&lt;/p&gt;

&lt;p&gt;You could think of that as a magnifying glass with a blue lens on your data. It comes out looking something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ta761hxs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/02/monet_blue.jpg" class="article-body-image-wrapper"&gt;&lt;img class=" wp-image-6003" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ta761hxs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/02/monet_blue.jpg" alt="" width="220" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second pillar is traces or &lt;a href="https://www.honeycomb.io/blog/get-deeper-insights-with-honeycomb-tracing/" rel="noopener noreferrer"&gt;tracing&lt;/a&gt;, which looks at individual calls and dives into how they are processed. From inside a tracing tool (e.g. Jaeger), you can do wonderful things — you can see which component took the longest or shortest, and you can see whether specific functions resulted in errors. In this case, for example, we might be able to use the information we found from the metrics to try to find a trace that hits the same endpoint. That trace might help us identify that the slow part of the trace was the call to the database, which is now taking much more time than before.&lt;/p&gt;

&lt;p&gt;(Of course, the process of getting from the metrics monitoring tool to the tracing tool is bumpy: the two types of tools collect different data. You need to find out how to correlate information in the metrics tool and the tracing tool. The process can be time-consuming and doesn’t always give you the accuracy you need. The fields might be called different things, and might use different encodings. Indeed, the key data might not be available in the two systems.)&lt;/p&gt;

&lt;p&gt;In our lens analogy, that’s a red lens. From this lens, the picture looks pretty different — but there’s enough in common that we can tell we’re looking at the same image. There are some parts that stand out and are much more visible; other aspects of detail entirely disappear.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9X5Vtuaz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/02/monet_red.jpg" class="article-body-image-wrapper"&gt;&lt;img class="wp-image-6004 " src="https://res.cloudinary.com/practicaldev/image/fetch/s--9X5Vtuaz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/02/monet_red.jpg" alt="" width="220" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But why did the database calls get slow? To continue debugging, you can look through logs, which is the third pillar. Maybe scrolling around in the logs, you might find some warnings issued by the database to show that it was overloaded at the time, or logs showing that the event queue had gotten long. That helps figure out what had happened to the database — but it’s a limited view. If we want to know how often this problem had arisen, we’d need to go back to the metrics to learn the history of the database queue.&lt;/p&gt;

&lt;p&gt;Like before, the process of switching tools, from tracing to logging, requires a new set of searches, a new set of interactions and of course more time.&lt;/p&gt;

&lt;p&gt;We could think of that as a green lens.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V5AuMaRW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/02/monet_green.jpg" class="article-body-image-wrapper"&gt;&lt;img class=" wp-image-6005" src="https://res.cloudinary.com/practicaldev/image/fetch/s--V5AuMaRW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/02/monet_green.jpg" alt="" width="220" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When companies sell the “three pillars of observability”, they lump all these visualizations together, but as &lt;em&gt;separate&lt;/em&gt; capabilities:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ta761hxs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/02/monet_blue.jpg" class="article-body-image-wrapper"&gt;&lt;img class="alignnone wp-image-6003" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ta761hxs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/02/monet_blue.jpg" alt="" width="220" height="265"&gt;&lt;/a&gt;    &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9X5Vtuaz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/02/monet_red.jpg" class="article-body-image-wrapper"&gt;&lt;img class="alignnone wp-image-6004" src="https://res.cloudinary.com/practicaldev/image/fetch/s--9X5Vtuaz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/02/monet_red.jpg" alt="" width="220" height="264"&gt;&lt;/a&gt;    &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V5AuMaRW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/02/monet_green.jpg" class="article-body-image-wrapper"&gt;&lt;img class="alignnone wp-image-6005" src="https://res.cloudinary.com/practicaldev/image/fetch/s--V5AuMaRW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/02/monet_green.jpg" alt="" width="220" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s not a bad start. Some things are completely invisible in one view, but easy to see in others, so placing them side by side can help alleviate those gaps. Each image brings different aspects more clearly into view: the blue image shows the outline of the flowers best; the red shows the detail in the florets; and the green seems to get the shading and depth best.&lt;/p&gt;

&lt;p&gt;But these three separate lenses have limitations. True observability is not just the ability to see each piece at a time; it’s also the ability to understand the whole and to see how the pieces combine to tell you the state of the underlying system.&lt;/p&gt;

&lt;p&gt;The truth is, of course, there aren’t three different systems interacting: there is one underlying system in all its richness. If we separate out these dimensions — if we collect metrics monitoring separately from log and traces — then we lose the fact that this data reflects the single underlying system.&lt;/p&gt;

&lt;p&gt;We need to collect and preserve that richness and dimensionality. We need to move through the data smoothly, precisely, and efficiently. We need to be able to discover where a trace has a phenomenon that may be occurring over and over in other traces, and to &lt;a href="https://docs.honeycomb.io/working-with-your-data/tracing/explore-trace-data/#returning-to-the-query-builder" rel="noopener noreferrer"&gt;find out where and how often&lt;/a&gt;. We need to break down a monitoring chart into its &lt;a href="https://docs.honeycomb.io/working-with-your-data/bubbleup/" rel="noopener noreferrer"&gt;underlying components&lt;/a&gt; to understand which factors really cause a spike.&lt;/p&gt;

&lt;p&gt;One way to implement this is to maintain a single set of telemetry collection and storage that keeps rich enough data that we can view it as metrics monitoring, tracing, or logging — or in some other perspective.&lt;/p&gt;

&lt;p&gt;Honeycomb’s event store acts a single source of truth for everything that has happened in your system. Monitoring, tracing, logging are simply different views of system events being stored — and it’s easy to switch quickly and easily between different views. Tracing isn’t a separate experience of the event store: it’s a different lens that brings certain aspects into sharper focus. Any point on a heat-map or a metric line-chart connects to a trace and any span on a trace can be turned into a query result.&lt;/p&gt;

&lt;p&gt;This single event store also enables Honeycomb to provide unique features such as BubbleUp. This is the ability to visually show a slice &lt;i&gt;across&lt;/i&gt; the data — in other words how two sets of events differ from each other, across all their various dimensions (fields). That’s the sort of question that metrics systems simply cannot show (because they don’t store the individual events), and let’s face it that would be exhausting in a dedicated log system.&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
What do you do when you have separate pieces of the complete picture? You need to manually connect the parts and make the connections, looking for correlates. In our lens analogy, that might be like seeing that an area shows as light colored in both the green and the red lens, so it must be yellow.&lt;/p&gt;

&lt;p&gt;You COULD do that math yourself. Flip back and forth. Stare at where bits contrast.&lt;/p&gt;

&lt;p&gt;Or, you could use a tool where seeing the image isn’t a matter of skill or experience of combining those pieces in your head: it’s all laid out, so you can see it as one complete beautiful picture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OWEBxB99--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/02/MON1478-1000x1000-1.jpg" class="article-body-image-wrapper"&gt;&lt;img class="wp-image-6006 alignleft" src="https://res.cloudinary.com/practicaldev/image/fetch/s--OWEBxB99--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/02/MON1478-1000x1000-1.jpg" alt="" width="220" height="264"&gt;&lt;/a&gt;&lt;i&gt;&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Claude Monet, &lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;i&gt;“&lt;a href="https://www.metmuseum.org/art/collection/search/437112" rel="noopener noreferrer"&gt;Bouquet of Sunflowers&lt;/a&gt;,” 1881&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;Join the swarm. Get started with &lt;a href="https://ui.honeycomb.io/signup?&amp;amp;utm_source=Devto&amp;amp;utm_Devto=blog&amp;amp;utm_campaign=referral&amp;amp;utm_keyword=%7Bkeyword%7D&amp;amp;utm_content=they-arent-pillars-theyre-lenses"&gt;Honeycomb for free&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>observability</category>
      <category>logging</category>
      <category>monitoring</category>
      <category>tracing</category>
    </item>
    <item>
      <title>The Future of Software is a Sociotechnical Problem</title>
      <dc:creator>Charity Majors</dc:creator>
      <pubDate>Fri, 18 Dec 2020 21:19:14 +0000</pubDate>
      <link>https://dev.to/honeycombio/the-future-of-software-is-a-sociotechnical-problem-10m0</link>
      <guid>https://dev.to/honeycombio/the-future-of-software-is-a-sociotechnical-problem-10m0</guid>
      <description>&lt;p&gt;&lt;a href="https://www.interaction-design.org/literature/topics/socio-technical-systems" rel="noopener noreferrer"&gt;"Sociotechnical"&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I learned this word from &lt;a href="https://twitter.com/lizthegrey" rel="noopener noreferrer"&gt;Liz Fong-Jones&lt;/a&gt; recently, and it immediately entered my daily lexicon. You know exactly what it means as soon as you hear it, and then you wonder how you ever lived without it.&lt;/p&gt;

&lt;p&gt;Our systems are sociotechnical systems. This is why technical problems are never just technical problems, and why social problems are never just social problems.&lt;/p&gt;

&lt;p&gt;I work on a company, Honeycomb, which develops next-gen &lt;a href="https://thenewstack.io/observability-a-3-year-retrospective/" rel="noopener noreferrer"&gt;observability&lt;/a&gt; tooling. But I don't spend my time trying to figure out how to get more people to use observability tools. Observability alone can't solve anything, it's just a necessary part of the solution.&lt;/p&gt;

&lt;p&gt;What I do spend my day thinking about is the future of building software. How can we convert the creative fuel of people’s labor into healthier teams and more reliable, resilient systems? We are incredibly wasteful of the creative fuel that people pour into the process, and the result is that we have unreliable, opaque systems hairballs that nobody understands — which are then operated by stressed, burned out humans who are afraid to touch them.&lt;/p&gt;

&lt;p&gt;What if we had:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;a future where your code goes live a few seconds or minutes after you commit your changes, and this is all very predictable and boring&lt;/li&gt;
    &lt;li&gt;a future where everyone owns their code in production, and you actually look forward to your own turn on call&lt;/li&gt;
    &lt;li&gt;a future where all the energy you pour into writing code and building systems genuinely moves the business forward, and you are rarely frustrated or lost or misled by those systems&lt;/li&gt;
    &lt;li&gt;a future where the debugger of last resort is not the engineer who has been there the longest, but the most curious person&lt;/li&gt;
    &lt;li&gt;a future where shipping software is not scary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What do you think, does this sound achievable? Easy? Or are you thinking “never gonna happen for my team in this lifetime?”&lt;/p&gt;

&lt;p&gt;This is all much more attainable than you might think.&lt;/p&gt;

&lt;h3&gt;The future is here, it is just unevenly distributed.&lt;/h3&gt;

&lt;p&gt;I have lived in the future. It's why I started this company — I got a brief glimpse of what I now think of as ODD, or observability-driven development, a world where the best engineers wrote code with half their screen taken up by their editor, half by a tool where they were constantly watching and poking at and playing with that code live in production. The code they wrote was better. The systems they built were understandable, in a way I had never seen before.&lt;/p&gt;

&lt;p&gt;Going back to a world where people write and ship blind was unthinkable. Not an option.&lt;/p&gt;

&lt;p&gt;We hear echoes of this from Honeycomb customers now: "This is incredible. I can never go back.“ &lt;/p&gt;

&lt;p&gt;Because the teams who invest in these sociotechnical practices are radically more productive and happy than those who don't. They move so much faster and with more confidence; their systems are more reliable and better understood; they amass dramatically less technical debt and can do far more with radically fewer people. They attract and retain better candidates.&lt;/p&gt;

&lt;p&gt;And as a software company, this is how you win.&lt;/p&gt;

&lt;h3&gt;We are in the Middle Ages of software delivery.&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://stripe.com/reports/developer-coefficient-2018" rel="noopener noreferrer"&gt;Stripe developer report&lt;/a&gt; reports that engineers spend at least 40% (self-reported) on miscellaneous technical bullshit that keeps you busy, maybe blocks you from working on what you need to work on ... but does not move the business forward. Just sit with that a sec. Forty percent. Optimistically.&lt;/p&gt;

&lt;p&gt;Or maybe you're familiar with the &lt;a href="https://cloud.google.com/blog/products/devops-sre/the-2019-accelerate-state-of-devops-elite-performance-productivity-and-scaling" rel="noopener noreferrer"&gt;DORA report&lt;/a&gt;. The honeycomb team’s engineering stats are an order of magnitude or two better than their Elite teams, which represent the top 20% of all teams. ("But the company is young, easy for you to say!" you may protest. Sure, we are relatively young ... a little over four years old. We are also a fast-growing platform with unpredictable, spiky traffic composed of user-generated streams of content that we have no control over.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2n75lbmxpposh7s6qh7a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2n75lbmxpposh7s6qh7a.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wish I could tell you "just buy Honeycomb and voila! Get high-performing teams!“&lt;/p&gt;

&lt;p&gt;That is not what I'm saying. &lt;b&gt;It is not that easy.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;It's a sociotechnical hole, and only a combination of technical fixes and social change will get us out of it.&lt;/p&gt;

&lt;h3&gt;A sociotechnical recipe for high-performing teams&lt;/h3&gt;

&lt;p&gt;But lots of smart, creative teams are out there working hard on this and sharing their findings. As a result, we know a LOT more about what contributes to a solution than we knew even just a year or two ago. You will be forgiven for skimming this very long list:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;Blameless retrospectives&lt;/li&gt;
    &lt;li&gt;Automatic deployments triggered on each commit, single commit per deploy&lt;/li&gt;
    &lt;li&gt;Removing human gates in the deploy pipeline&lt;/li&gt;
    &lt;li&gt;Good test coverage, instrumented test harness&lt;/li&gt;
    &lt;li&gt;Shared conventions around instrumentation&lt;/li&gt;
    &lt;li&gt;Training, education, collaboration&lt;/li&gt;
    &lt;li&gt;Code reviews and mentoring&lt;/li&gt;
    &lt;li&gt;Promoting people for their value as team members and force multipliers, not just raw coding ability&lt;/li&gt;
    &lt;li&gt;Interview processes that value strengths, not lack of weaknesses&lt;/li&gt;
    &lt;li&gt;Shared value systems and organizational transparency&lt;/li&gt;
    &lt;li&gt;Welcoming of diverse viewpoints and fresh eyes&lt;/li&gt;
    &lt;li&gt;Teams that value juniors and know how to train them up&lt;/li&gt;
    &lt;li&gt;Tooling that rewards curiosity&lt;/li&gt;
    &lt;li&gt;Job ladders that value communication and independent initiative&lt;/li&gt;
    &lt;li&gt;Encouraging software engineers to own their code from end to end&lt;/li&gt;
    &lt;li&gt;Encouraging SRE types to work more like product teams&lt;/li&gt;
    &lt;li&gt;Adopting SLOs, SLIs, and aligning on call pain strictly with user pain&lt;/li&gt;
    &lt;li&gt;Making sure everyone gets enough sleep and time off&lt;/li&gt;
    &lt;li&gt;Observability tooling (in the technical sense, &lt;a href="https://www.honeycomb.io/blog/so-you-want-to-build-an-observability-tool/" rel="noopener noreferrer"&gt;as I define it here&lt;/a&gt;; not in the old fashioned sense of "metrics, logs and traces")&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://thenewstack.io/observability-a-3-year-retrospective/" rel="noopener noreferrer"&gt;Observability&lt;/a&gt; is only a one piece of the solution ... but it is a necessary piece that should be actively frontloaded if your efforts are to have maximum impact.&lt;/p&gt;

&lt;h3&gt;Observability is about the unknown-unknowns&lt;/h3&gt;

&lt;p&gt;Rolling out o11y tooling is like turning on the light and putting on your glasses before you start swinging at the pinata.&lt;/p&gt;

&lt;p&gt;To get at the candy inside — the real actionable user and technical insights — you need to be able to interactively slice and dice in real time, break down by high cardinality dimensions, and ask those new questions, the ones that you couldn’t have predicted you would need to ask. This is the minimum viable technical functionality you need in order to explore exactly what is happening in production, what happened when you deployed a particular piece of code, what happened when that user reported that bug. That’s why previous iterations of monitoring were not enough.&lt;/p&gt;

&lt;p&gt;Observability in the modern technical definition is about answering the unknown-unknowns, and it is necessary. With observability, all things become easier. It is a force amplifier for all your other efforts.&lt;/p&gt;

&lt;p&gt;If you don't have observability -- if you only have metrics, logs, and/or traces -- all you can ask will be those questions that you predicted and defined in advance. You are swinging out at the pinata in the dark, or where you think it was yesterday or last week. It might not be completely prohibitively impossible, but it's a damn sight harder and a lot comes down to luck.&lt;/p&gt;

&lt;h3&gt;
&lt;a href="https://thenewstack.io/observability-a-3-year-retrospective/" rel="noopener noreferrer"&gt;Observability is a necessary ingredient&lt;/a&gt;. But everything matters.&lt;/h3&gt;

&lt;p&gt;People often kvetch at me "yeah, but anything's easy when you have the best engineers." They have this exactly backwards. &lt;b&gt;Observability-driven development is what makes great engineers&lt;/b&gt;. Observability is what enables you to peek under the hood of the abstractions, it grounds you in reality, forces you to think through the code all the way to how the user will use it. It tethers you to your users and lets you see the world through their eyes.&lt;/p&gt;

&lt;h3&gt;TDD → ODD&lt;/h3&gt;

&lt;p&gt;Learning to check your assumptions vs reality was the argument for TDD (test-driven development). That makes you write better code, indisputably. But tests stop at the edge of your laptop! Tests imperfectly mock a predictable subset of reality. Testing in production means replacing the artificial test sandbox with reality.&lt;/p&gt;

&lt;p&gt;If you believe TDD makes you a better developer, you should be hungry for the developer you will become using ODD.&lt;/p&gt;

&lt;p&gt;I am cautiously optimistic that the industry will embrace observability in far less time than it took to adopt TDD and metrics. Mostly because it is much, much easier to do things this way. It’s actually much harder to do things the bad old ways, what with all the hacks and workarounds.&lt;/p&gt;

&lt;p&gt;And every little bit helps. Every one of these changes will, if you embrace them, make your people happier and more productive.&lt;/p&gt;

&lt;h3&gt;Observability-driven development is what creates great software engineers.&lt;/h3&gt;

&lt;p&gt;The greatest obstacle between us and a better tomorrow is this pervasive lack of hope. (The second greatest is our perverse pride in our Rube Goldberg hacks &amp;amp; sunk costs fallacy.)&lt;/p&gt;

&lt;p&gt;Most people still have not experienced what it's like to build software in a radically better way. Even worse, most people don't see themselves in the better world I describe. They don't think this world is meant for them.&lt;/p&gt;

&lt;p&gt;I don’t know how to fix this yet. But if we only succeed in making life better for the elites, we will have failed.&lt;/p&gt;

&lt;p&gt;Observability is for everyone, and it is easier if you do it first. Observability makes every technical effort that comes after it sooooo much easier to achieve. Observability is what creates great engineers, not vice versa. Start at the edge, instrument some code, and work in. Rinse and repeat. You got this.&lt;/p&gt;

&lt;p&gt;Experience what Honeycomb can do for your business. Check out &lt;a href="https://www.honeycomb.io/get-a-demo?&amp;amp;utm_source=Devto&amp;amp;utm_Devto=blog&amp;amp;utm_campaign=referral&amp;amp;utm_keyword=%7Bkeyword%7D&amp;amp;utm_content=the-future-of-software-is-a-sociotechnical-problem" rel="noopener noreferrer"&gt;our short and sweet demo&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>observability</category>
      <category>debugging</category>
      <category>instrumentation</category>
      <category>devops</category>
    </item>
    <item>
      <title>Making Instrumentation Extensible</title>
      <dc:creator>Liz Fong-Jones</dc:creator>
      <pubDate>Wed, 09 Dec 2020 20:06:08 +0000</pubDate>
      <link>https://dev.to/honeycombio/making-instrumentation-extensible-4ejf</link>
      <guid>https://dev.to/honeycombio/making-instrumentation-extensible-4ejf</guid>
      <description>&lt;p&gt;&lt;span&gt;Observability-driven development requires both rich query capabilities and sufficient instrumentation in order to capture the nuances of developers' intention and useful dimensions of cardinality. When our systems are running in containers, we need an equivalent to our local debugging tools that is as easy to use as Printf and as powerful as gdb. We should empower developers to write instrumentation by ensuring that it's easy to add context to our data, and requires little maintenance work to add or replace telemetry providers after the fact. Instead of thinking about individual counters or log lines in isolation, we need to consider how the telemetry we might want to transmit fits into a wider whole.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bEglRhaj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2019/06/bee-extension-350x250.jpg" class="article-body-image-wrapper"&gt;&lt;img class="aligncenter wp-image-4809 size-medium" src="https://res.cloudinary.com/practicaldev/image/fetch/s--bEglRhaj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2019/06/bee-extension-350x250.jpg" alt="photo of a chain of bees connecting two parts of a hive" width="300" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Aggregated counters, gauges, and histograms can provide us with information broken down by host or endpoint, but not necessarily higher cardinality fields that we need for a rich understanding of our distributed systems. Automatic instrumentation of a language server framework, such as framework support for Node.js Express or Go http.Server in &lt;a href="https://www.honeycomb.io/auto-instrumentations/"&gt;Honeycomb's Beelines&lt;/a&gt;, can only provide a modest amount of context. It will capture request header fields such as URL and response durations/error codes, but not anything from the business logic or involving the logged-in user's metadata. Because observability requires the ability to understand the impact of user behavior upon our applications, we cannot just stop with collecting surface level data. Thus, we'll need to make changes to our code to instrument it.&lt;/span&gt;&lt;/p&gt;

&lt;h2&gt;Instrumentation should be reusable&lt;/h2&gt;

&lt;p&gt;&lt;span&gt;Typically, instrumenting code involves adding a vendor's library or a standard package like OpenCensus or slf4j to one's dependencies, then calling the library directly from instrumented code. If multiple providers and kinds of telemetry (e.g. logs, metrics, traces, events…) are in use, calls to each wind up sprinkled across the codebase. But should we have to re-instrument our entire codebase every time we gain access to new methods of data aggregation/visualization or change observability providers? Of course not. This gives rise to the need to separate observability plumbing from your business logic, or domain-specific code.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;To address this problem of abstracting instrumentation, Tyler Treat envisions a solution involving centralized inter-process collection in "&lt;/span&gt;&lt;a href="https://bravenewgeek.com/the-observability-pipeline/"&gt;&lt;span&gt;The Observability Pipeline&lt;/span&gt;&lt;/a&gt;&lt;span&gt;", and Pete Hodgson suggests abstracting collection in-process in "&lt;/span&gt;&lt;a href="https://martinfowler.com/articles/domain-oriented-observability.html"&gt;&lt;span&gt;Domain Oriented Observability&lt;/span&gt;&lt;/a&gt;&lt;span&gt;". Tyler's article explains creating structured events, and then streaming them to an out of process service that can aggregate them and send them onwards to a variety of instrumentation sinks. Pete's article suggests creating a separate class for handling the vendor-specific pieces of instrumentation, but still relies upon tight coupling between the instrumentation code and the domain-specific code--e.g. creating a method in the instrumentation code to handle each potential property we might want to record about an event (e.g. &lt;code&gt;discountCodeApplied()&lt;/code&gt;, &lt;code&gt;discountLookup{Failed,Succeeded}()&lt;/code&gt;).&lt;/span&gt;&lt;/p&gt;

&lt;h2&gt;Why not both?&lt;/h2&gt;

&lt;p&gt;&lt;span&gt;However, there's a simpler, within-process approach that is easier for developers to understand, test, configure, maintain, and operate. It's a fusion of that described by Pete in "Event-Based Observability" and "Collecting Instrumentation Context", and by Tyler's distributed event buffering solution. With the improved solution, we neither need to have an advanced understanding of mocking functions and classes, nor do we need to operate a Kafka pipeline from day 0. Instead, we just generate and consume &lt;a href="https://www.honeycomb.io/blog/how-are-structured-logs-different-from-events/"&gt;structured events&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0QahCs55--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2019/06/bee-chain-350x250.jpg" class="article-body-image-wrapper"&gt;&lt;img class="aligncenter wp-image-4811 size-medium" src="https://res.cloudinary.com/practicaldev/image/fetch/s--0QahCs55--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2019/06/bee-chain-350x250.jpg" alt="photo of a vertical chain of bees constructing a hive" width="300" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Within each span of work done in the domain-specific business logic, we populate a weakly-typed context dictionary with key/value pairs added from within instrumented code, as well as the default standard contextual fields (e.g. requestId, startTime, endTime, etc). Child units of work become separate contexts and spans, with appropriate fields (e.g. parentId, requestId) templated (or "partially applied" in Pete's words) from the parent context/span. Adding telemetry becomes as easy as Printf for developers -- it's just setting a &lt;code&gt;ctx[key] = val&lt;/code&gt; only for keys and values relevant to your code. We no longer need to create one function call to the instrumentation adapter for each telemetry action. Using Pete's example, we might set &lt;code&gt;discountCode =&amp;gt; FREESHIPPING&lt;/code&gt;, &lt;code&gt;responseCode =&amp;gt; 403&lt;/code&gt;, or &lt;code&gt;discountLookupSucceeded =&amp;gt; {true,false,nil}&lt;/code&gt; within &lt;/span&gt;&lt;i&gt;&lt;span&gt;one&lt;/span&gt;&lt;/i&gt;&lt;span&gt; event instead of making the multiple function calls above, or emitting multiple distinct "Announcement" objects for only one work unit. Writing tests to validate that the generated context map is correct becomes straightforward to do in table-based testsuites (e.g. &lt;code&gt;go functest&lt;/code&gt;), rather than requiring mocking functions and classes.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Once the work unit finishes, its context dictionary is sent in-process to the instrumentation adapter where any number of listeners can interpret it. Each listener sees the context maps for each received event, decides whether it's relevant to it, and if so, translates it according to its own rules into metrics, traces/events/structured logs, or human-readable logs. We no longer need to duplicate calls to the same instrumentation provider from each kind of telemetry function call, but can create single listeners for each common metric (e.g. response time metrics collection, response code) that act on a wider range of events. We can then measure the correctness of listeners, ensuring that each processor is only interested in the correct set of structured events, and dispatches them to the upstream structured event, log, metric, or trace provider(s)' APIs appropriately.&lt;/span&gt;&lt;/p&gt;

&lt;h2&gt;Correspondence is more useful when it's about the outcome&lt;/h2&gt;

&lt;p&gt;&lt;span&gt;Unlike Tyler's streaming design there need not be a 1:1 correspondence between listeners/routers and instrumentation sinks. Instead, the correspondence is between the action we'd like to coalesce or report on, and what related calls we make -- e.g. performing more than one metric counter increment, etc. to the same sink, or even scattering increments across many different sinks if we're transitioning between providers. This makes the code much more testable, as it's focused on the intent of "record these values from this specific kind of event, to whatever Sinks are relevant", rather than a catch-all of "duplicate everything in the kitchen we do in Sink A in Sink B instead". And the value of event stores such as Honeycomb quickly becomes clearer -- because you don't &lt;/span&gt;&lt;i&gt;&lt;span&gt;have&lt;/span&gt;&lt;/i&gt;&lt;span&gt; to do anything different to aggregate or process each such structured event, only pass it on to us directly. Let us worry about how to efficiently query the data when you ask a question, such as &lt;code&gt;P99(duration_ms)&lt;/code&gt; or &lt;code&gt;COUNT WHERE err exists GROUP BY customer_id ORDER BY COUNT desc&lt;/code&gt;.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Decoupling event creation from event consumption, even within the same process, is a great step between instrumentation spaghetti and needing a Kafka, Kinesis or PubSub queue. Never create a distributed system unless you need to, and run as few distributed systems as possible. Same-process structured event creation and structured event consumption is super easy to work with, test, and reason about, to boot! As you grow and your needs scale, you may wind up reaching for that Kafka queue. But you'll have an easier migration path, if so.&lt;/span&gt;&lt;/p&gt;

&lt;h2&gt;Ideas for future-proofing&lt;/h2&gt;

&lt;p&gt;&lt;span&gt;How does this relate to OpenTelemetry née Open{Census,Tracing}? Despite the creation of the new consensus standard, the ongoing transition to OpenTelemetry is proof indeed that we ought to future-proof our work by ensuring we can switch to and from instrumentation providers, including those that do not support the current newest standard, without further breaking domain code. Instead of using the OpenTelemetry API directly within your domain-specific code, it still may be wise to use one context/span propagation library of your choice (which could still be OTel's), and write an InstrumentationAdapter that passes data it receives through to OpenTelemetry's metrics &amp;amp; trace consumers, as well as to legacy and future instrumentation providers.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;I hope that this article was helpful! If you're looking for more detailed examples of how Honeycomb Beelines work, check out our &lt;a href="https://github.com/honeycombio/examples"&gt;Examples repo in Github &lt;/a&gt;, such as &lt;a href="https://github.com/honeycombio/examples"&gt;this&lt;/a&gt; &lt;a href="https://github.com/honeycombio/examples/blob/master/golang-gatekeeper"&gt;example of using our Beeline for Go alongside custom instrumentation&lt;/a&gt;. &lt;/span&gt;&lt;/p&gt;




&lt;p&gt;Looking to find out more? Get started with &lt;a href="https://ui.honeycomb.io/signup?&amp;amp;utm_source=Devto&amp;amp;utm_Devto=blog&amp;amp;utm_campaign=referral&amp;amp;utm_keyword=%7Bkeyword%7D&amp;amp;utm_content=making-instrumentation-extensible"&gt;Honeycomb for free&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>instrumentation</category>
      <category>observability</category>
      <category>sre</category>
      <category>devops</category>
    </item>
    <item>
      <title>Challenges with Implementing SLOs</title>
      <dc:creator>Danyel Fisher</dc:creator>
      <pubDate>Mon, 07 Dec 2020 20:44:21 +0000</pubDate>
      <link>https://dev.to/honeycombio/challenges-with-implementing-slos-1kp</link>
      <guid>https://dev.to/honeycombio/challenges-with-implementing-slos-1kp</guid>
      <description>&lt;p&gt;A few months ago, Honeycomb released our SLO — Service Level Objective — feature to the world. We’ve written before about &lt;a href="https://www.honeycomb.io/slo/" rel="noopener noreferrer"&gt;how to use it&lt;/a&gt; and some of the use scenarios. Today, I’d like to say a little more about how the feature has evolved, and what we did in the process of creating it. (Some of these notes are based on my talk, “Pitfalls in Measuring SLOs;” you can find the slides to that talk &lt;a href="https://www.honeycomb.io/talks/" rel="noopener noreferrer"&gt;here&lt;/a&gt;, or view the video on our &lt;a href="https://www.honeycomb.io/talks/" rel="noopener noreferrer"&gt;Honeycomb Talks page)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Honeycomb approaches SLOs a little differently than some of the market does, and it’s interesting to step back and see how we made our decisions.&lt;/p&gt;

&lt;p&gt;If you aren’t familiar with our SLO feature, I’d encourage you to check out the &lt;a href="https://www.honeycomb.io/production-slos/" rel="noopener noreferrer"&gt;SLO webcast&lt;/a&gt; and our &lt;a href="https://www.honeycomb.io/slo/" rel="noopener noreferrer"&gt;other documentation&lt;/a&gt;. The shortest summary, though, is that an SLO is a way of expressing &lt;i&gt;how reliable&lt;/i&gt; a service is. An SLO comes in two parts: a metric (or indicator) that can measure the &lt;i&gt;quality&lt;/i&gt; of a service, and an expectation of &lt;i&gt;how often&lt;/i&gt; the service meets that metric.&lt;/p&gt;

&lt;p&gt;When &lt;a href="https://twitter.com/lizthegrey" rel="noopener noreferrer"&gt;Liz Fong-Jones&lt;/a&gt; joined Honeycomb, she came carrying the banner of SLOs. She’d had a lot of experience with them as an SRE at Google, and wanted us to support SLOs, too. Honeycomb had an interesting secret weapon, though: the fact that Honeycomb stores rich, wide events [REF] means that we can do things with SLOs that otherwise aren’t possible.&lt;/p&gt;

&lt;p&gt;The core concept of SLOs is outlined in the &lt;a href="https://landing.google.com/sre/books/" rel="noopener noreferrer"&gt;Google SRE book and workbook&lt;/a&gt;, and in Alex Hidalgo’s upcoming &lt;a href="http://shop.oreilly.com/product/0636920337867.do" rel="noopener noreferrer"&gt;Implementing Service Level Objectives&lt;/a&gt; book. In the process of implementing SLOs, though, we found that there were a number of issues that aren’t well-articulated in the Google texts; I’d like to spend a little time analyzing what we learned.&lt;/p&gt;

&lt;p&gt;I’ve put this post together because it might be fun to take a look behind the scenes — at what it takes to roll out this feature; at some of the dead ends and mistakes we made; and how we managed to spend $10,000 of AWS on one particularly embarrassing day.&lt;/p&gt;

&lt;p&gt;As background, I’m trained as a human-computer interaction researcher. That means I design against user needs, and build based on challenges that users are encountering. My toolbox includes a lot of prototyping, interviewing, and collecting early internal feedback. Fortunately, Honeycomb has a large and supportive user community — the “Pollinators” — who love to help each other, and give vocal and frequent feedback.&lt;/p&gt;

&lt;h3&gt;Expressing SLOs&lt;/h3&gt;

&lt;p&gt;In Honeycomb, you can express static &lt;a href="https://docs.honeycomb.io/working-with-your-data/triggers/" rel="noopener noreferrer"&gt;triggers&lt;/a&gt; pretty easily: simply set an aggregate operation (like COUNT or AVERAGE) and a filter. The whole experience re-uses our familiar query builder.&lt;/p&gt;

&lt;p&gt;We tried to go down the same path with SLOs. Unfortunately, it required an extra filter and — when we rolled it out with paper prototypes — more settings and screens than we really wanted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X6mYhQZV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mly8h2l60nd32xe8getp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X6mYhQZV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mly8h2l60nd32xe8getp.png" alt="for post"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We decided to reduce our goals, at least in the short term. Users would create SLOs far fewer times than they would view and monitor their SLOs; our effort should be spent on the monitoring experience. Many of our users who were starting out with SLOs would be more advanced users; because SLOs are aimed at enterprise users, we could help ensure our customer success team was ready to help users create them.&lt;/p&gt;

&lt;p&gt;In the end, we realized, an SLO was just three things: an &lt;a href="https://landing.google.com/sre/sre-book/chapters/service-level-objectives/" rel="noopener noreferrer"&gt;SLI (“Service Level Indicator”)&lt;/a&gt;, a time period, and a percentage. "Was the SLI fulfilled 99% of the time over the last 28 days?" An SLI, in turn, is a function that returns TRUE, FALSE, or N/A for every event. This turns out to be very easy to express in Honeycomb &lt;a href="https://docs.honeycomb.io/working-with-your-data/customizing-your-query/derived-columns/" rel="noopener noreferrer"&gt;Derived Columns&lt;/a&gt;. Indeed, it meant we could even create an &lt;a href="https://docs.honeycomb.io/working-with-your-data/slos/cookbook/" rel="noopener noreferrer"&gt;SLI Cookbook&lt;/a&gt; that helped express some common patterns.&lt;/p&gt;

&lt;p&gt;We might revisit this decision at some point in the future — it would be nice to make the experience friendlier as we’re beginning to learn more about how users want to use them. But it was also useful to realize that we could allow that piece of the experience to be less well-designed.&lt;/p&gt;

&lt;h3&gt;Tracking SLOs&lt;/h3&gt;

&lt;p&gt;Our goal in putting together the main SLO display was to let users see where the burndown was happening, explain why it was happening, and remediate any problems they detected.&lt;/p&gt;

&lt;p&gt;This screenshot gives a sense of the SLO screen. At the top-left, the “remaining budget” shows how the current SLO has been burned down over 30 days. Note that the current budget has 46.7% remaining. We can also see that the budget has been gradually burning slowly and steadily.&lt;/p&gt;

&lt;p&gt;The top-right view shows our overall compliance: for each day of the last 30, what did the previous 30 look like? We’re gradually getting better.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bWMKKWKy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/03/image-12.png" class="article-body-image-wrapper"&gt;&lt;img class=" wp-image-6166 aligncenter" src="https://res.cloudinary.com/practicaldev/image/fetch/s--bWMKKWKy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/03/image-12.png" alt="" width="720" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Contrast this view: we’ve burned almost three times our budget (-176% means we burned the first 100%, and then &lt;i&gt;another&lt;/i&gt; 1.76 of it).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vhhRJBcn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/03/image-11.png" class="article-body-image-wrapper"&gt;&lt;img class=" wp-image-6165 aligncenter" src="https://res.cloudinary.com/practicaldev/image/fetch/s--vhhRJBcn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/03/image-11.png" alt="" width="721" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A lot of that was due to a crash a few weeks ago — but, to be honest, our steady state of burning was probably lower than it wanted to be. Indeed, we’ve &lt;i&gt;never&lt;/i&gt; exceeded our goal of 99.5% at &lt;i&gt;any time&lt;/i&gt; in the last 30 days.&lt;/p&gt;

&lt;h3&gt;Explaining the Burn&lt;/h3&gt;

&lt;p&gt;The top parts of the screen are familiar and occur in many tools. The bottom part of the chart is, to me, more interesting, as they take advantage of the unique aspects that Honeycomb has to offer. Honeycomb is all about the &lt;b&gt;high-cardinality, high-dimensional&lt;/b&gt; data. We love it when users send us rich, complex events: it lets us give them tools to provide rich comparisons between events.&lt;/p&gt;

&lt;p&gt;The chart on this page shows a heatmap. Like other Honeycomb heatmaps, it shows the number of events with various durations (Y axis) by time (X Axis). This time, though, it adds yellow events that failed the SLI. This image shows that the yellow failed events are largely ones that are a little slower than we might expect; but a few are being processed quickly and failing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pC-h8zIK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/03/image-5.png" class="article-body-image-wrapper"&gt;&lt;img class="size-full wp-image-6158 aligncenter" src="https://res.cloudinary.com/practicaldev/image/fetch/s--pC-h8zIK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/03/image-5.png" alt="" width="616" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Contrast this image, which shows that most of the failed events happened in a single burst of time. (The time axis on the bottom chart looks only at one day, and is currently set on one of the big crash days).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QJXFM98N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/03/image-6.png" class="article-body-image-wrapper"&gt;&lt;img class="size-full wp-image-6159 aligncenter" src="https://res.cloudinary.com/practicaldev/image/fetch/s--QJXFM98N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/03/image-6.png" alt="" width="613" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last, we can use Honeycomb’s &lt;a href="https://docs.honeycomb.io/working-with-your-data/bubbleup/" rel="noopener noreferrer"&gt;BubbleUp&lt;/a&gt; capability to contrast events that succeeded to those that failed — across every dimension that is in the dataset! For example, in this chart, we see (in the top left) that failing events had status codes of 400 and 500, while succeeding events had status codes of 200.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lZjgOEIM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/03/image-7.png" class="article-body-image-wrapper"&gt;&lt;img class="size-full wp-image-6160 aligncenter" src="https://res.cloudinary.com/practicaldev/image/fetch/s--lZjgOEIM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/03/image-7.png" alt="" width="627" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can also see — zooming into the field &lt;code&gt;app.user.email&lt;/code&gt; in the second row — that this incident of burn is actually due only to one person — encountering a small number of errors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Wwh24ZAG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/03/image-8.png" class="article-body-image-wrapper"&gt;&lt;img class="alignnone wp-image-6161" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Wwh24ZAG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/03/image-8.png" alt="" width="292" height="199"&gt;&lt;/a&gt; &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AZpM5dXP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/03/image-9.png" class="article-body-image-wrapper"&gt;&lt;img class="alignnone wp-image-6162" src="https://res.cloudinary.com/practicaldev/image/fetch/s--AZpM5dXP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/03/image-9.png" alt="" width="324" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This sort of rich explanation also lets us discover how to respond to the incident. For example, seeing this error, we know several things: we can reach out to the relevant customer to find out what the impact on them was; meanwhile, we can send the issue to the UX team to try to figure out what sequence of actions got to this error.&lt;/p&gt;

&lt;h2&gt;User Responses to SLOs&lt;/h2&gt;

&lt;p&gt;From the earlier versions of SLOs, we got useful and enthusiastic responses to the early betas. One user who had set up their SLO system, for example, wrote: “The Bubble Up in the SLO page is really powerful at highlighting what is contributing the most to missing our SLIs, it has definitely confirmed our assumptions.”&lt;/p&gt;

&lt;p&gt;Another found SLOs were good to show that their engineering effort was going in the right direction: ““The historical SLO chart also confirms a fix for a performance issue we did that greatly contributed to the SLO compliance by showing a nice upward trend line. :)”&lt;/p&gt;

&lt;p&gt;Unfortunately, after that first burst of ebullience, enthusiasm began to wane a little. A third customer finally gave us the necessary insight: “I’d love to drive alerts off our SLOs. Right now &lt;b&gt;we don’t have anything to draw us in&lt;/b&gt; and have some alerts on the average error rate .... It would be great to get a better sense of when the budget is going down and define alerts that way.”&lt;/p&gt;

&lt;h2&gt;Designing an Alert System&lt;/h2&gt;

&lt;p&gt;We had hoped to put off alerts until after SLOs were finished. It had become clear to us — from our experience internally as well as our user feedback — that alerts were a fundamental part of the SLO experience. Fortunately, it wasn’t hard to &lt;a href="https://docs.honeycomb.io/working-with-your-data/slos/#define-burn-alerts" rel="noopener noreferrer"&gt;design an alerting system&lt;/a&gt; that would warn you when your SLO was going to fail in several hours, or when your budget had burned out. We could extrapolate from the last few hours what the next few would look like; after some experimentation, we settled on a 1:4 ratio of baseline to prediction: that is, a one-hour baseline would be used to predict four hours from now; a six hour baseline would be used to predict the next day.&lt;/p&gt;

&lt;p&gt;We built our first alert system, wired it up to check on status every minute ... and promptly arranged a $10,000 day of AWS spend on data retrieval. (Before this, our most expensive query had cleared $0.25; this was a new and surprising cost).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--piQ1APsY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/03/image-10.png" class="article-body-image-wrapper"&gt;&lt;img class="size-full wp-image-6163 aligncenter" src="https://res.cloudinary.com/practicaldev/image/fetch/s--piQ1APsY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/03/image-10.png" alt="" width="702" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tony Hoare is known to have said that “premature optimization is the root of all evil;” it turns out that some optimization, however, can come too late. In our case, running a one-minute resolution query across sixty days of data, every minute, was asking a lot of both our query system and our storage.&lt;/p&gt;

&lt;p&gt;We paused alerts; and rapidly implemented a caching system.&lt;/p&gt;

&lt;p&gt;Caching is always an interesting challenge, but perhaps the most dramatic issue we ran into is that Honeycomb is designed as a best-effort querying system which is ok with occasional incorrect answers. (It’s even one of our company values: &lt;a href="https://www.honeycomb.io/blog/honeycomb-values-2018/" rel="noopener noreferrer"&gt;“Fast and close to right is better than perfect!”&lt;/a&gt;). Unfortunately, when you cache a close-to-right value, that means that you keep an incorrect value in your cache for an extended period; occasional incorrect values had an outsize effect on SLO quality. Some investigation showed that our database was able to identify queries that were approximations, and that few retries would usually produce a correct value; we ended up ensuring that we simply didn’t cache approximations.&lt;/p&gt;

&lt;p&gt;(We had other challenges with caching and quirks of the database, but I think those are less relevant from a design perspective.)&lt;/p&gt;

&lt;h3&gt;Handling Flappy Alerts&lt;/h3&gt;

&lt;p&gt;One of our key design goals was to reduce the number of alerts produced by noisy systems. Within a few days of release, though, a customer started complaining that their alert was turning just as noisy.&lt;/p&gt;

&lt;p&gt;We realized they’d been unlucky: their system happened to be such that their burndown was being estimated at &lt;i&gt;just about &lt;/i&gt;four hours. A bad event would pop in — and it would drop to 3:55. A good event would show up, and they’d bump up to 4:05. This flapping would turn on and off the alerts, frustrating and annoying users.&lt;/p&gt;

&lt;p&gt;Fortunately, the fix was easy once we’d figured out the problem: we added a small buffer, and the problems went away.&lt;/p&gt;

&lt;h2&gt;Learning from Experience&lt;/h2&gt;

&lt;p&gt;Last, I’d like to reflect just a little on what we’ve learned from the SLO experience, and some best practices for handling SLOs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;b&gt;Volume is important.&lt;/b&gt; A very small number of events really shouldn’t be enough to exhaust budget: if two or three failures can do it, then most likely, a standard alert would be the right use case. The SLO should tolerate at least in the dozens of failed events a day. Doing the math backward, an SLO of 99.9% needs a minimum level of traffic of a few tens of thousands of events a day to be meaningful.&lt;/li&gt;
&lt;li&gt;
&lt;b&gt;Test pathways, not users:&lt;/b&gt; It’s tempting to write an SLO per customer, to find out whether any customer is having a bad experience. That seems not to be as productive a path: first, it reduces volume (because each customer now needs those tens of thousands of events); second, if a single customer is having a problem, does that imply something about the system, or the customer? Instead, writing SLOs on paths through the system and on user scenarios seems like a better way to identify commonalities.&lt;/li&gt;
&lt;li&gt;
&lt;b&gt;Iterating is important: &lt;/b&gt;We learned rapidly that some of our internal SLOs were often off by a bit: they tested the wrong things, or had the wrong intuition for what it meant for something to be broken. For example, “status code &amp;gt;= 400” gets user errors (400s) as well as failures in our own system (500s). Iterating on them helped us figure out what we wanted.&lt;/li&gt;
&lt;li&gt;
&lt;b&gt;Cultural change around SLOs can be slow.&lt;/b&gt; Alerts on numbers in the system are familiar; SLOs are new and may seem a little unpredictable. Internally, our teams had been slow to adopt SLOs; after an&lt;a href="https://www.honeycomb.io/blog/incident-report-running-dry-on-memory-without-noticing/" rel="noopener noreferrer"&gt; incident hit&lt;/a&gt; that the SLOs caught long before alarms, engineers started watching SLOs more carefully.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;SLOs are an observability feature for characterizing what went wrong, how badly it went wrong, and how to prioritize repair. The pathway to implementing SLOs, however, was not as straightforward as we’d hoped. My hope by putting this post together is to help future implementors make decisions for their paths — and to help users know a little more about what’s going on behind the scenes.&lt;/p&gt;

&lt;p&gt;Want to know more about what Honeycomb can do for your business? Check out &lt;a href="https://www.honeycomb.io/get-a-demo?&amp;amp;utm_source=Devto&amp;amp;utm_Devto=blog&amp;amp;utm_campaign=referral&amp;amp;utm_keyword=%7Bkeyword%7D&amp;amp;utm_content=challenges-with-implementing-slos/"&gt;our short demo&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>observability</category>
      <category>slo</category>
      <category>operations</category>
      <category>sre</category>
    </item>
    <item>
      <title>Honeycomb SLO Now Generally Available: Success, Defined.</title>
      <dc:creator>Danyel Fisher</dc:creator>
      <pubDate>Fri, 04 Dec 2020 23:24:12 +0000</pubDate>
      <link>https://dev.to/honeycombio/honeycomb-slo-now-generally-available-success-defined-2hc3</link>
      <guid>https://dev.to/honeycombio/honeycomb-slo-now-generally-available-success-defined-2hc3</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/honeycombio/working-toward-service-level-objectives-slos-part-1-4oed"&gt;Previously, in this series&lt;/a&gt;, we created a derived column to show how a back-end service was doing. That column categorized every incoming event as passing, failing, or irrelevant. We then counted up the column over time to see how many events passed and failed. But we had a problem: we were doing far too much math ourselves.&lt;/p&gt;

&lt;p&gt;To address that problem, Honeycomb has now released &lt;a href="https://honeycomb.io/slos"&gt;&lt;b&gt;SLO Support!&lt;/b&gt;&lt;/a&gt;&lt;b&gt; &lt;/b&gt;Unsurprisingly, it is based on precisely the principles we discussed above.&lt;/p&gt;

&lt;p&gt;To recall, the derived column looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="k"&gt;EQUALS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"batch"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="k"&gt;EQUALS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="k"&gt;EQUALS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="n"&gt;LT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;duration_ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which meant, “we only count requests that hit the batch endpoint, and use the POST method. If they do, then we will say the SLI has succeeded if we processed it in under 100 ms, and returned a 200; otherwise, we’ll call it a failure.” We counted the percentage of total requests as our SLI success rate. For example, we might say that over the last thirty days, we managed a 99.4% SLI success rate.&lt;/p&gt;

&lt;h2&gt;Formalizing this structure&lt;/h2&gt;

&lt;ul&gt;
    &lt;li&gt;We’ll pick &lt;i&gt;an SLI&lt;/i&gt;. An SLI (Service Level Indicator) consists of the ability to sort all the events in my dataset into three groups: those that are irrelevant, those that pass, and those that fail.&lt;/li&gt;
    &lt;li&gt;Now, we’ll pick a&lt;i&gt; target level&lt;/i&gt; for this SLI. “Of the relevant events, we want &lt;b&gt;99.95% of them to pass&lt;/b&gt;.”&lt;/li&gt;
    &lt;li&gt;Last, we’ll pick a &lt;i&gt;duration&lt;/i&gt; for them: “&lt;b&gt;Over each 30 days&lt;/b&gt;, we expect our SLI to be at 99.95% passing.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The nice thing about this is that we can &lt;i&gt;quantify how our SLI is doing&lt;/i&gt;. We can look at a dataset, and see what percentage of events have succeeded.&lt;/p&gt;

&lt;p&gt;This is a really useful way to think about systems that are constantly in minor states of error. Ordinary noise happens; this can lead to transient failures or occasional alerts. We can use this structure to ask how much these minor running errors are costing us.&lt;/p&gt;

&lt;p&gt;(When there’s a catastrophic failure, frankly, SLOs are less surprising: every light on every console is blinking red and the phone is buzzing. We’ll use SLOs in those cases to estimate “how bad was this incident.”)&lt;/p&gt;

&lt;h2&gt;Understanding your Error Budget&lt;/h2&gt;

&lt;p&gt;Let’s make the assumption that we expect to see 100,000 relevant events in a given thirty day period. Let’s further say that, say, 700 of them have failed over the last 27 days. Over the next three days, we can afford for another 300 events to fail and still maintain a 99.9% SLO.&lt;/p&gt;

&lt;p&gt;This gets to the concept of an &lt;b&gt;error budget. &lt;/b&gt;In Honeycomb’s implementation, error budgets are &lt;b&gt;continuously rolling&lt;/b&gt;: at any moment, old errors are slowly scrolling away into the past, no longer counting against your budget.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m1CrLNzQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/01/SLO1-error-budget.png" class="article-body-image-wrapper"&gt;&lt;img class="size-full wp-image-5738 alignright" src="https://res.cloudinary.com/practicaldev/image/fetch/s--m1CrLNzQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/01/SLO1-error-budget.png" alt="graph showing error budget lines" width="468" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our example, we'll assume that the world looks something like this: The grey line at the top is the total number of events a system has sent. It’s staying pretty constant. The orange line shows errors.&lt;/p&gt;

&lt;p&gt;For this chart, the Y scale on the errors is exaggerated: after all, if you’re running at 99.9%, that means that there’s 1/1000 the number of errors as successes. (The orange line would be very small!)&lt;/p&gt;

&lt;p&gt;33 days ago, there was an incident which caused the number of errors to spike. Fortunately, we got that under control pretty quickly. Two weeks ago, there was a slower-burning incident, which took a little longer to straighten out.&lt;/p&gt;

&lt;h2&gt;Checking the Burn Down graph&lt;/h2&gt;

&lt;p&gt;It would be great to track &lt;i&gt;when&lt;/i&gt; we spent our error budget. Was the painful part of our last month those big spikes? Or was it the fact that we’ve had a small, continuous background burn the other time? How much were those background events costing us?&lt;/p&gt;

&lt;p&gt;The &lt;b&gt;burn down graph&lt;/b&gt; shows the last month, and how much budget was burned every day. If we had looked at the graph last week, we'd have seen that your last 30 days had been burnt, pretty hard, by that first incident, and then again by the second. The rest of the time has been a slow, continuous burn: nothing too bad. That helps us make decisions: are we just barely making budget every month? Is the loss due to incidents, or is it because we are slowly burning away over time?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uUJ3eOyn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/01/SLO2-burn-down1.png" class="article-body-image-wrapper"&gt;&lt;img class="aligncenter size-full wp-image-5739" src="https://res.cloudinary.com/practicaldev/image/fetch/s--uUJ3eOyn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/01/SLO2-burn-down1.png" alt="graph showing downward trend of burn-down" width="468" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both of those can be totally fine! For some systems, it’s perfectly reasonable to have a slow, gentle burn of occasional errors. For others, we want to keep our powder dry to compensate for more-severe outages!&lt;/p&gt;

&lt;p&gt;The graph from six days ago was looking dismal. That first incident had burned 40% of budget in a single incident; the usual pace of “a few percent a day” meant that the budget was nearly exhausted.&lt;/p&gt;

&lt;p&gt;But if we look at the burn down graph today, things are looking better! The first incident is off the books, and now we're only making up for the errors of D2. Someday, that too will be forgotten.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZS9zk5J9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/01/SLO3-burn-down2.png" class="article-body-image-wrapper"&gt;&lt;img class="aligncenter size-full wp-image-5740" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZS9zk5J9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/01/SLO3-burn-down2.png" alt="graph showing burn-down trend today" width="468" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We should also take a look at how we compare to the goal. For every day, we can compute the percentage of events that has passed the SLI. As you can see, we’re usually above 95% for most 30 day periods. At the trough of the first incident, things were pretty bad — and we lost ground, again, with the second one — but now we’re maintaining a comfortably higher level.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wz9qCxDY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/01/SLO4-overall-budget.png" class="article-body-image-wrapper"&gt;&lt;img class="aligncenter size-full wp-image-5741" src="https://res.cloudinary.com/practicaldev/image/fetch/s--wz9qCxDY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/01/SLO4-overall-budget.png" alt="graph showing error budget overall" width="468" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, all these illustrations have shown moments when our problems were comfortably in the past. While that’s a great place to have our problems, we wouldn’t be using Honeycomb if all our problems were solved. That’s why there are two other important SLO aspects to think about:&lt;/p&gt;

&lt;h2&gt;SLO Burn Alerts&lt;/h2&gt;

&lt;p&gt;When the error rate is gradually increasing, it would be great to know when we'll run out of budget. Honeycomb creates Burn Alerts to show when our SLO will run out of budget. The green line shows the gradually shrinking budget, but on a slightly adjusted window.&lt;/p&gt;

&lt;p&gt;Then, Honeycomb predicts forward. The orange line looks at how our &lt;b&gt;last&lt;/b&gt; hour has been, and then interpolates forward to the &lt;b&gt;next&lt;/b&gt; four hours. In this image, the four hour estimate is going to dip below zero — and so the system warns the user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K6h0JpOP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/01/SLO5-prediction.png" class="article-body-image-wrapper"&gt;&lt;img class="aligncenter size-full wp-image-5742" src="https://res.cloudinary.com/practicaldev/image/fetch/s--K6h0JpOP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/01/SLO5-prediction.png" alt="graph showing extrapolation of errore budget exhaustion" width="1940" height="1108"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This can let us know how long until we use up our error budget. It acts as a forewarning against slow failures.&lt;/p&gt;

&lt;p&gt;It’s really useful to have a couple of different time ranges. A 24 hour alert can mean “you’ve got a slow degradation in your service; you might want to fix it. — but worry about it in the morning.” A four hour alert means “it’s time to get cracking” (at Honeycomb, we tend to send 24 hour alerts to Slack channels, but 4 hour alerts to PagerDuty).&lt;/p&gt;

&lt;h2&gt;&lt;b&gt;Find out why it's going wrong&lt;/b&gt;&lt;/h2&gt;

&lt;p&gt;This wouldn’t be Honeycomb if we didn’t provide you tools to dive into an issue. The SLO Page shows a &lt;a href="https://docs.honeycomb.io/working-with-your-data/heatmaps/"&gt;Heatmap&lt;/a&gt; and a &lt;a href="https://docs.honeycomb.io/working-with-your-data/bubbleup/"&gt;BubbleUp&lt;/a&gt; of the last 24 hours, so you can figure out what’s changed and how you want to take it on.&lt;/p&gt;

&lt;p&gt;Here’s a great example: the SLO page for a Honeycomb tool that’s looking at rendering speed. (Yep, we’ve even set an SLO on end user experience!) This is a pretty loose SLO — really, we’re keeping it around to alarm us if our pages suddenly get really bad — but we can see that we’re doing OK against our goals.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iU445LCg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/01/SLO6-overall.png" class="article-body-image-wrapper"&gt;&lt;img class="aligncenter size-full wp-image-5743" src="https://res.cloudinary.com/practicaldev/image/fetch/s--iU445LCg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/01/SLO6-overall.png" alt="screenshot of overall SLO view page" width="1146" height="1306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The bottom half of the page shows &lt;i&gt;where&lt;/i&gt; the problems are coming from. The BubbleUp heatmap shows the last day of events: higher up are yellow, meaning these events fail the SLI; lower down are blue, meaning they are compliant with the SLI. We can see that mostly this is happening when events are particularly slow.&lt;/p&gt;

&lt;p&gt;We can also look in there and see that it’s &lt;b&gt;one particular page&lt;/b&gt; that seems to be having the worst experience, and one particular user email that’s running slow. That’s a pretty cool insight — it tells us where to look, and how we might want to handle it. It also gives us a sense for what repro cases to look for, and figure out what strange thing this user is doing.&lt;/p&gt;

&lt;h2&gt;Now, define your own SLOs&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.honeycomb.io/working-with-your-data/slos/"&gt;Honeycomb SLOs&lt;/a&gt; are now released and are available to Enterprise/yearly contract customers. We’d love to learn more about how you think about SLOs, and what you use them for.&lt;/p&gt;




&lt;p&gt;Read the final installment in this blog series: &lt;a href="https://dev.to/honeycombio/challenges-with-implementing-slos-1kp"&gt;Challenges with Implementing SLOs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;New to Honeycomb? &lt;a href="https://ui.honeycomb.io/signup?&amp;amp;utm_source=Devto&amp;amp;utm_Devto=blog&amp;amp;utm_campaign=referral&amp;amp;utm_keyword=%7Bkeyword%7D&amp;amp;utm_content=honeycomb-slo-now-generally-available-success-defined"&gt;Get started for free&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>slo</category>
      <category>observability</category>
      <category>devops</category>
      <category>sre</category>
    </item>
    <item>
      <title>Working Toward Service Level Objectives (SLOs), Part 1</title>
      <dc:creator>Danyel Fisher</dc:creator>
      <pubDate>Fri, 04 Dec 2020 23:19:16 +0000</pubDate>
      <link>https://dev.to/honeycombio/working-toward-service-level-objectives-slos-part-1-4oed</link>
      <guid>https://dev.to/honeycombio/working-toward-service-level-objectives-slos-part-1-4oed</guid>
      <description>&lt;p&gt;In theory, Honeycomb is always up. Our servers run without hiccups, our user interface loads rapidly and is highly responsive, and our query engine is lightning fast. In practice, this isn’t always perfectly the case — and dedicated readers of this blog have learned about how we &lt;a href="https://www.honeycomb.io/search/incident+review"&gt;use those experiences to improve the product&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, we could spend all our time on system stability. We could polish the front-end code and look for inefficiencies; throw ever-harder test-cases at the back-end. (There are a few developers who are vocal advocates for that approach!) But we also want to make the product better — and so we keep rolling out so many &lt;a href="https://changelog.honeycomb.io/"&gt;great features&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;How do we decide when to work on improving stability, and when we get to go make fun little tweaks?&lt;/p&gt;

&lt;h2&gt;From organizational objectives to events&lt;/h2&gt;

&lt;p&gt;So let’s say we come to an agreement with each other about "how bad" things are. When things are bad—when we’re feeling mired in small errors, or one big error that takes down the service—we can slow down on Cool Feature Development, and switch over to stability work. Conversely, when things are feeling reasonably stable, we can believe we have a pretty solid infrastructure for development, and can slow down on repair and maintenance work.&lt;/p&gt;

&lt;p&gt;What would that agreement look like?&lt;/p&gt;

&lt;p&gt;First, it means being able to take a good hard look at our system. Honeycomb has a &lt;a href="https://www.honeycomb.io/blog/toward-a-maturity-model-for-observability/"&gt;mature level of observability&lt;/a&gt;, so we feel pretty confident that we have the raw tools to look at how we’re doing — where users are experiencing challenges, and where bugs are appearing in our system.&lt;/p&gt;

&lt;p&gt;Second, it means coming to understand that no system is perfect. If our goal is 100% uptime at all times for all requests, then we’ll be disappointed, because some things will fail from time to time.&lt;em&gt; But we can come up with statements about quality of service&lt;/em&gt;. Honeycomb had an internal meeting where we worked to quantify this:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;We pretty much &lt;b&gt;never&lt;/b&gt; want to lose customer data. We live and die by storing customer data, so we want &lt;i&gt;every&lt;/i&gt; batch of customer telemetry to get back a positive response, and quickly. Let’s say that we want them to be handled in under 100 ms, without errors, for 99.95% of requests. (That means that in a full year, we could have &lt;b&gt;4 hours&lt;/b&gt; of downtime.)&lt;/li&gt;
    &lt;li&gt;We want our main service to be up pretty much every time someone clicks on honeycomb.io, and we want it to load pretty quickly. Let’s say we want to load the page without errors, within a second, for 99.9% of requests.&lt;/li&gt;
    &lt;li&gt;Sometimes, when you run a query, it takes a little longer. For that, we decided that 99.5% of data queries should come back within 10 seconds and not return an error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are entirely reasonable goals. The wonderful thing is, they can actually be expressed in Honeycomb’s dogfood servers as &lt;a href="https://www.honeycomb.io/blog/level-up-with-derived-columns-two-neat-tricks-that-will-improve-your-observability/"&gt;Derived Column expressions&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;For example, we would write that first one — the one about data ingest — as “We’re talking about events where &lt;code&gt;request.endpoint&lt;/code&gt; uses the &lt;code&gt;batch&lt;/code&gt; endpoint and the input is a &lt;code&gt;POST&lt;/code&gt; request. When they do, they should return a code 200, and the &lt;code&gt;duration_ms&lt;/code&gt; should be under 100.&lt;/p&gt;

&lt;p&gt;Let’s call this a “Service Level Indicator,” because we use it to indicate how our service is doing. In our &lt;a href="https://docs.honeycomb.io/working-with-your-data/customizing-your-query/derived-columns/reference/"&gt;derived column language&lt;/a&gt;, that looks like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="k"&gt;EQUALS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"batch"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="k"&gt;EQUALS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="k"&gt;EQUALS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="n"&gt;LT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;duration_ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We name that derived column “SLI”, and we can generate a COUNT and a HEATMAP on it&lt;/p&gt;

&lt;p&gt;This looks pretty sane: we see that there are many more points that are true (the indicator is ok! everything is great!) than false (oh, no, they failed!); and we can see that all the points that are slowest are in the “false” group.&lt;/p&gt;

&lt;p&gt;Let’s whip out our Trusty Pocket Calculator: 35K events with “false”; 171 million with true. That’s about a 0.02% failure rate — we’re up at 99.98%. Sounds like we’re doing ok!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ToJjW0OX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2019/09/SLO-1.gif" class="article-body-image-wrapper"&gt;&lt;img class="aligncenter size-full wp-image-5232" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ToJjW0OX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2019/09/SLO-1.gif" alt="animated gif of a graph with some failures" width="1112" height="673"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But there are still some failures. I’d love to know why!&lt;/p&gt;

&lt;p&gt;By clicking over to the BubbleUp tab, I can find out who is having this slow experience. I highlight all the slowest requests, and BubbleUp shows me a histogram for every dimension in the dataset. By finding those columns that are most different from everything else, I can see wehre these errors stand out.&lt;/p&gt;

&lt;p&gt;... and I see that it’s one particular customer, and one particular team. Not only that, but they’re using a fairly unusual API for Honeycomb (that’s the fourth entry, &lt;code&gt;request.header.user-agent&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9GsO5xFS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2019/09/SLO-2.png" class="article-body-image-wrapper"&gt;&lt;img class="aligncenter size-full wp-image-5233" src="https://res.cloudinary.com/practicaldev/image/fetch/s--9GsO5xFS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2019/09/SLO-2.png" alt="screenshot of using BubbleUp to identify one problematic user" width="985" height="988"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is great, and highly actionable! I can reach out to the customer, and find out what’s up; I can send our integrations team to go look at that particular package, and see if we’re doing something that’s making it hard to use well.&lt;/p&gt;

&lt;h2&gt;Quantifying quality of service means you can measure it&lt;/h2&gt;

&lt;p&gt;So bringing that back to where we started: we’ve found a way to start with organizational goals, and found a way to quantify our abstract concept: “always up and fast” now has a meaning, and is measurable. We can then use that to diagnose what’s going wrong, and figure out how to make it faster.&lt;/p&gt;

&lt;p&gt;Part 2, coming soon: Wait, why did I have to pull out my pocket calculator? Don’t we have computers for that? Also, this term “SLI”, it feels familiar somehow...&lt;/p&gt;




&lt;p&gt;Read the next post in the series:&lt;br&gt;
&lt;a href="https://www.honeycomb.io/blog/honeycomb-slo-now-generally-available-success-defined/"&gt;Honeycomb SLO Now Generally Available: Success, Defined.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Excited about what the future of operational excellence looks like? Get started with &lt;a href="https://ui.honeycomb.io/signup?&amp;amp;utm_source=Devto&amp;amp;utm_Devto=blog&amp;amp;utm_campaign=referral&amp;amp;utm_keyword=%7Bkeyword%7D&amp;amp;utm_content=working-toward-service-level-objectives-slos-part-1"&gt;Honeycomb for free&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>slos</category>
      <category>observability</category>
      <category>devops</category>
      <category>sre</category>
    </item>
    <item>
      <title>Unpacking Events: All the Better to Observe</title>
      <dc:creator>honeycomb</dc:creator>
      <pubDate>Mon, 16 Nov 2020 17:28:52 +0000</pubDate>
      <link>https://dev.to/honeycombio/unpacking-events-all-the-better-to-observe-1agk</link>
      <guid>https://dev.to/honeycombio/unpacking-events-all-the-better-to-observe-1agk</guid>
      <description>&lt;p&gt;&lt;span&gt;At Honeycomb, we’ve been listening to your feedback. You want easier ways to predict usage and scale your observability spend with your business. What would it look like to meet you where you already are, using similar terms, and give you more control with a simpler experience? We think that means reimagining the customer experience into one that centers around an event-based model.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;But what exactly is an event? What does that mean for your team’s observability journey?&lt;/span&gt;&lt;/p&gt;

&lt;h2&gt;&lt;span&gt;The Old Way&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;&lt;span&gt;Traditionally, Honeycomb has charged customers based on two axes: ingest and retention. We figured not everyone has the same needs, so why not have you select what’s right for you? But in practice, that translated into placing more administrative burden on you.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Many of you told us that you’d frequently visit the Usage page to fiddle with the slider, responding to spikes in traffic (and therefore ingest) by reducing your retention period in order to keep your bill around the same amount each month. We started to see that become a difficult (but common) tradeoff: if you want to send more data, then it wouldn’t stick around as long. Many of you ended up robbing Peter to pay Paul.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;In addition, we found that it’s not intuitive for many of you to estimate ingest in gigabytes. As a result, many Usage page sliders were adjusted reactively, without much sense of how that would affect Honeycomb cost as more systems were integrated or as service traffic continued to grow.&lt;/span&gt;&lt;/p&gt;

&lt;h2&gt;&lt;span&gt;Stress-Free Observability&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;&lt;span&gt;Let’s face it, that’s not a great experience. If we could take what we’ve learned from you to make it better, what would we do?&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;You can’t always anticipate traffic spikes. A great experience would not penalize you for those.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;You don’t want to obsess over usage every month or have to explain variations in spend to your accounting team. A great experience would let you set your monthly or yearly spend and forget about it, knowing you have headroom for growth.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;You want to stop worrying about retention and capacity planning. We’ve worked with many teams who limit their retention to 24 hours, or even less! A great experience would give you an extended time frame with your data. In the beginning, you would have space to get comfortable with your new instrumentation. Over time, it would allow you to reflect back on the last two months to support your incident review and capacity planning needs.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;A great experience would encourage you to send us wide events with many context fields, since that’s the richness you need for observability. You shouldn’t have to worry about how much data each of those events sends.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;What we’ve found is that as you progress on your observability journey, your instrumentation will reach an equilibrium. Once you figure out your right level of instrumentation, your usage should be predictable and aligned with your application’s traffic patterns. You want to spend time thinking about improving your application, not optimizing fiddly usage sliders.&lt;/span&gt;&lt;/p&gt;

&lt;h2&gt;&lt;span&gt;You Already Think About Events&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;&lt;span&gt;In thinking about how to meet you where you already are, it makes a lot of sense to land on the &lt;/span&gt;&lt;b&gt;event&lt;/b&gt;&lt;span&gt; as the core unit of measure.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;But not all events are scoped similarly. Let’s define what an “event” would mean to Honeycomb, and how that relates to the events you care about for your service.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Honeycomb defines an event as a single “unit of work” in your application code. But a “unit of work” can have a dozen meanings in a dozen contexts. It can be as small as flipping a bit or as large as a round-trip HTTP request. The simplest definition is that an event is usually either a &lt;/span&gt;&lt;b&gt;trace span&lt;/b&gt;&lt;span&gt;, or a &lt;/span&gt;&lt;b&gt;log event&lt;/b&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Let’s unpack that a bit further.&lt;/span&gt;&lt;/p&gt;

&lt;h3&gt;&lt;span&gt;Log Events&lt;/span&gt;&lt;/h3&gt;

&lt;p&gt;&lt;span&gt;For logs, enumerating events is pretty straightforward. If you use (or if you’re planning to use) &lt;/span&gt;&lt;a href="https://docs.honeycomb.io/getting-data-in/integrations/honeytail/"&gt;&lt;span&gt;honeytail&lt;/span&gt;&lt;/a&gt;&lt;span&gt; to send structured logs into Honeycomb, you likely already know how many log events you’re sending. For infrastructure teams with less authority over code changes, installing an agent like honeytail, the &lt;/span&gt;&lt;a href="https://docs.honeycomb.io/getting-data-in/integrations/aws/"&gt;&lt;span&gt;AWS integrations&lt;/span&gt;&lt;/a&gt;&lt;span&gt;, or the newly-upgraded &lt;/span&gt;&lt;a href="https://docs.honeycomb.io/getting-data-in/integrations/kubernetes/"&gt;&lt;span&gt;Kubernetes agent&lt;/span&gt;&lt;/a&gt;&lt;span&gt; is the best way to get data into Honeycomb. Each event in these agents corresponds to one event in Honeycomb.&lt;/span&gt;&lt;/p&gt;

&lt;h3&gt;&lt;span&gt;Trace Spans and Events&lt;/span&gt;&lt;/h3&gt;

&lt;p&gt;&lt;span&gt;With spans, we need to examine the definition a bit more. To start: we’ve decided that one span equals one event.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;If you want high-res observability into your systems, you’ve probably looked into trace-aware instrumentation like our &lt;a href="https://docs.honeycomb.io/getting-data-in/beelines/"&gt;Beelines&lt;/a&gt;. &lt;a href="https://www.honeycomb.io/search/tracing"&gt;We’ve already written a lot about the benefits of tracing.&lt;/a&gt; For this post, let’s focus on what &lt;/span&gt;&lt;b&gt;1 span == 1 event &lt;/b&gt;&lt;span&gt;would mean for adding trace-aware instrumentation to your service.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;As a service owner, you already have your own concept of events in your world: HTTP or API requests, background tasks, queue events, etc. If your app is in production, you probably know your traffic patterns, i.e.:&lt;/span&gt;&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;span&gt;How many of your service’s events you experience at any particular time scale—per second, per hour, per day, per month&lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;&lt;span&gt;The seasonality of those events at different times of the day, week, month, year&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;span&gt;When you’ve instrumented for tracing, one of your service’s events generates a single Honeycomb trace. A trace is made up of one or more spans. Remember that in this world, one span is one event.&lt;/span&gt;&lt;/p&gt;

&lt;h2&gt;&lt;span&gt;Estimating Honeycomb Events&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;&lt;span&gt;From here you can roughly predict your Honeycomb usage as a function of your traffic. For example, you could estimate your monthly usage like so:&lt;/span&gt;&lt;/p&gt;

&lt;pre&gt;&lt;span&gt;  (Number of your service’s events per month)
&lt;/span&gt;&lt;span&gt;× (Number of spans in each service event)
_____________________________________________
=  Honeycomb usage per month&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&lt;span&gt;So how do you figure out the number of spans for each of your service’s events?&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;A useful guideline: one span gets generated from each method call, down to a certain level of granularity. By “granularity,” we mean how deep you go down the call stack. Sometimes you care about the context in methods being called by other methods, and sometimes you don’t. &lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;For example, you probably care more about what kinds of database queries your controller is making, and less about what arguments went into &lt;code&gt;Math.sum()&lt;/code&gt;. (Don’t let me tell you what’s important, though! You know your code better than I do.)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.honeycomb.io/wp-content/uploads/2020/05/sql.png"&gt;&lt;img class="aligncenter size-full wp-image-6589" src="https://res.cloudinary.com/practicaldev/image/fetch/s--okcsUzX4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/05/sql.png" alt="" width="1600" height="94"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Still, the number of spans generated from one of your service’s events depends on the kind of event that is. In this example, an HTTP request using the &lt;a href="https://docs.honeycomb.io/getting-data-in/ruby/beeline/"&gt;ruby-beeline&lt;/a&gt; Rails integration, generated 18 spans. If you’re calling out to another service like Redis or S3, that will generate more spans.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.honeycomb.io/wp-content/uploads/2020/05/collapsed.png"&gt;&lt;img class="aligncenter size-full wp-image-6588" src="https://res.cloudinary.com/practicaldev/image/fetch/s--hfmZ3kDn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/05/collapsed.png" alt="" width="1600" height="93"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the same HTTP request, fully expanded:&lt;a href="https://www.honeycomb.io/wp-content/uploads/2020/05/expanded.png"&gt;&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.honeycomb.io/wp-content/uploads/2020/05/expanded.png"&gt;&lt;img class="aligncenter size-full wp-image-6586" src="https://res.cloudinary.com/practicaldev/image/fetch/s--s9K0jlVw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/05/expanded.png" alt="" width="1600" height="862"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;&lt;b&gt;What to expect&lt;/b&gt;&lt;/h2&gt;

&lt;p&gt;&lt;span&gt;There's no magic number for the “proper” level of granularity in tracing. As you ramp up your use of Honeycomb, you'll make discoveries that'll guide how to further instrument your code. New Honeycomb users often discover long-hidden bugs and inefficiencies when they first instrument for tracing. Aim for higher granularity early on with the goal of learning, finding these inefficiencies, and nipping them in the bud.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;So when you see a high-granularity trace with many spans, ask yourself, “Is this trace valuable?” It’s entirely in the eye of the beholder!&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.honeycomb.io/wp-content/uploads/2020/05/mysql_trace.png"&gt;&lt;img class="aligncenter size-full wp-image-6587" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZGsXlEzV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.honeycomb.io/wp-content/uploads/2020/05/mysql_trace.png" alt="" width="1276" height="960"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;After this initial period of discovery, you'll gain familiarity with what a normal trace looks like for various parts of your service. Going forward, you'll be much more interested in the abnormal and better able to tune your instrumentation.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Let’s look back at our estimation formula from up above to figure out exactly what usage to expect:&lt;/span&gt;&lt;/p&gt;

&lt;pre&gt;&lt;span&gt;  (Number of your service’s events per month) &lt;/span&gt;
&lt;span&gt;× (Number of spans in each service event) &lt;/span&gt;
&lt;span&gt;_____________________________________________ 
=  Honeycomb usage per month&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&lt;span&gt;Plugging in some numbers, let’s say your service gets around 1 million requests per day, or up to 30 million requests per month. If each request sends ~20 spans, then you’re looking at 600 million Honeycomb events per month. If each request sends ~50 spans, you’ll be sending 1.5 billion Honeycomb events per month.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Rather than worrying about storage size and retention periods, in this event-based world you’d be able to quickly ascertain what your usage needs are. In future posts, we’ll cover more about what that means going forward and how to even further optimize your usage with techniques like dynamic sampling.&lt;/span&gt;&lt;/p&gt;




&lt;p&gt;Have questions on how to get started? Want help estimating your event volume? Reach out to our team at &lt;a href="mailto:info@honeycomb.io"&gt;&lt;/a&gt;&lt;a href="mailto:info@honeycomb.io"&gt;info@honeycomb.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Not using Honeycomb? &lt;a href="https://ui.honeycomb.io/signup?&amp;amp;utm_source=Devto&amp;amp;utm_Devto=blog&amp;amp;utm_campaign=referral&amp;amp;utm_keyword=%7Bkeyword%7D&amp;amp;utm_content=lets-talk-events"&gt;Get started today, for free&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>tracing</category>
      <category>observability</category>
      <category>span</category>
      <category>logging</category>
    </item>
    <item>
      <title>The Future of Ops Careers — Honeycomb</title>
      <dc:creator>Charity Majors</dc:creator>
      <pubDate>Fri, 13 Nov 2020 16:36:21 +0000</pubDate>
      <link>https://dev.to/honeycombio/the-future-of-ops-careers-honeycomb-56pj</link>
      <guid>https://dev.to/honeycombio/the-future-of-ops-careers-honeycomb-56pj</guid>
      <description>&lt;p&gt;Have you seen &lt;a href="https://medium.com/@jeremydaly/lambda-a-serverless-musical-cf8ec5d522e1?" rel="noopener noreferrer"&gt;Lambda: A Serverless Musical&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;If not, you really have to. I love Hamilton, I love serverless, and I’m not trying to be a crank or a killjoy or police people’s language. BUT, unfortunately, the chorus chose to double-down on one of the stupidest and most dangerous tendencies the serverless movement has had from day one: misunderstanding and trash-talking operations.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;“I’m gonna reduce your… ops&lt;/i&gt;&lt;br&gt;
&lt;i&gt;I’m gonna reduce your… ops”&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;Well, I hate to tell you, but…&lt;/p&gt;

&lt;p&gt;&lt;i&gt;“No, I am not throwing away my… ops.&lt;/i&gt;&lt;br&gt;
&lt;i&gt;And you’re not throwing away my… ops.”&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;Or anyone else’s for that matter.&lt;/p&gt;

&lt;p&gt;Even if you don’t run any servers or have any infrastructure of your own, you’ll still have to deal with operability and operations engineering problems. I hate to be the bearer of bad news (not really), but the role of operations isn’t going away. At best, the shifts that supposedly reduce your ops are simply delegating the operability of your stack to someone that does it better. The reality for most teams is that operations engineering is more necessary than ever.&lt;/p&gt;

&lt;p&gt;Beyond Hamilton clap backs, that distinction matters because it has real career ramifications for engineers who, like me, are so operationally minded. Where are Ops careers heading?&lt;/p&gt;

&lt;h2&gt;Where Does Ops Fit, Anyway?&lt;/h2&gt;

&lt;p&gt;In some corners of engineering, “ops” is straight up used as a synonym for toil and manual labor. There is no good ops, only dead ops. The existence of ops is a technical failure: a blemish to be automated away, eradicated by adding more and more code. Code defeats toil. Dev makes ops obsolete. #NoOps!&lt;/p&gt;

&lt;p&gt;If this is such an inexorable march towards utopia, maybe someone can explain to me why the shops that flirt the hardest with #NoOps have been, without exception, such humanitarian disasters?&lt;/p&gt;

&lt;p&gt;Or, I’ll start. Operations is ridiculously important. When you denigrate it and diminish it, that’s the first sign that you aren’t doing it well. The way to do something well generally starts with adding focus and rigor, not writing it off.&lt;/p&gt;

&lt;p&gt;Consider Business Development and Operations. Business is the why, development is the what, operations is the how. Operations is the constellation of your organizational memory: patterns, practices, habits, defaults, aspirations, expertise, tools, and everything else used to deliver business value to users.&lt;/p&gt;

&lt;p&gt;The value of serverless isn’t found in “less ops.” Less ops doesn’t yield better systems than more ops, any more than fewer lines of code means better software. The value of serverless is unlocked by clear and powerful abstractions that let you delegate running large portions of your infrastructure to other people who can do it better than you — yes, because of economies of scale, but more so because that’s their core business model. YOUR core business model probably has nothing to do with infrastructure.&lt;/p&gt;

&lt;p&gt;Because of that, a great sort is now happening between software engineering, infrastructure operations, and core business value.&lt;/p&gt;

&lt;h2&gt;What Is Infrastructure?&lt;/h2&gt;

&lt;p&gt;Infrastructure is software support. It’s the prerequisite thing you &lt;i&gt;have&lt;/i&gt; to do, in order to get to the stuff you &lt;i&gt;want&lt;/i&gt; to do. It’s not what you want to be doing, yet your business goals presume its existence.&lt;/p&gt;

&lt;p&gt;An important quality of infrastructure is that it typically changes less often and is more stable than the software that constitutes your core business value. The features you ship to customers are typically under constant or frequent development, and they change at the rate of pull requests and commits (in fact, the velocity of these changes can be a critical competitive advantage). Infrastructure, on the other hand, changes at a more glacial pace — at the rate of package managers, OS updates, and new machine images. It’s seconds-to-minutes versus hours-to-days.&lt;/p&gt;

&lt;p&gt;This dividing line between infrastructure and core business value even holds true for companies whose business model is building infrastructure for other companies. For example, a company providing email focuses on products that consist of email workflow features that are constantly being developed and shipped to users. There isn’t much new business value to be wrung out of modifying commodity SMTP transport layers or optimizing IMAP servers.&lt;/p&gt;

&lt;p&gt;To its credit, serverless is perhaps the first trend to have really understood and powerfully leveraged that dividing line. IaaS, PaaS, and full-service suites like Gitlab were all germinal forms of this shift. “Cloud native” was also, arguably, another lurch in that direction. But where has that taken our industry?&lt;/p&gt;

&lt;h2&gt;*-As-a-Service Is Really Just Code for “Outsourcing”&lt;/h2&gt;

&lt;p&gt;IaaS, PaaS, and even FaaS/serverless are really all just types of outsourcing. But yet we don’t call it “outsourcing” when we rely on companies like AWS to run our datacenter and provide compute or storage, or when we use Google apps for our email, documents, and spreadsheets?&lt;/p&gt;

&lt;p&gt;Historically, “outsourcing” is what we call shifting work off-premises when we aren’t yet comfortable with the arrangement; whether because the fit is awkward, the support is incomplete, or the service isn’t on par with what we could do ourselves. With infrastructure outsourcing, service quality is now creeping up the stack. More and more complex subsystems are becoming commodity components: and other companies utilize them to build their own businesses (or other infrastructure!) on top.&lt;/p&gt;

&lt;p&gt;When I started my career, I was a jack-of-all-trades systems person. I ran mail, web, db, DNS, cache, deploys, CI/CD, patched operating systems, built debs and rpms, etc, etc. Most engineers don’t do those things now, and nor do I. Why would I, when I can pay someone else to abstract those details away, so that I can spend my time focusing on delivering customer value?&lt;/p&gt;

&lt;p&gt;Increasingly, as an industry, we are outsourcing any bits that we can.&lt;/p&gt;

&lt;p&gt;As a more personal example, why would you want to run your own observability team or build your own in-house monitoring software, if that’s not your core business? Why split your focus to building a bespoke and unsustainable version of a thing when you can readily buy a world-class version? If my company has had ten or twenty full-time engineers working on that solution, how long will it be until your team of three or five can catch up?&lt;/p&gt;

&lt;p&gt;In a post-cloud world, we’ve learned that it’s usually much better and far easier to buy than it is to build those things that don’t add business value.&lt;/p&gt;

&lt;h2&gt;How to Outsource Things Well&lt;/h2&gt;

&lt;p&gt;In my personal example, buying doesn’t mean that you shouldn’t have an observability team. It means that the observability team should turn their gaze inward. That team should take a page out of the SRE or test community’s books and focus on providing value for your org’s developers whenever they interact with this outsourced solution.&lt;/p&gt;

&lt;p&gt;That team should write libraries, generate examples, and drive standardization; ushering in consistency, predictability, and usability. They should partner with internal teams to evaluate use cases. They should partner with your vendors as roadmap stakeholders. They might also write glue code and helper modules to connect disparate data sources and create cohesive visualizations. Basically, that team becomes an integration point between your organization and the outsourced work.&lt;/p&gt;

&lt;p&gt;We already &lt;a href="https://cloudplatformonline.com/rs/248-TPC-286/images/DORA-State%20of%20DevOps.pdf" rel="noopener noreferrer"&gt;know from industry research&lt;/a&gt; that the key to success when outsourcing is to embed those off-prem contributions within cross-functional teams, which manage integrating that work back into the broader organization.&lt;/p&gt;

&lt;p&gt;Monstrous amounts of engineering work create the stack that ships value to your customers. Trying to save work, some teams build complicated Rube Goldberg machines that are brutal to run, change, and debug. It’s much harder to build simple platforms with operable, intelligible components that provide a humane user experience. Bridging that gap requires quality operations engineering to streamline that outsourcing for successful user adoption.&lt;/p&gt;

&lt;p&gt;That’s why even if you run no servers and have no infrastructure of your own, you still have operability and operations problems to contend with. Getting to the point where your org successfully has no infrastructure of its own takes a lot of world-class operations expertise. Staying there is even harder. Any jerk with a credit card can just go spin up a server you’re now responsible for. Try being any sort of roadblock and see how quickly that happens.&lt;/p&gt;

&lt;h2&gt;What This Means For Operationally Minded Engineers&lt;/h2&gt;

&lt;p&gt;The reality is that jack-of-all-trades systems infrastructure jobs are slowly vanishing: the world doesn’t need thousands of people who can expertly tune postfix, SpamAssassin and ClamAV — the world has Gmail. You might find your next job by following the trail of technologies you know, like getting hired as a MySQL expert. But technologies come and go, so you should think carefully before hitching your cart to any particular piece of software. What will this mean for your career?&lt;/p&gt;

&lt;p&gt;The industry is bifurcating along an infrastructure fault line, and the long-held indistinguishability between infrastructure-oriented engineers and operationally-minded engineers is swiftly eroding. These are becoming two different roles and career paths at two different kinds of companies: infrastructure providers, and the rest of them. Those of us who love optimizing, debugging, maintaining, and tackling weird systems problems far more than writing new greenfield code, now have a choice to make: go deep and specialize in infrastructure, or go broad on operability.&lt;/p&gt;

&lt;p&gt;If the mission of your company is to solve a category problem by providing infrastructure to the world, then operations will always be a core part of that mission: your company thrives by solving that particular operability problem better than anyone. So you are justified in going deep and specializing in it, and figuring out how to do it better and more efficiently than anyone else in the world — so that other people don’t have to. But know that even this infrastructure-heavy backend work also needs design, product management, and software engineering work — just like those non-infrastructure focused companies!&lt;/p&gt;

&lt;p&gt;If your chosen company isn’t solving an infrastructure problem for the world, there are still loads of opportunities for ops generalists here too. But know that a core part of your job is critically examining the cycles your company devotes to infrastructure operations and finding effective ways to outsource or minimize their in-house developer cycles. Your job is &lt;i&gt;not &lt;/i&gt;to go deep if there is any alternative.&lt;/p&gt;

&lt;p&gt;I see operationally-minded engineers working cross-functionally with software development teams to help them grow in a few key areas: making outsourcing successful, speeding up time to value, and up-leveling their production chops.&lt;/p&gt;

&lt;p&gt;They’re evolving very crude “build vs. buy” industry arguments (often based on little more than whimsical notions) into sophisticated understandings of how and when to leverage abstractions that radically accelerate development. They build and maintain the bridges that make outsourcing successful.&lt;/p&gt;

&lt;p&gt;They’re evolving release engineering to fulfill the delivery part of CI/CD. Far too many teams are perfectly competent at writing software, yet perfectly remedial when it comes to shipping that software swiftly and safely.&lt;/p&gt;

&lt;p&gt;They’re also up-leveling the production operational skills of software engineers by crafting on-call rotations, counseling teams on instrumentation, and teaching observability. As teams leave behind dated metrics and logs, they start using observability to dig themselves out of the ever-increasing massive hole where everyone constantly ships software they don’t understand to a production system they’ve never understood.&lt;/p&gt;

&lt;p&gt;Everyone needs operational skills; even teams who don’t run any of their own infrastructure. Ops is the constellation of skills necessary for shipping software; it’s not optional. If you ship software, you have operations work that needs to be done. That work isn’t going away. It’s just moving up the stack and becoming more sophisticated, and you might not recognize it.&lt;/p&gt;

&lt;p&gt;I look forward to the improved Lambda Serverless Musical chorus:&lt;/p&gt;

&lt;p&gt;&lt;i&gt;I’m going to improve your… ops.&lt;/i&gt;&lt;br&gt;
&lt;i&gt;Yes, I’m going to improve your… ops!&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;Read more about &lt;a href="https://www.honeycomb.io/blog/observations-on-the-enterprise-of-hiring/?&amp;amp;utm_source=tns&amp;amp;utm_medium=blog-links&amp;amp;utm_campaign=referral&amp;amp;utm_content=observations-on-the-enterprise-of-hiring" rel="noopener noreferrer"&gt;Honeycomb’s hiring methodology&lt;/a&gt;. P.S. &lt;a href="https://jobs.lever.co/honeycomb" rel="noopener noreferrer"&gt;We’re hiring&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Join the swarm! Get started with &lt;a href="https://ui.honeycomb.io/signup?&amp;amp;utm_source=Devto&amp;amp;utm_Devto=blog&amp;amp;utm_campaign=referral&amp;amp;utm_keyword=%7Bkeyword%7D&amp;amp;utm_content=the-future-of-ops-careers"&gt;Honeycomb for free&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>career</category>
      <category>observability</category>
      <category>operations</category>
      <category>sre</category>
    </item>
  </channel>
</rss>
