Files
nexus/sreweekly/articles/168/06-the-case-method-better-monitoring-for-humans.html
2026-09-12 17:23:01 +08:00

283 lines
25 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html>
<head>
<!-- Google tag (gtag.js) --> <script async src="https://www.googletagmanager.com/gtag/js?id=G-3VKN4BGJPL"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-3VKN4BGJPL'); </script>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Twitter cards -->
<meta name="twitter:site" content="@">
<meta name="twitter:creator" content="@">
<meta name="twitter:title" content="The CASE Method: Better Monitoring For Humans">
<meta name="twitter:description" content="A framework for improved monitoring ergonomics, mental models, and attention.">
<meta name="twitter:card" content="summary_large_image">
<meta property="og:image" content="http://onemogin.com/assets/images/case-logo.png?201">
<!-- end of Twitter cards -->
<title>The CASE Method: Better Monitoring For Humans</title>
<meta name="description" content="Riiiiiiing! It’s 3am and you’ve just been dreaming about something great then poof: the phone rings. You’re on call this week and something seems to’ve gone ...">
<link rel="alternate" type="application/rss+xml" title="One Mo' Gin" href="http://onemogin.com/feed.xml" />
<!-- Latest compiled and minified CSS -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans:wght@400;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/main.css">
<link rel="canonical" href="http://onemogin.com/monitoring/case-method-better-monitoring-for-humans.html">
</head>
<body class="bg-white dark:bg-zinc-900 text-gray-900 dark:text-zinc-100">
<header class="mb-3 shadow-md p-3 border-b border-gray-200 dark:border-zinc-700">
<div class="flex items-center">
<a class="text-2xl" href="/">One Mo' Gin</a>
<nav class="ml-auto text-sm">
<div class="px-5 py-3 space-x-3 rounded-2xl shadow-md border border-gray-200 dark:border-zinc-700">
<a class="hover:underline text-rose-500 hover:text-rose-600" href="/observability">Observability</a>
<a class="hover:underline text-rose-500 hover:text-rose-600" href="/resilience">Resilience</a>
<a class="hover:underline text-rose-500 hover:text-rose-600" href="/about">About</a>
</div>
</nav>
</div>
</header>
<div class="mt-8 mx-12 lg:mx-24">
<div>
<article class="prose prose-neutral lg:prose-lg dark:prose-invert prose-a:text-rose-500">
<header>
<h1>The CASE Method: Better Monitoring For Humans</h1>
<time class="text-sm text-gray-400" datetime="2019-04-09 07:49:00 +0000">Apr 9, 2019</p>
</header>
<p>Riiiiiiing! It’s 3am and you’ve just been dreaming about something great then poof: the phone rings. You’re on call this week and something seems to’ve gone awry. Automated systems are beckoning you to assess the situation and take action. Welcome to a critical point in running modern computer systems. Let’s talk about how to make alerting better for humans.</p>
<p>I’d like to introduce a philosophy for monitoring borne from my decades of on-call experience, my role in multiple large observability teams, and heavy influence from Rob Ewaschuk’s seminal <a href="https://docs.google.com/document/d/199PqyG3UsyXlwieHaqbGiWVa8eMWi8zzAn0YfcApr8Q/edit#heading=h.6ammb5h32uqq">My Philosophy on Alerting</a> — which has since been encoded into the <a href="https://landing.google.com/sre/sre-book/toc/index.html">Google SRE book</a> — and John Allspaw’s <a href="https://www.slideshare.net/jallspaw/alert-designcac-talk2013">Considerations for Alert Design</a>.</p>
<p><em>Thanks to <a href="https://twitter.com/kellyleland">Kelly Dunn</a>, <a href="https://twitter.com/arijit_mukherji">Arijit Mukherji</a>, and <a href="https://twitter.com/mpetazzoni">Maxime Petazzoni</a> for reviewing this post.</em></p>
<h1 id="what-is-case">What is CASE?</h1>
<p>Inspired by <a href="http://www.brendangregg.com/usemethod.html">Brendan Gregg’s USE Method</a> and <a href="https://www.weave.works/blog/the-red-method-key-metrics-for-microservices-architecture/">Tom Wilkie’s RED Method</a> I have backronymed a method. I call it <strong>the CASE Method</strong> and it defines four points that a team should consider and maintain when working with automated monitoring:</p>
<ul>
<li><a href="#context-heavy"><strong>C</strong>ontext-heavy</a></li>
<li><a href="#actionable"><strong>A</strong>ctionable</a></li>
<li><a href="#symptom-based"><strong>S</strong>ymptom-based</a></li>
<li><a href="#evaluated"><strong>E</strong>valuated</a></li>
</ul>
<p>Using CASE, an organization will have a healthy skepticism about interrupting humans. Monitoring will be evaluated regularly for value and effectiveness. Humans will have better mental models and greater confidence when alerted.</p>
<p>To get catchy for a second, the idea is that you need to make a CASE for each alert’s existence. :sunglasses:</p>
<h1 id="why-do-we-need-this">Why do we need this?</h1>
<p><a href="https://medium.com/@copyconstruct/on-call-b0bd8c5ea4e0">On call can suck</a>. There are a lot of reasons for this and CASE won’t help you fix all of them. It can, however, improve the quality of the things that wake you up in the night. Sneakily encoded into it are a number of organizational processes that may help as well.</p>
<p>I’ve found the RED and USE methods really helpful not only in building things, but also in the shared vocabulary they provide. It is my hope that CASE brings some clarity and conversation to the alerts that protect our systems and harangue our colleagues.</p>
<p>The core idea is to establish a culture in your organization where the existence of an alert is viewed with healthy skepticism. Alerts may be created for good reason, but we should be skeptical of their continued value unless it is demonstrated. What justifies this alert, and has that criteria been re-evaluated lately? CASE provides a framework for these questions.</p>
<h1 id="context-heavy">Context-Heavy</h1>
<p>Reading a jargon filled text message on your phone at 3am is hard enough at the best of times. Responding to that page effectively requires information. Optimally the information is targeted to the problem in question and helps the responder understand the system’s context as quickly as possible. In a sense, one must “design” the alert in such a way that this is possible. This is effectively the observe and orient portions of an <a href="https://en.wikipedia.org/wiki/OODA_loop">OODA loop</a>. Spending time on this design should be worthwhile, because interrupting a human being is costly and should be treated with respect.</p>
<p><img src="/assets/images/case-alerts.png" alt="Lots of things interrupt people" />
<br /><em>Lots of things cause problems. Especially ghosts.</em></p>
<p>How can we help the responder? Alerts are one of the first stimuli that an operator will receive and are therefore a strong contributor to any hypothesis generation they may do. Runbooks and dashboards are common destinations, but are they suited to the alert rather than being full of general guidance? Allspaw claims that we must “think about the way the alert could be interpreted or acted on” (slide 29)<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. A good alert is designed for the operator rather than just set at a threshold and pushed out into production.</p>
<p>To that end, here are some ideas for improved alert context:</p>
<ul>
<li>Link the user to something helpful and designed, not just to a generic runbook or dashboard. In the past colleagues and I used “investigation dashboards” that were tuned to specific alerts. This may help well known failures, but might be misleading for other things. It’s a tightrope!</li>
<li>Provide insight into the history of the alert: is it new? How often does it fire? Is it seasonal?</li>
<li>Recent change awareness: Help with system state. Has anything changed lately like a deploy or feature flag?</li>
<li>Show relationships and inform the mental model: Are the system’s dependencies clearly shown, preferably with indications of health?</li>
<li>Get the user to a team quickly: Can the responder see any in-progress incidents or determine who else in the org has already been paged? Has the <a href="https://en.wikipedia.org/wiki/Incident_management">incident management</a> program been invoked?</li>
</ul>
<p>Optimally your incident management program feeds more suggestions into how alert context can be improved as you investigate failures. We can always improve this!</p>
<h1 id="actionable">Actionable</h1>
<p>Is the responder supposed to do something in response to this notification? If action is not necessary or clear why have you interrupted them? The intent is to avoid alerts that pester the operator when no action is needed.</p>
<blockquote class="imgur-embed-pub" lang="en" data-id="u2MmRrJ"><a href="//imgur.com/u2MmRrJ">What am I supposed to do now that you've surprised me?</a></blockquote>
<script async="" src="//s.imgur.com/min/embed.js" charset="utf-8"></script>
<p><em>What am I supposed to do now that you’ve gotten my attention?</em></p>
<p>In the early days of a system when complexity is low and few people are involved we often establish monitoring as a form of informational awareness. A note saying that heap usage has grown may be a nice bit of context for us in case we see a later interruption in service. At scale this becomes unmanageable because our systems operate in various states of degradation at any time. This quickly leads to <a href="https://en.wikipedia.org/wiki/Alarm_fatigue">alarm fatigue</a> and can result in desensitization that harms an operator’s ability to respond effectively either due to ignoring or outright filtering of such notifications. Don’t fall into the trap of allowing alerts to continue, only to route them to email and then into a folder you never read.</p>
<p>These are the attributes of an actionable alert:</p>
<ul>
<li>The situation requires action, it is not merely informational.</li>
<li>There is no obvious automation for this action, or automation is unsafe. If the action can be automated, automate the damn thing and stop bothering people!</li>
<li>The situation contains urgency guidance in the form of a <a href="https://en.wikipedia.org/wiki/Service-level_agreement">service-level agreement</a> (SLA) and perhaps a <a href="https://en.wikipedia.org/wiki/Disaster_recovery#Recovery_time_objective">recovery time objective</a>. This allows the responder to enlist the help of the organization’s incident management program.</li>
</ul>
<p>To be clear I am not advocating that you <em>only</em> alert on the topmost SLOs for your API or similar. This concept of monitoring SLOs is fractal in that each service in your organization can be approached the same way. You will obviously be monitoring top level SLOs that face paying customers, but you will also monitor infrastructure SLOs like databases. Pretty quickly these become focused on internal customers and supporting them. Turtles all the way down!</p>
<h1 id="symptom-based">Symptom-Based</h1>
<p>Like it or not, you’re probably working with a distributed system (Cavage)<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>. As a result, your work is likely to employ many tactics to isolate and buffer services from failure (Treynor et al)<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup>. While pangs of high garbage collection durations or database query times might mean something is awry, these rumbles are not urgent if users are not going to experience problems either now or very soon.</p>
<p>These sorts of signals may be important and/or actionable, but if they are not causing user difficulties then they are likely not urgent enough to warrant interrupting our operator. Cause based alerts are snapshots of our mental models about system failure. It’s best to monitor important <em>symptoms</em> rather than attempting to enumerate every possible cause of failure.</p>
<p>To ensure your alerts are actionable you can focus on the <a href="https://en.wikipedia.org/wiki/Performance_indicator">performance indicators</a> that are important to your users. Ewaschuk called this aspect “monitoring for your users”. Also recall that you’ll be applying this philosophy through your entire organization. Once service in the bowels of your infrastructure begins having urgent problems, you can expect that the relevant team will be involved. Further hardening your systems against that failure is a wholly separate line of work (Treynor et al, section Strategies for Minimizing and Mitigating Critical Dependencies)<sup id="fnref:3:1" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup>.</p>
<h2 id="symptoms-change-less">Symptoms Change Less</h2>
<p>Cook reminds us that complex systems contain a multitude of flaws, faults, and problems<sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup>. If you’re trying to enumerate each of these possible causes you’ll be doing a large amount of unhelpful work that never ends. Many of the problems you’re attempting to spot will shift away over time. Sridharan says that systems are “not necessarily going to be operating while 100% healthy at any given time“ so we should focus on more “human-centric” situations (“<a href="https://distributed-systems-observability-ebook.humio.com/">Distributed Systems Observability</a>”, 7)<sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">5</a></sup>.</p>
<h2 id="avoid-incident-based-alert-debt">Avoid Incident-based Alert Debt</h2>
<p>A common incident remediation is to make an alert for a cause. This “debt” of narrowly useful alerts may create a false sense of confidence, since your system will continue to change how it fails.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">We are monitoring the SHIT out of everything but that…</p>&mdash; Honest Status Page (@honest_update) <a href="https://twitter.com/honest_update/status/867058053480427525?ref_src=twsrc%5Etfw">May 23, 2017</a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>Rather than creating a false sense of confidence from cause-based alerts, instead ask yourself:</p>
<ul>
<li>Why didn’t a symptom-based alert find this?</li>
<li>Could improved context for the responder help?</li>
<li>How can we improve our observability tooling to make this diagnosis faster rather than creating alert debt?</li>
</ul>
<p>Observability tooling for diagnosis will only improve if you consider it the means for getting from symptom to solution. Without this feedback loop you end up with a collection of reactive alerts and charts that document your past failures and none of your future ones. This provides a wonderful opportunity for an organization to shift from a reactive stance on alerting to a proactive one. It also elevates the conversation between engineering and product via common expectations and clear value. The CASE (:wink:) for any alert’s existence is clear.</p>
<h2 id="cause-based-is-ok-in-moderation">Cause-Based Is OK In Moderation</h2>
<p>Sometimes the system being monitored leaves us little choice about a cause-based alert. Other times our operators are acutely aware that the symptom will lead to imminent failure and is therefore very actionable. Maybe you just aren’t sure what’s up and set up alerts out of an abundance of caution. This need for action is hopefully temporary until the system can be modified to deal with degradation.</p>
<p>Keep the other parts of CASE in mind when dealing with these situations. Being temporary doesn’t remove the need for thoughtfulness.</p>
<h1 id="evaluated">Evaluated</h1>
<p>The changes — new code, new infra, or new… whatever — to our systems introduce new forms of failure (Cook, 3).<sup id="fnref:4:1" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup> Do we still trust that this alert works as expected? Having sharp, recent mental models of your systems and experience responding to some alerts to aid <a href="https://www.getrevue.co/profile/resilience/issues/resilience-roundup-anticipatory-thinking-issue-27-168981">anticipatory thinking</a> is a key part of a <a href="https://en.wikipedia.org/wiki/Learning_organization">learning organization</a>. Because the faults in our systems will continue to evolve, so must we.</p>
<p>We need to regularly evaluate the performance of each alert to ensure they work the way that we expect. Listen up management, you can have a strong impact helping your team establish this! Here are some ideas for how to do evaluation:</p>
<ul>
<li>Leverage <a href="https://principlesofchaos.org/">chaos engineering</a>, <a href="https://www.gremlin.com/community/tutorials/how-to-run-a-gameday/">game days</a>, or other forms of testing to ensure that alerts do what you expect. You can do this within your team without the process of larger incident management machinery!</li>
<li>Include collection of data about all relevant alerts that participated in incidents are part of your incident management program. Flag help, harm, irrelevance, confusion and more. Use this as feedback.</li>
<li>Healthy alerts fire on occasion and are well exercised. Verify that all the links work and point to relevant context, etc.</li>
<li>Alerts that never fire or that fire frequently are unhealthy. Improve or eliminate these. Be wary of both overload and underload!</li>
<li>Keep an expiration timestamp on alerts. If an alert expires, reevaluate it against CASE and update the timestamp. Think of this as a freshness date and review with your team regularly.</li>
<li>Make improvement of alerts easy. Use monitoring as code and keep your alerts in a Git repository. Pull requests help you involve the team as well and you get history for past experiences. This may help remove fear of changing the alert or getting sign off from those that “own” it.</li>
<li>Allow feedback on alerts, even if it’s just a quick <a href="https://www.google.com/forms/about/">Google Form</a> so that responders can signal an alert being unhelpful or noisy. Put a link or call to action in the body of your alert and review the feedback regularly.</li>
<li>Establish team norms that those on call have time in their schedule to improve on call during slow periods. Try and leave things better than when you found them!</li>
</ul>
<h1 id="closing">Closing</h1>
<p>I believe that the CASE method provides teams and organizations a way to discuss the care and feeding of automated alerting. A single engineer can begin evaluating alerts through the CASE lens and from that scale up to an entire org working with teams, management, and incident management programs to keep alerts groomed and valuable. It requires no fancy tools or complex process.</p>
<p>As an industry we must continue to consider the human factors of on call responsibility whilst giving our customers the best experience possible. The tools and practices that we use have a vast opportunity for improvement. I hope that CASE contributes to this improvement.</p>
<p>Bask in improved alerting!</p>
<iframe src="https://giphy.com/embed/qISaMW1xwmvNS" width="480" height="360" frameborder="0" class="giphy-embed" allowfullscreen=""></iframe>
<p><a href="https://giphy.com/gifs/bird-owl-qISaMW1xwmvNS">via GIPHY</a></p>
<h1 id="citations">Citations</h1>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p>Allspaw, John. “<a href="https://www.slideshare.net/jallspaw/alert-designcac-talk2013">Considerations for Alert Design.</a>” Monitorama 2013 Portland, OR. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>Cavage, Mark. <em><a href="https://queue.acm.org/detail.cfm?id=2482856">There’s Just No Getting Around It: You’re Building A Distributed System</a></em>. ACM Queue, 2013. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>Treynor, Ben et al. <em><a href="https://queue.acm.org/detail.cfm?id=3096459">The Calculus of Service Availability</a></em>. ACM Queue, 2018. <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:3:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
</li>
<li id="fn:4" role="doc-endnote">
<p>Cook, Richard. <em><a href="https://web.mit.edu/2.75/resources/random/How%20Complex%20Systems%20Fail.pdf">How Complex Systems Fail</a></em>. Cognitive technologies Laboratory, University of Chicago. 2000 <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:4:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
</li>
<li id="fn:5" role="doc-endnote">
<p>Sridharan, Cindy. <em><a href="https://distributed-systems-observability-ebook.humio.com/">Distributed Systems Observability</a></em>. O’Reilly Media, Inc. 2018 <a href="#fnref:5" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
</li>
</ol>
</div>
<p>
<a href="https://github.com/gphat/feedback/issues/new">
<button type="button" class="inline-flex items-center gap-x-1.5 rounded-md bg-rose-500 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-rose-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-rose-600">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5">
<path fill-rule="evenodd" d="M10 3c-4.31 0-8 3.033-8 7 0 2.024.978 3.825 2.499 5.085a3.478 3.478 0 01-.522 1.756.75.75 0 00.584 1.143 5.976 5.976 0 003.936-1.108c.487.082.99.124 1.503.124 4.31 0 8-3.033 8-7s-3.69-7-8-7zm0 8a1 1 0 100-2 1 1 0 000 2zm-2-1a1 1 0 11-2 0 1 1 0 012 0zm5 1a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd" />
</svg>
Leave Me Feedback!
</button>
</a>
</p>
<div class="p-3 shadow-md rounded-md border border-gray-200 dark:border-zinc-700">
<div class="panel-heading">
<div class="font-semibold">Like what you are reading?</div>
</div>
<div class="flex items-center gap-3">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M12.75 19.5v-.75a7.5 7.5 0 00-7.5-7.5H4.5m0-6.75h.75c7.87 0 14.25 6.38 14.25 14.25v.75M6 18.75a.75.75 0 11-1.5 0 .75.75 0 011.5 0z" />
</svg>
<p class="text-sm">Subscribe <a href="/feed.xml">via RSS!</a></p>
</div>
</div>
</article>
</div>
</div>
<footer class="mt-8 p-3 border-t border-gray-200 dark:border-zinc-700">
<div>
<div class="flex items-center justify-between">
<ul>
<li>One Mo' Gin</li>
<li><a class="hover:underline text-rose-500 hover:text-rose-600" href="mailto:cory@onemogin.com">cory@onemogin.com</a></li>
</ul>
<ul class="flex gap-3">
<li>
<a href="https://github.com/gphat">
<span class="w-4 h-4">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
</span>
</a>
</li>
<li>
<a href="https://linkedin.com/in/gphat">
<span>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/></svg>
</span>
</a>
</li>
</ul>
<p class="text-gray-400">&copy; Cory Watson. All rights reserved.
</p>
</div>
</div>
</footer>
</body>
</html>