<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
	<channel>
		
		<title>Andreas Sommer – software and health engineer – Blog</title>
		<link>https://andidog.de/blog/</link>
		<description>Writing about software engineering, health, or both combined.</description>
		<atom:link href="https://andidog.de/blog/rss" rel="self"></atom:link>
		<language>en-us</language>
		<lastBuildDate>Thu, 24 Jul 2025 00:00:00 +0000</lastBuildDate>
		<image>
			<url>https://andidog.de/static/img/logo.png</url>
			<title>Andreas Sommer – software and health engineer – Blog</title>
			<link>https://andidog.de/blog</link>
			<width>144</width>
			<height>144</height>
		</image>

		
			<item>
				<pubDate>Thu, 24 Jul 2025 00:00:00 +0000</pubDate>
				
				<title>Connecting Intermittent Explosive Disorder with diet and histamine intolerance: no more uncontrollable anger and rage</title>
				<link>https://andidog.de/blog/2025-07-24-intermittent-explosive-disorder-and-histamine-intolerance</link>
				<description>&lt;div id=&#34;preamble&#34;&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Intermittent Explosive Disorder (IED) is a disease defined by uncontrollable anger and rage, racing thoughts and other exaggerated, abnormal behavior.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Science and medical information only provides symptom descriptions for this disease, and sufferers have basically no chance to solve it. Only psychiatric medication is well-known to improve it to some extent but can have strong side effects and does not solve the cause.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;IED destroys families, relationships and probably even lifes. It&amp;#8217;s considered a rare condition, but with an estimated lifetime prevalence of 3-5%, it seems not rare at all (for comparison: ADHD is estimated at 5-10% and considered a widespread syndrome nowadays). Guess the impact that a permanent solution could have, even if it only works for a subset of affected people. I found an easily-explainable solution that worked for me ‒ mostly the dietary change of leaving out histamine-rich food items.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&#34;_table_of_contents&#34; class=&#34;discrete dog-blog-breakpoint&#34;&gt;Table of contents&lt;/h2&gt;
&lt;div id=&#34;toc&#34; class=&#34;toc&#34;&gt;
&lt;div id=&#34;toctitle&#34; class=&#34;title&#34;&gt;&lt;/div&gt;
&lt;ul class=&#34;sectlevel1&#34;&gt;
&lt;li&gt;&lt;a href=&#34;#_my_story&#34;&gt;My story&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_development_of_the_disease&#34;&gt;Development of the disease&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_detecting_ied_in_yourself&#34;&gt;Detecting IED in yourself&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_medication_and_optionally_therapy_can_be_a_good_first_step&#34;&gt;Medication and optionally therapy can be a good first step&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_measuring_symptoms_to_find_the_cause&#34;&gt;Measuring symptoms to find the cause&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#solution&#34;&gt;Histamine intolerance (HIT) is the cause, omitting histamine-rich food items the solution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_what_comes_after_the_anger_is_solved&#34;&gt;What comes &lt;em&gt;after&lt;/em&gt; the anger is solved?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_related_thoughts_and_reading&#34;&gt;Related thoughts and reading&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_my_story&#34;&gt;My story&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;…won&amp;#8217;t be detailed very much here. It doesn&amp;#8217;t matter for resolving the illness, and I want my privacy after all these years of fighting and not knowing what&amp;#8217;s going on. The goal of this article is to help others. There are many stories online to read and watch, even scientific case reports, in case you&amp;#8217;re unfamiliar with how the disease can present behavior-wise:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/@Dirtspawn064/search?query=explosive&#34;&gt;Videos&lt;/a&gt; about someone&amp;#8217;s experience with IED incl. self-harm, pet harm, hitting walls and other people, strong anger outbursts. Got better with medication. Disappointments, loud noises or getting touched mentioned as main triggers. Relation to autistic traits.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.reddit.com/r/intermittentexplosive/comments/1eh5xcy/my_30f_boyfriend_31m_has_ied_heres_some_tips_to/&#34;&gt;Description from someone about her boyfriend and what she did to help&lt;/a&gt;. On the other side, most IED stories online can rather be summarized with recommendations like &#34;leave that person&#34;. This disease easily destroys family ties if untreated.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As already mentioned in the above links, there are hints about anger symptoms relating to ADHS and autism. For instance, try searching &lt;a href=&#34;https://www.reddit.com/r/ADHD/search/?q=anger&#34;&gt;for &#34;anger&#34; on r/ADHD&lt;/a&gt; and lots of posts will pop up.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.mayoclinicproceedings.org/article/S0025-6196(12)62444-6/fulltext&#34;&gt;Case reports of Mayo Clinic patients&lt;/a&gt; (dated 1987), mostly clinical severity&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.tandfonline.com/doi/full/10.1080/14999013.2017.1365782&#34;&gt;One study&lt;/a&gt; correlates road rage incidents, aggressive criminal acts and other actions with IED (full text not available)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Not about IED, but this &lt;a href=&#34;https://www.reddit.com/r/Anger/comments/1jhoh37/what_the_most_messed_up_thing_youve_done_in_a_fit/&#34;&gt;r/Anger post&lt;/a&gt; reveals various scary stories of what people do while their brain is in anger mode&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Another health topic on a software engineering blog? Yes, normally such a switch of topics is unexpected because those computer freaks only write about their stuff. Unless health problems take over your life, you develop an analysis tool specifically to figure it all out, you become a hobby scientist and expert for your own health, ultimately find real solutions, and want to share it for the benefit of everyone out there. My analysis software, yet unpublished, again had an important stake in studying this problem, and below I&amp;#8217;ll prove once more how important data analysis and correlations are.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_development_of_the_disease&#34;&gt;Development of the disease&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Intermittent Explosive Disorder didn&amp;#8217;t really occur when I was younger. A few signs here and there when I got unnerved for small things, but overall it either didn&amp;#8217;t &#34;break out&#34; yet, or wasn&amp;#8217;t noticeable. My father had anger and rage outbursts ever since I can remember, and IED is said to possibly be genetic. I didn&amp;#8217;t want to be like him.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I got clearer symptoms only at adult age. It&amp;#8217;s impossible to say when this really started. Some problems at work annoyed me, particularly if others did stuff without taking care, resulting in me fixing the issues, for example, and I&amp;#8217;d sometimes rant about it. This could however be explained as the perfectionism of a young engineer, or by the environment the company gave me. I left the somewhat-toxic environment at my own choice, switched companies and was good for a long time, but still, the same triggers could annoy me. Stupid drivers on the road would also upset me. I can&amp;#8217;t say at all when &lt;em&gt;road rage&lt;/em&gt; started for me, but I had it to a non-extreme extent, meaning I wouldn&amp;#8217;t honk and shout at everyone, like some other people do. It mostly stayed inside my car. And then came family life and failing partnerships, creating strong social triggers for this illness. Yet, all my anger usually had a good explanation: stupid or ignorant people around me, bad relationships, a crying baby, inconsiderate drivers, clumsily forgetting where I had put my belongings in the apartment, things falling down or just &#34;everything goes wrong today&#34; kind of days, having to repeat myself when talking to others, and so on. I kept telling myself that it&amp;#8217;s those triggers which caused anger, and didn&amp;#8217;t think much of it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;There&amp;#8217;s an important distinction to make here:&lt;/strong&gt; IED presents as &lt;strong&gt;uncontrollable&lt;/strong&gt; anger and rage. Probably every healthy person gets angry about something many times in their life, maybe even many times per week depending on the circumstances. &lt;strong&gt;The difference is that someone suffering from IED goes from trigger to rage in milliseconds and doesn&amp;#8217;t have the capability to stop the bad behavior at the onset. Specifically, in your mind, you can&amp;#8217;t choose an alternative behavior. There&amp;#8217;s no time for it, and no other thoughts in your head at that time.&lt;/strong&gt; You explode, shout, rage, misbehave, and the angry feeling in your gut ‒ sometimes felt literally ‒ might only go away after a few minutes or sometimes hours. I have no clue how and when the disease developed.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_detecting_ied_in_yourself&#34;&gt;Detecting IED in yourself&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;You came to this article, so you already know or suspect that you or someone close to you has a problem. The first important part now is to know your triggers. I&amp;#8217;ve listed a few of mine above. Also, you will likely have non-triggers, that is, bad situations which you can tolerate without getting angry. For me, I was mostly fine at work except for a few occasions, I never had problems among my friends, and my anger was rather in family situations and on the road. Triggers can vary a lot, but I guess the disease is the same.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Second, you need to find out if you have a normal level of anger, for example triggered solely by your surroundings, or rather anger that is uncontrollable, pathological anger, stemming from a mental illness that needs to be fixed in your body and appears even for the smallest issue. It&amp;#8217;s super easy to always blame others, especially if you&amp;#8217;re really behaving well with other people 80% of the time. But those 80% of time don&amp;#8217;t matter if the remaining 20% are killed by your rage outbursts. Mind that it&amp;#8217;s very much possible that other people in your environment treat you badly, making you angry, and you still can&amp;#8217;t just state it&amp;#8217;s only the other person. Try to deal with, and objectively look at, yourself, as you can&amp;#8217;t change others. If your current relationship already got intoxicated by anger and stress, there&amp;#8217;s always the chance in another one and sometimes things need a fresh start.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;There seems to be no objective way to &lt;em&gt;quickly&lt;/em&gt; determine if you have the disease.&lt;/strong&gt; Nevertheless, read on to what my body&amp;#8217;s problem and the solution was… you&amp;#8217;ll see that anyone can try my dietary solution safely and thereby find out if bad behavior and outbursts turn back to healthy levels ‒ or go to complete remission (no more symptoms), as is the case for me.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_medication_and_optionally_therapy_can_be_a_good_first_step&#34;&gt;Medication and optionally therapy can be a good first step&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;I had no idea that a mental illness, caused by biochemical reasons in my body, could even be the case. I only got that last-resort idea after many years of struggling&lt;/strong&gt;, facing life consequences and trying a myriad of interventions to fix this syndrome, all without any improvements. With that idea, the logical next steps to rescue myself were to call the crisis hotline, confirm the idea of getting medical treatment, getting an emergency appointment and a &lt;strong&gt;first prescription for an antidepressive from my general practitioner doctor&lt;/strong&gt;, and then following up with a psychiatrist about the medication. (You can&amp;#8217;t imagine the effort and pain it took me to get to that simple-sounding conclusion which finally got the ball rolling.)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The psychiatrist appointment, which in countries like mine usually only happens after several weeks or months on the waiting list even in case of emergency, was honestly useless because it only confirmed that the medication was a good first treatment choice and that the psychiatrist had no idea about IED whatsoever. In fact, IED only appeared in the ICD (International Statistical Classification of Diseases and Related Health Problems) around 2016, and was mainly documented in the USA before that, described for much longer in their DSM (Diagnostic and Statistical Manual of Mental Disorders) and case/medication reports dating back to 1987 and maybe even earlier. Doctor can&amp;#8217;t do much about IED apart from prescribing antidepressives and a few other, off-label medication types. Psychiatry is a field that has almost no technical or medical options for root cause analyses, but I was still surprised that not even blood was drawn or any tests made when I was there. &lt;strong&gt;The medication I got from my general practitioner, chosen by guidelines, was quetiapine&lt;/strong&gt; (Americans know it from the brand name Seroquel), a drug affecting neurotransmitters in the brain. My dosage was 2x25 mg a day, the minimal therapeutic dose. &lt;strong&gt;Another well-known type of medications that &#34;work&#34; for IED, according to online stories and case report, are SSRIs (selective serotonin reuptake inhibitors). The beta blocker propranolol is also &lt;a href=&#34;https://www.mayoclinicproceedings.org/article/S0025-6196(12)62444-6/fulltext&#34;&gt;documented&lt;/a&gt; to help in many cases.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;My point here is: medication has been available for decades, why not try it?&lt;/strong&gt; For me, trying the pills for a while proved that 1) they do work pretty quickly and 2) &lt;strong&gt;it&amp;#8217;s in my body and not a psychological problem. That&amp;#8217;s why all the talk therapy and other attempts failed&lt;/strong&gt; in the long run. &lt;strong&gt;Therapy has a short-term positive effect that feels like starting with a new mindset, and therefore I&amp;#8217;d recommend trying it in combination.&lt;/strong&gt; It&amp;#8217;s not for me though. &lt;strong&gt;Since the medication worked to a very good extent, and symptoms reappeared when trying to lower the dose or not taking a pill for a day, I knew that it might be possible to find the actual cause in my body.&lt;/strong&gt; I think medication is a good start to quickly get rid of IED-triggered behavior. It may even work long-term if you don&amp;#8217;t experience intolerable side effects. However, mind that those medications can have serious side effects and don&amp;#8217;t treat a cause. Particularly medications affecting neurotransmitters like serotonin, dopamine and norepinephrine are well-described if you search online.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I had researched SSRIs before and was actually hoping to get one of them to try, as they are said to be highly effective within weeks, albeit sometimes with harsh side effects. It turned out that quetiapine was a similar drug I hadn&amp;#8217;t read about before, and it worked within days, not weeks. &lt;strong&gt;Not only my irritability improved a lot, but also my motivation, insomnia and how good my days felt. Racing thoughts were completely gone. I was finally &lt;em&gt;able&lt;/em&gt; to freely decide what my mind thinks.&lt;/strong&gt; It felt like seeing snow for the first time in life. My thoughts were totally calm. If I did get a small intrusive thought, I could now just decide to stop thinking about that topic! This was suddenly the case in &lt;em&gt;all&lt;/em&gt; life situations. In addition, and much more important, things wouldn&amp;#8217;t annoy me so easily anymore, and if they did, I could decide within a few seconds whether I react to it and get annoyed. Previously, I had milliseconds and the reaction was like pre-programmed, not decideable. &lt;strong&gt;That was the &#34;uncontrollable anger&#34; part of IED ‒ also gone, thanks to medication.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Eventually though, &lt;strong&gt;I was able to get rid of the medication after about 4 months&lt;/strong&gt;. At that time, I had not only, luckily, found the real cause, but also experienced &lt;strong&gt;severe and dangerous side effects&lt;/strong&gt;. There had been a few rough and somewhat-acceptable, known effects such as sedation (which subsided quickly after experimenting with intake timing), insomnia, and exacerbated restless legs syndrome (RLS; I normally have this in summer) due to the influence on dopamine. But those last weeks before quitting, I couldn&amp;#8217;t sleep &lt;em&gt;at all&lt;/em&gt; anymore, was groggy and very dizzy all day, was ready to pause my gym membership because I couldn&amp;#8217;t sustain any sports or much movement anymore, and eventually considered visiting a hospital. Particularly my lower body was physically tired in a way that I&amp;#8217;ve never sensed before. I&amp;#8217;d like to sensitize you about such risks. Almost every medication with strong main effect can also have strong side effects. Every doctor knows that, normally. I&amp;#8217;m especially considerate of anything that crosses the blood-brain barrier. These issues went away after tapering off the medication ‒ which by the way should never be done at once (&#34;cold turkey&#34;) because of the corresponding risks.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_measuring_symptoms_to_find_the_cause&#34;&gt;Measuring symptoms to find the cause&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In autumn 2024, I finally picked up the term &#34;Intermittent Explosive Disorder&#34; again for my research even though I remembered that other than some symptom descriptions, there was nothing interesting to find online when I heard of the term first around 2022. This led me to finally write down symptoms in a structured way, long-term, every day. It&amp;#8217;s not easy to find a metric that can be objectively measured and consequently written down each day without guessing (was my anger a 7 or a 9 out of 10??). The same applies to other symptoms, though, and fortunately I had years of experience writing down health symptoms from my migraine research (I fixed migraine to a good extent, see my &lt;a href=&#34;/blog/2025-05-28-fixed-my-migraine-weather-sports-headaches&#34;&gt;article&lt;/a&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The first metric I started to write down daily is &#34;inner anger&#34; on a scale of 0-3 where 1 would be annoyed feeling, 2 stronger anger, and 3 a freakout, even if it remained only in my head.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;And the second one is &#34;nice to person XYZ&#34; on a scale of 1-5, with both the day&amp;#8217;s minimum (worst behavior) and maximum (best behavior) written down, so actually two metrics. I did it for multiple close people, so I had even more data. On that scale, 1 stands for screaming, wild, unfair, outrageous behavior, 2 for very unfriendly, 3 for neutral/affirmative, 4 for friendly/nice and 5 for loving/caring/understanding behavior.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Together, this means I have one internal metric that was &#34;measurable&#34; even if I didn&amp;#8217;t shout or otherwise react to other people, and two metrics that define my externalizing behavior&lt;/strong&gt;, or in other words, how bad IED actually affected my behavior towards others, not just my thoughts. It was so incredibly stupid to start the data collection so late, as I knew that the data is the most important input for finding correlations with other conditions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;What could I now do by just having some numbers of how angry and outrageous I was? Standalone, those numbers are useless. They must be correlated with, at best, possible causes. I had lots of conditions already written down for a while due to my migraine research. For example whether I was outside in the sun, did sports, took supplements and ‒ sadly only since that autumn ‒ also what I ate on each day. After a few months, I still had no clue and also didn&amp;#8217;t find any success stories online. I tested and analyzed supplements which are supposed to help (e.g. magnesium is said to be calming), among other attempts. I spare you the details.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;solution&#34;&gt;Histamine intolerance (HIT) is the cause, omitting histamine-rich food items the solution&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I had used magnesium for years to try and combat migraine. It&amp;#8217;s recommended for a myriad of health conditions and said to have a calming effect, improve sleep and headache, yada yada. It&amp;#8217;s the holy grail supplement nowadays. Different magnesium salts have different effects and side effects, but for me, magnesium had exactly one outcome:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;div class=&#34;title&#34;&gt;Magnesium vs. anger (since writing down data, until roughly the time I figured out this negative effect, ~100 days of data)&lt;/div&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2025-07-24-intermittent-explosive-disorder-and-histamine-intolerance/magnesium-vs-anger.webp&#34; alt=&#34;Magnesium vs. anger&#34; width=&#34;1000&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Remember my scale of being nice and friendly to &#34;person XYZ&#34;? It&amp;#8217;s the main behavioral problem I wanted to improve and &lt;strong&gt;magnesium supplementation lowered my niceness score by 0.8 points! That&amp;#8217;s vastly significant.&lt;/strong&gt; (For simplicity, I combined all magnesium types and dosages into one bar in the graph since there was no difference for me.) For the &#34;inner anger&#34; metric, worsening can be seen as well, but it&amp;#8217;s not very obvious, so I&amp;#8217;m happy to have chosen an externalizing behavior metric as well. &lt;strong&gt;The more often I took magnesium, the longer the very bad effect lasted.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This was the first hint of effects from diet and supplements. I also &lt;strong&gt;tried the ketogenic diet&lt;/strong&gt; which is effective for the more well-known mental health disorders (depression, bipolar disorder, anxiety, schizophrenia, epilepsy, etc.). In short: it &lt;strong&gt;didn&amp;#8217;t help for my IED&lt;/strong&gt; (and I might have done it wrong by miscalculating the fat ratio). After starting to write down total daily fat, protein, carbohydrates and calories to help get used to keto, I extended that at some point to &lt;strong&gt;write down the foods I ate&lt;/strong&gt;. For example, my spreadsheet has one row for each meal (breakfast 1/2/3, lunch 1/2/3, dinner 1/2/3) and I&amp;#8217;d put the cooking &lt;strong&gt;ingredients&lt;/strong&gt; in there, such as &#34;pizza with flour, tomato sauce, champignons, salami, grated gouda cheese&#34;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;After several months of recording food items, I found the first food which strongly affected my anger: my beloved peanuts. Then other nuts. Actually, almost all nuts (not all are displayed below). Shit.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;div class=&#34;title&#34;&gt;Without/with certain types of nuts vs. anger (74 days of data)&lt;/div&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2025-07-24-intermittent-explosive-disorder-and-histamine-intolerance/nuts-vs-anger.webp&#34; alt=&#34;Nuts vs. anger&#34; width=&#34;1000&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The bars for &#34;I ate cashews/almonds&#34; are shown transparent because they have less than 10 days of data each, but the effect is clear: these and even more types of nuts turned out as very bad triggers for my anger. Statistically, one of course has to exclude cofactors like combinations with other foods. I did that. The data didn&amp;#8217;t lie. Ripping those favorite snacks out of my diet already helped tremendously.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;I still wasn&amp;#8217;t sure what the common denominator was, though. That turned out to be high histamine content. My &#34;bad list&#34; of foods grew to over 10 items after a few more weeks of research.&lt;/strong&gt; It was all easy after getting the initial idea and the written-down data available for every day. It&amp;#8217;s just statistical analysis and in the years before, I had already written the tool which produces the above graphs from my spreadsheet of health data (the tool will be released in a few weeks or months, I hope).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;As of June 2025, my known incompatible foods were:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;avocado&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;banana&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;blueberries&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;chocolate&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;coconut milk&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;coffee (incl. decaf)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;cream&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;eggs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;green salad&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;joghurt&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;kiwi&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;nuts (most probably all of them, but some I eat so rarely that I don&amp;#8217;t have enough data; for example brazil nuts which are anyway to be eaten in very small amounts)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;onions&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;spinache&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tea (from the actual tea plant i.e. black/green/white tea, not herbal/fruity water)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;vinegar and fermented foods (sauerkraut diarrhea, ewwww never again)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;There are very few stories on the internet saying that histamine can have an effect on your mental state and behavior, but &lt;em&gt;there are&lt;/em&gt;. And here&amp;#8217;s mine. The data proves it. &lt;strong&gt;I created a metric in my statistical analysis which tracks how many of those known-incompatible foods I ate on a day, and in retrospective, the number of portions perfectly, linearly (!) correlate with anger symptoms:&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;div class=&#34;title&#34;&gt;Incompatible foods vs. anger&lt;/div&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2025-07-24-intermittent-explosive-disorder-and-histamine-intolerance/incompatible-foods-1.webp&#34; alt=&#34;Incompatible foods vs. anger&#34; width=&#34;1000&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2025-07-24-intermittent-explosive-disorder-and-histamine-intolerance/incompatible-foods-2.webp&#34; alt=&#34;Incompatible foods vs. anger&#34; width=&#34;1000&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2025-07-24-intermittent-explosive-disorder-and-histamine-intolerance/incompatible-foods-3.webp&#34; alt=&#34;Incompatible foods vs. anger&#34; width=&#34;1000&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;It can&amp;#8217;t be more obvious than those graphs: all anger metrics are worse the more high-histamine foods I eat.&lt;/strong&gt; It&amp;#8217;s not gluten, not lactose, not some minor, usually destroyed-by-cooking toxin like oxalates ‒ it&amp;#8217;s histamine! Histamine is in many foods, can&amp;#8217;t be destroyed or dissolved by cooking and there are great lists available online that show which foods can have a high content.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Mind that not everyone has the same trigger foods. Tomatoes are listed on all web pages that discuss histamine intolerance, but for me, they&amp;#8217;re actually very positive. Maybe that&amp;#8217;s just a gift so I have at least one favorite food left that I can eat? Meat is good for me as well, luckily, because otherwise I wouldn&amp;#8217;t know anymore what to eat to get satiated.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The above data had already convinced me, but &lt;strong&gt;there were more signs that hinted at histamine&lt;/strong&gt; being the actual problem:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Since magnesium was extremely bad for me, which I still can&amp;#8217;t understand today, I tried its antagonist calcium. And indeed, &lt;strong&gt;calcium is linearly positive regarding anger symptoms! Calcium even seems to work independently from leaving out my trigger foods. I guess that it&amp;#8217;s because calcium is a potent antihistamine.&lt;/strong&gt; It was used as such in the early 20th century. The effect was very easy to observe: if I have a stuffed nose and take calcium, the nose is mostly free within 20 minutes, and the effect could last up to 3 hours. Surely there might also be a risk to high calcium supplementation, so I rather consider diet the main solution for IED, and will be very considerate about using calcium at all.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The more incompatible foods I ate, the more my nose is stuffed.&lt;/strong&gt; This relationship is also perfectly linear in my data. So the surrounding topic to research here is allergies. Not just food allergies, but also pollen and other triggers. I currently believe that heat is also a trigger. Start reading about &#34;histamine intolerance&#34; (HIT), &#34;mast cell activation syndrome&#34; (MCAS) and related topics, and you&amp;#8217;ll get into a huge world of people with extreme health trouble, with various suggested solutions.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;So in summary, leaving out food items&lt;/strong&gt; and taking calcium &lt;strong&gt;did the trick. I&amp;#8217;m still in full remission, no anger symptoms, after several months on this restrictive diet.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;If you ask now: what if the medication has fixed the problem in the long term, and not the dietary change? No, the data and my observations were absolutely clear here. Going lower than the minimal dosage of quetiapine brought back anger symptoms latest after 36 hours. Its effect only lasts while the level remains roughly constant, which is why you need to take two pills each day. While the medication reduced symptoms to a good extent, leaving out foods had a much stronger impact, namely complete remission of symptoms. &lt;strong&gt;I don&amp;#8217;t consider the medication a solution, or find it in any way comparable to the exclusion diet.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Also, I use the &lt;strong&gt;antihistamine&lt;/strong&gt; cetirizine every now and then against my pollen allergy on days with a runny nose. That &lt;strong&gt;didn&amp;#8217;t have an effect on the anger symptoms&lt;/strong&gt;. It&amp;#8217;s not surprising: antihistamine medications block certain histamine receptors, and usually not all of them; they don&amp;#8217;t influence accumulation of histamine.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This is the end of the informative part of the article. Below you&amp;#8217;ll find another optional section with my next steps to try and find the root cause for my body&amp;#8217;s overreaction to, or overaccumulation of, histamine. I don&amp;#8217;t want to miss out on great foods and drinks forever. No facts or findings in there, yet, but maybe there will be an update later. &lt;strong&gt;Good luck to you!&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_what_comes_after_the_anger_is_solved&#34;&gt;What comes &lt;em&gt;after&lt;/em&gt; the anger is solved?&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;How to ensure the symptoms don&amp;#8217;t come back? I don&amp;#8217;t really believe in histamine intolerance as standalone problem or it being the &lt;em&gt;root&lt;/em&gt; cause. I reckon it&amp;#8217;s caused by something else. And I don&amp;#8217;t want to skip eating all those great food items forever. I don&amp;#8217;t have a clear answer yet, but the research about HIT led to SIBO (small intestinal bacterial overgrowth) as a possible cause. Since SIBO is quite widespread, the possibility for me to have it seemed high, so I did a test. SIBO is a common underlying problem of IBS (irritable bowel syndrome), but I don&amp;#8217;t have any digestive or abdominal problems, or frequent flatulence from certain foods. Why do a test then if I don&amp;#8217;t have the typical symptoms? Well, let&amp;#8217;s compare that to my histamine intolerance: it&amp;#8217;s absolutely rare to get mental symptoms from too much histamine. Most people simply get allergy symptoms like skin rashes, runny nose, itchy eyes and so on. I had regular allergy symptoms as well since I&amp;#8217;m allergic to trees and grasses. This still doesn&amp;#8217;t mean you can&amp;#8217;t have other symptoms. Just because something is rare and almost completely undocumented doesn&amp;#8217;t mean it cannot happen. I&amp;#8217;m ready to do anything to fix my health issues long term. It&amp;#8217;s like in software engineering: if you do it the right way, the problem doesn&amp;#8217;t come back to you later. This explains why I wanted to test for SIBO despite not having the well-known symptoms like bloating, diarrhea and digestive issues.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The test cost around 100€ incl. return shipment of the glass vials, and debrief phone call about the results. Since doctors and insurances here don&amp;#8217;t know or cover SIBO, I paid and did all this myself. There are several labs offering tests, even in other countries. The results turned out strongly positive for hydrogen gas production. In the article &lt;a href=&#34;https://ibsandsiboclinics.co.uk/the-surprising-connection-between-histamine-intolerance-and-sibo/&#34;&gt;The Surprising Connection Between Histamine Intolerance and SIBO&lt;/a&gt;, among other sources, I found a reasonable explanation: overgrowth of bacteria in the small intestine, where naturally only a small amount of bacteria should arrive and settle, can damage the gut lining. And that in turn can lead to bad degradation of histamine by the body. There are enzymes involved in the degradation process, as you&amp;#8217;ll read in the first 5 minutes about histamine intolerance, yet supplementing the DAO enzyme didn&amp;#8217;t help in my case. Anyway, due to this finding, my current attempt is to fix SIBO and thereby maybe the root cause of histamine intolerance. The problem is that I don&amp;#8217;t have anger symptoms anymore, so it&amp;#8217;s impossible to relate the gut healing with improving symptoms. Yet I still have insomnia as very major health issue, and if my craziest theories prove to be true, then histamine keeps me from falling sleep at night, treating SIBO will fix HIT, and I&amp;#8217;ll be happy in life 🤔. Wish me luck, since this isn&amp;#8217;t much based on data or other people&amp;#8217;s experiences anymore.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I&amp;#8217;m following the recommended antimicrobial treatment: oregano oil, berberine, then probiotics, and finally gut restoration with certain supplements. I&amp;#8217;ll update this article if it improves anything. Again: I can&amp;#8217;t tell if anger symptoms improve since I&amp;#8217;m in full remission already. Plus I want to reintroduce avocado, chocolate, eggs, among other items, and not fear food any longer. The exclusion diet is said to be required only temporarily for histamine intolerance, and not required long-term for everyone.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_related_thoughts_and_reading&#34;&gt;Related thoughts and reading&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.reddit.com/r/HistamineIntolerance/&#34;&gt;r/HistamineIntolerance&lt;/a&gt; has lots of stories (but almost none about mental symptoms)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;HIT may not be the only cause of IED. In my research of the literature and online posts, correlations to ADHD (which I don&amp;#8217;t have) appeared, and I&amp;#8217;m sure many other causes are imaginable. There&amp;#8217;s unfortunately barely any helpful research about causes, at least in what I found for the term &#34;intermittent explosive disorder&#34;. Given that medication affecting serotonine or dopamine works, and histamine is now also a proven influence, it could be a complex interaction between neurotransmitter levels, still unfortunately poorly understood.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;a href=&#34;https://mastzellaktivierung.info/en/downloads.html#foodlist&#34;&gt;SIGHI list of compatible foods&lt;/a&gt; is the most used, most complete listing of potentially high-histamine foods. Remember that not all of those foods may be a trigger.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Many great webpages exist for histamine intolerance, how mast cells work (or malfunction) and what other illnesses and symptoms that can bring&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Overall, since scientific studies and papers didn&amp;#8217;t show me any potential causes, I was really happy to keep using Reddit as an alternative source of information. Yes, it&amp;#8217;s full of underwhelming, short and unexplained posts and answers by single people. But you can still get lots of ideas out of there and put them together with your own observations and theories. I must have visited dozens of subreddits with topics like antidepressive medications, depression and other mental health conditions, histamine intolerance, mast cell activation syndrome, anger, IED, etc. I highly recommend searching content on Reddit using the Google search engine and the additional search query &lt;code&gt;site:reddit.com&lt;/code&gt; since Google is still the best index. Particularly the subreddit specific to IED, &lt;a href=&#34;https://www.reddit.com/r/intermittentexplosive/&#34;&gt;r/intermittentexplosive&lt;/a&gt;, contains barely any solutions or success stories apart from medical treatment, so I hope to be able to help some folks over there. Plus hundreds of websites for those same topics which I converted to written notes. The effort was worth it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Random thought: books, guides and therapists keep talking about childhood problems, trauma, abuse, the &#34;inner child&#34;, what feeling is behind anger (hey there, cognitive-behavioral therapy!). What if functional medicine became the norm and doctors would test more people for diet or histamine-related causes? Would we find that many angry people have primarily a biochemical problem, not a psychological one?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I still don&amp;#8217;t understand why magnesium is bad for my anger even at small supplement doses. Experts out there, please enlighten me because I couldn&amp;#8217;t figure this out.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
				<guid>https://andidog.de/blog/2025-07-24-intermittent-explosive-disorder-and-histamine-intolerance</guid>
			</item>
		
			<item>
				<pubDate>Wed, 28 May 2025 00:00:00 +0000</pubDate>
				
				<title>How I mostly fixed my migraine, weather and sports-induced headaches</title>
				<link>https://andidog.de/blog/2025-05-28-fixed-my-migraine-weather-sports-headaches</link>
				<description>&lt;div id=&#34;preamble&#34;&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;After 37 years of migraine, I found a scientifically well-explained solution. It&amp;#8217;s hydration with just table salt as electrolyte. And a few additional habits to turn off the remaining headache that the salt couldn&amp;#8217;t always prevent.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In this article, I want to explain the background, and since it&amp;#8217;s a supplementary intervention without much research behind it, my data about safety and long-term efficacy after trying several variants of salt supplementation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;My last blog post was 3 years ago, as I was spending lots of private time solving health issues. This is still a software engineering blog, and software helped me figure this all out.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&#34;_table_of_contents&#34; class=&#34;discrete dog-blog-breakpoint&#34;&gt;Table of contents&lt;/h2&gt;
&lt;div id=&#34;toc&#34; class=&#34;toc&#34;&gt;
&lt;div id=&#34;toctitle&#34; class=&#34;title&#34;&gt;&lt;/div&gt;
&lt;ul class=&#34;sectlevel1&#34;&gt;
&lt;li&gt;&lt;a href=&#34;#_migraine_started_in_childhood&#34;&gt;Migraine started in childhood&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_science_principles_why_even_write_about_this_single_person_case&#34;&gt;Science principles ‒ why even write about this single-person case?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_failed_attempts&#34;&gt;Failed attempts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_the_solution_for_my_migraine_salt_at_the_right_amount&#34;&gt;The solution for my migraine: salt at the right amount&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_safety_of_the_salt_intervention&#34;&gt;Safety of the salt intervention&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_scientific_theory_of_electrolyte_imbalance_behind_migraine&#34;&gt;Scientific theory of electrolyte imbalance behind migraine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_the_end_of_the_fight_after_37_years_of_pain&#34;&gt;The end of the fight after 37 years of pain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_related_reading&#34;&gt;Related reading&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_migraine_started_in_childhood&#34;&gt;Migraine started in childhood&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;It all started with the early signs of developing a &#34;migraine brain&#34;: many nights of my childhood, I had to wake up several times to vomit. Combined with a terrible headache, of course. In adolescent years, I would often come home from school, just wanting to lie down in a dark room until the headache pain, light sensitivity and sometimes sound sensitivity ended the next morning. Surely, I missed out on lots of fun in my childhood. I don&amp;#8217;t remember when the puking part ended, but the rest never did… until I found the solution which drastically helped within a matter of weeks.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Doctors couldn&amp;#8217;t do or understand much about migraine back then. At the age of 18 or so, I still had no remedy at all. I remember a general doctor telling me: &#34;Strange, aspirine should work after 30 minutes&#34;. Of course, aspirine can be effective in some common headache types like tension headache, but barely for migraine headaches. Why would nobody ever tell me? I still tried that medication &lt;em&gt;all the time&lt;/em&gt; to no avail. The term &#34;medication overuse headache&#34; only became well-known later. At that age, I already had some theories what&amp;#8217;s triggering the illness for me, such as weather and air pressure changes, but my pure observations wouldn&amp;#8217;t help because I couldn&amp;#8217;t change the weather.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;My main symptoms are a headache developing over several hours, then in case of very strong migraine also a neck strain spreading usually on one side of my head. Once developed, I wouldn&amp;#8217;t get rid of it until waking up the next morning. Luckily, I have never experienced cluster headaches or migraine lasting several days. A visual aura happened only once, and scared me. Migraine can have many prodromes (early sign of migraine onset), symptoms with and without pain, and is therefore studied as multifaceted, allegedly hard-to-fix sickness.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;For a while in my youth, I subjectively believed that drinking coke works against headaches. Even in later years, I tried a few caffeinated and other drinks in this faith. My parents and me never collected any data. It could have proven that the sugary drink didn&amp;#8217;t help at all. I was too young and naive to get this idea, and no doctor recommended a headache journal either. All I got was two dead teeth and several root canal surgeries from all those drinks. They were available because my parents bought them all the time. Moms and dads, stop this crap!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_science_principles_why_even_write_about_this_single_person_case&#34;&gt;Science principles ‒ why even write about this single-person case?&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Doctors had no idea of migraines back then. My parents also had the average health knowledge for that era: none. And who&amp;#8217;s to blame them ‒ the 1990&amp;#8217;s were still a time in which you had no other chance but to trust experts: doctors and unfortunately also newspaper and magazine articles. The internet, open science and wide-spread, free health information by governments or even influencers all happened much later. And despite the existence of these great sources of information, many people, not just our parents&#39; generation, still don&amp;#8217;t make use of them. So as I solved my migraine by a convincing extent, I also set out to tell others about the story, and clearly document my case on this public, free website. I believe that free information is a cornerstone of modern science. There are too many commercial interests and corruption conflicting with science and its subsidization. The solution is to simply override scientific malpractice by single people&amp;#8217;s experience-based, anecdotal, and in my case data-backed, solutions. That&amp;#8217;s my personal rationale behind this article and also behind the things I&amp;#8217;ll write about next: free information gives people the power to fix their health.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Obviously, my solution may not work for everyone else. But you&amp;#8217;ll read below that salt supplementation wasn&amp;#8217;t my own idea. A whole Facebook group is dedicated to a related protocol and has helped an unknown number of people. There are forums and groups for many illnesses, which is a great way to discuss your specific symptoms. These groups are usually structured by questions and comment threads and, only if you&amp;#8217;re lucky, clear instructions on what to try against the respective illness. They are however not an easily, publicly accessible and searchable way to find information about migraines. I&amp;#8217;m therefore trying to put together the major parts in a concise way, even if I only have data and proofs for my single case.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_failed_attempts&#34;&gt;Failed attempts&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;openblock image-float-left&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;div class=&#34;title&#34;&gt;French fries: &lt;strong&gt;not&lt;/strong&gt; a healthy, permanent solution&lt;/div&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2025-05-28-fixed-my-migraine-weather-sports-headaches/mcdonalds-french-fries.webp&#34; alt=&#34;French fries&#34; width=&#34;260&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;By the age of 25, I hadn&amp;#8217;t tried much apart from aspirine and triptans, in the hopes that some unproven &#34;blood pressure in the brain vessels&#34; theory plays out somehow. No medication really worked, and regularly buying a pack of 2 (stupid package size!) triptan pills at a horrendous price therefore wasn&amp;#8217;t justified. Instead, I toughened up, so-to-say, not letting migraine days ruin my activities. They of course still did, because you can&amp;#8217;t fully focus on work or hobbies, nor do sports with a full-blown migraine. The acceptance however worked somehow on the psychological level to weaken its position as a miserable part of my life.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In 2021, four years ago, me now aged 34, I somehow got the idea of writing down daily symptoms in a spreadsheet, as an attempt to get the headache and other symptoms solved. Not long after, my mouth ulcers were gone after trying out several interventions (hint: use SLS-free toothpaste). So I considered &lt;em&gt;data&lt;/em&gt; as a great way to correlate symptoms, interventions and with that, potentially solve health issues. I continued, switched from paper spreadsheets to a huge Google spreadsheet, tried out more and more supplements and stuff in order to solve my main concern at the time ‒ the migraine headache and accompanying neck pain.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;My strongest migraine attacks would usually come with strong neck pain, slowly spreading into my head. Many migraineurs have &lt;strong&gt;prodromes as first symptoms&lt;/strong&gt;, and the headache appearing as last, most severe symptom. Prodromes let you predict that you get a headache, so the typical advice &#34;know your triggers&#34; should be extended to &#34;know your triggers and prodromes&#34;. The nausea and light sensitivity from my youth are also well-known prodromes. &#34;Feeling&#34; weather changes is another one. I&amp;#8217;d know in most cases if a strong headache develops over the next hours, but simply didn&amp;#8217;t know how to prevent it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;openblock image-float-right&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;div class=&#34;title&#34;&gt;Example spreadsheet with health data (simplified, contrived)&lt;/div&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2025-05-28-fixed-my-migraine-weather-sports-headaches/example-sheet.webp&#34; alt=&#34;Spreadsheet&#34; width=&#34;480&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Before having tried any interventions, when I started to write down how strong my headache was each day, I had a headache (of any severity) &lt;em&gt;every third day&lt;/em&gt;, 120 out of 365 days!&lt;/strong&gt; Life sucks, eh? Many of those were also full-blown migraine attacks. &lt;strong&gt;The way I wrote them down in my log was easy: 0=no headache, 1=weak headache, 2=medium and already quite painful, 3=ruining my day. With this data, analyzing the monthly/yearly count of headaches, and their average severity, was the next logical step.&lt;/strong&gt; As a software developer, I wrote my own small program to analyze my spreadsheet data. That gave answers about whether I have more or less headache if I drink apple juice, take supplements, do sports, had alcohol, etc.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I also got enthusiastic about reading scientific studies around the topic. Which remedies exist? What supplements and dietary interventions could I try? I became focused on trying vitamin D, magnesium, eating enough food because skipping meals is a trigger for me, etc. And indeed, the year 2022 turned out to have 22 headache days less than the year before. Or in words: from every third day to roughly every fourth day! Quite a success, I thought, not yet knowing that long-term health issues can be solved much better.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;In 2023, I tried many more supplements&lt;/strong&gt; from scientific literature and ideas from the internet. For migraine, you quickly find a plethora of things to try. Apart from &lt;a href=&#34;https://www.reddit.com/r/migraine/search/?q=McDonalds+fries&#34;&gt;r/migraine&amp;#8217;s top recommendation of salty McDonald&amp;#8217;s fries&lt;/a&gt;, you&amp;#8217;ll find quite some &lt;strong&gt;substantiated evidence in favor of several supplements, for instance coenzyme Q10, vitamin B2 (riboflavin), vitamin D or magnesium&lt;/strong&gt;. And of course modern medication such as triptans or monoclonal antibody medications like Erenumab. Food triggers are also listed for a small percentage of migraineurs, but I hadn&amp;#8217;t considered that at the time. Of those data-backed suggestions from science, and countless comments from other people on Reddit, I picked the ones which made sense to me. Since either or both of Vitamin D and magnesium seemed to help, I was eager to find other supplementary or lifestyle interventions to help my pain. Regular sports was one of the things I kept evaluating. I did neck stretches, neck strengthening with weight training, avoiding the valsalva maneuver (breath-holding) during training, different magnesium supplements and higher dosage, caffeine and electrolyte drinks, other supplements. My improvements from the previous year remained, likely because I was still using vitamin D and magnesium, but boy did this take a vengeance&amp;#8230;&amp;#8203; &lt;strong&gt;higher doses of vitamin D (2000-5000 IU/day), taken over a long time, left me with permanent, severe dizziness over several months&lt;/strong&gt;, useless neurologist appointments, their new distracting theories of &#34;vestibular migraine&#34;, and so on. By looking into my spreadsheet, I could luckily see that I had raised the dosage before this occurred, and fully tapered off vitamin D to get rid of the dizziness. The body buffers vitamin D, so even after taking a small daily dose, I kept seeing symptoms. If you check online information, vitamin D is hyped as the world savior and high doses often mentioned as safe. That&amp;#8217;s simply not true for everyone! This definitely made me trust N&amp;gt;1 science (studies on many subjects) less in the future, now equally taking single case studies and experience reports (&#34;N=1 science&#34;) more into account. Reddit in particular turned out as great source for real people reporting about their health problems and solutions. Unfortunately, the average internet user doesn&amp;#8217;t really detail their story at all, and health still remains individual. Anyway, internet answers can be great hints of possible illness causes that you didn&amp;#8217;t consider before.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;My research on migraine-related neck pain also misled me: my neck training sessions turned out as potential trigger of migraine, mostly since I was lifting heavy weights (up to 15 kg / 33 lbs). DOMS in the neck is a one-of-a-kind experience that not everybody gets in their life, and it surely made me stronger, but it didn&amp;#8217;t make the headache much better in the long run, and definitely worse on training days. Another wasted effort to follow this idea, as so many before. The below section on the scientific theory will explain why migraine doesn&amp;#8217;t originate in the neck. I consider neck pain as secondary symptom or prodrome of my migraine.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;But I insisted to follow the obvious observations: &lt;strong&gt;intense sports were still triggering my headache. A common term for this is &lt;em&gt;exercise-induced headache&lt;/em&gt;&lt;/strong&gt; and it can have various causes. After a lower back injury in the gym end of 2023, I reconsidered how I do my training. I wasn&amp;#8217;t really following common advice, even though it was known to me. I was weak in my back, but luckily smart enough to use the safety bars. Therefore, I didn&amp;#8217;t destroy my life but was able to recover the muscle which just shut off during squats. Upon resuming strength training, I now always warm up for 5 minutes on the treadmill. I switched to exercises on safer machines and did Andy Galpin&amp;#8217;s &#34;3 by 5&#34; protocol (as advertised by Andrew Huberman), meaning 3-5 repetitions, sets, minutes of break, etc. On top, I started with real &lt;em&gt;progressive overload&lt;/em&gt; training, increasing the weight whenever I was ready to do more than 5 reps of the previous weight. Writing down the weights in a spreadsheet was again a good solution. A digital spreadsheet makes it easy to change exercises, hide the ones currently not in my plan, and so on. &lt;em&gt;Google Spreadsheet&lt;/em&gt; comes with a good mobile app, so that&amp;#8217;s my preferred tool. &lt;strong&gt;With the warmup, breaks and safety changes, the average headache severity reduced even more.&lt;/strong&gt; Hard to quantify how much, since just a few months later, beginning of 2024, I had finally found the best-yet fix ‒ the salt intervention. &lt;strong&gt;Overall, in 2023, I was down to 83 headache days, i.e. one every 4.4 days.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;openblock image-float-left&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;div class=&#34;title&#34;&gt;An electrolyte product I tried&lt;/div&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2025-05-28-fixed-my-migraine-weather-sports-headaches/dextro-electrolytes.webp&#34; alt=&#34;An electrolyte product&#34; width=&#34;120&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Electrolytes were an often mentioned topic on the internet and in some studies about exercise-induced headache, so I researched it further. I tried apple juice soda and other rather natural sources which didn&amp;#8217;t help, and later sports mixtures containing sodium, potassium and sometimes magnesium. Unfortunately, here comes a crux of analyzing preventative drugs or supplements: if you only take them when there&amp;#8217;s a trigger (for me: sports) or you feel a prodrome (for me: noticing a weather change), you can&amp;#8217;t really find out if it helps unless there&amp;#8217;s a super-significant difference. &lt;strong&gt;Interventions must be tried in a &lt;em&gt;preventative&lt;/em&gt; fashion over the course of at least some weeks.&lt;/strong&gt; Headache frequency without electrolytes after sports was 20.1% in 2023, but &lt;em&gt;with&lt;/em&gt; electrolytes it was worse at 36.8%. This proves nothing. In order to look at long-term effects, I also looked at &#34;with/without supplement on at least X out of the last Y days&#34;. And indeed, if I took electrolytes after sports on 3 out of the last 7 days (this also means sports 3x a week), the risk of a headache (20.8% in 2023) would even be slightly less compared to not taking them (23.1%). Fine, those results wouldn&amp;#8217;t make anyone jump and say that electrolytes are any effective. Such a small difference just isn&amp;#8217;t significant.&lt;br&gt;
&lt;strong&gt;However, I was lucky to also have analyzed only the highest headache severity separately ‒ and of those debilitating days, I had &lt;em&gt;zero&lt;/em&gt; when taking electrolytes after sports in 3 out of the last 7 days. Getting rid of the worst days of my daily life was a big finding, end of 2022. This was the first time when I had a clear hint about electrolytes being involved.&lt;/strong&gt; The finding was in a small time frame and only on sports days, though. It yet didn&amp;#8217;t prevent migraine overall.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Regarding weather-induced headaches:&lt;/strong&gt; the triggering weather pattern never became clear to me until I analyzed air pressure information of my location. What if it was air pressure change? That would turn out as true in my data: days with pressure increase had somewhat higher risk of headache. But it doesn&amp;#8217;t matter, as attacks could happen on days with sunshine turning to rain, rain turning to sunshine, air pressure changing in any direction. Only the probability is different, but every day is a potential migraine day! I stopped writing down the useless weather information at some point. We can&amp;#8217;t change the weather.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Those years of reading scientific papers, social media reports of real people trying interventions took a lot of my private time. It became a full-blown hobby. The average severity (my daily headache score between 0 and 3) went down from 0.57 in the year 2021, to only 0.38 in 2023. Significant, but not life-saving. However, I wouldn&amp;#8217;t know how to do it differently. Doing nothing would have changed nothing at all. Was it all a failure? I don&amp;#8217;t think so. Learning about a hundred failed attempts that don&amp;#8217;t work taught me a lot about scientific methods, real-world statistics, making logical conclusions, following the obvious instead of miniscule and pseudoscientific hints, and that apple juice &lt;strong&gt;isn&amp;#8217;t &lt;em&gt;really&lt;/em&gt; a working electrolyte even if I had the feeling that it works. Subjective feelings all turned out as false or even negative, so writing down and objectively evaluating and graphing my statistics was a good course of action.&lt;/strong&gt; As of 2023, my homegrown analysis app had to analyze many symptoms against many conditions and produced a huge table of correlation percentages that I starred at for hours to see significant effects of supplements and other attempts. This made no sense anymore. Each analysis took 10 minutes already as the program was poorly developed and slow, not meant for long-term usage. I set out to rewrite it in another programming language, add a web page to control what I want to analyze, and to visually show graphs for correlations of symptoms vs. interventions. I&amp;#8217;m going to publish that application in the next months, and believe it&amp;#8217;s a quite good biohacking and health optimization tool for people who are happy entering daily data into a spreadsheet.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Despite the failure to fix headache in those previous years, I consider these years a success. They turned me into a hobby scientist dedicated to my own health, and I became interested to use this for the good of other people&lt;/strong&gt;, too, resulting in this blog article, for instance. The fix for migraine came in 2024, and later, in 2025, I would even be able to put a decades-long mental disease into remission with the help of health data collected in my ever-growing spreadsheet. But that&amp;#8217;s for a later blog post, if I ever dare to share that story.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_the_solution_for_my_migraine_salt_at_the_right_amount&#34;&gt;The solution for my migraine: salt at the right amount&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The results in the years 2021-2024:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2025-05-28-fixed-my-migraine-weather-sports-headaches/headache-stats.webp&#34; alt=&#34;Headache statistics over the years&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The graph doesn&amp;#8217;t show the severity of the headache days, only the count. You can see the dip from 83 headache days in 2023 to only 32 headache days in 2024, the year in which I started supplementing salt. That&amp;#8217;s only one headache every 11.4 days! The average severity, not shown here, reduced from 0.38 to 0.15 (as mentioned above, I wrote down severity as score between 0 and 3 where 0=no headache, 1=weak headache, 2=medium and already quite painful, 3=ruining my day). In 2024, I only had 7 days of full-blown migraine. Numbers, numbers&amp;#8230;&amp;#8203; they are critical to health science, but don&amp;#8217;t nicely translate to what they mean for my life. &lt;strong&gt;The successful change in 2024 allowed me to finally consider migraine fixed to an extent that doesn&amp;#8217;t make me fear it anymore. I am so happy and thankful for that.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I can only imagine what this could mean for people who have a really strong migraine problem. I have almost never experienced multi-day migraine. Mine mostly resolved overnight, but some folks even have episodes lasting weeks! Whether this solution works for you or not, I think it&amp;#8217;s well worth the little effort to try it for a few weeks.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;As mentioned, &lt;strong&gt;the main change is to drink a tiny amount of salt each day&lt;/strong&gt;. If the scientific explanation holds true, there&amp;#8217;s a good chance that &lt;em&gt;certain&lt;/em&gt; types of migraine may have a root cause related to sodium-potassium imbalance in nerve cells and therefore supplementing with a &lt;em&gt;safe&lt;/em&gt; dose of table salt could work for many people. There are unfortunately many types of headache in the &lt;a href=&#34;https://ichd-3.org/&#34;&gt;International Classification of Headache Disorders (ICHD)&lt;/a&gt; for which I cannot provide any insights. &lt;strong&gt;There&amp;#8217;s however enough information on the internet to distinguish the vastly different &#34;regular&#34; tension headache from migraines, so I don&amp;#8217;t explain that here. This article is about migraines, and headache as their most typical and most painful symptom. I&amp;#8217;m not a doctor and not giving medical advice here, so treat and try all information &lt;em&gt;at your own risk&lt;/em&gt;. Below, you&amp;#8217;ll find a section about safety, for good reasons.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Science provides many theories and even more recommendations for migraine, with some of them making obvious sense (such as weather changes and exercise inducing headache), but no clear &#34;cause X? use remedy Y!&#34; findings, or explanations why there are so many different triggers. Most people with migraines are left with barely working medicine such as painkillers, aspirine, triptans or supplements (e.g. magnesium, CoQ10). With those, they get a few percent of improvement in headache days, as I experienced in my own story above, but no life-changing outcomes. And most importantly, those treatments aren&amp;#8217;t preventative, but curative and often applied only on pain days, usually too late after the root cause has already developed in the body. Funnily, if you do statistics like me, you may get surprising results such as headache being worse on days when you took ‒ for example ‒ aspirine. That&amp;#8217;s easily explained: you don&amp;#8217;t take aspirine as preventative measure (I hope you don&amp;#8217;t; ever heard of &lt;em&gt;medication overuse headaches&lt;/em&gt;??!), but only when you feel pain already. So statistically, headache severity will very likely be higher on those days, making the statistic totally useless because the data can&amp;#8217;t answer if aspirine worked for you. You need to try a preventative, at best cause-treating intervention over a longer period of time, and can probably ditch medication at some point.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;This is the intervention that works for me &lt;em&gt;now, long-term&lt;/em&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Drink around least 2.5 liters (85 oz) of &lt;strong&gt;plain water&lt;/strong&gt; every day. I live in a country with clean, unchlorinated tap water, so I&amp;#8217;m using that. See below for my data about headache vs. water intake ‒ I highly recommend finding your own optimum amount! On sports days, my body automatically demands more. I mostly don&amp;#8217;t drink tea or coffee. I have an insufficient amount of data hinting that tea (black/green/white i.e. from tea plant, not herb/fruit tea) might be very positive for my headache, but such diuretic drinks make me pee very often, and both tea and coffee contain histamine which isn&amp;#8217;t for me. Hence I&amp;#8217;m skipping them for non-migraine reasons.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I &lt;strong&gt;add less than a quarter tea spoon of table salt&lt;/strong&gt; (¼ tea spoon ≈ 1.25 g NaCl alias sodium chloride ≈ 0.5 g sodium) &lt;strong&gt;to every 1-liter bottle&lt;/strong&gt; that I drink. After some days, it doesn&amp;#8217;t taste salty at all anymore. I found that the body buffers sodium, so the absolute amount over several days is more important than weighing the exact mass.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Watch out for concerning symptoms&lt;/strong&gt;, see the section &#34;Safety of the salt intervention&#34; below!&lt;/p&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That&amp;#8217;s why I reduced from ¼ tea spoon to basically just a pinch of salt per liter:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;div class=&#34;title&#34;&gt;Less than a quarter table spoon suffices for me&lt;/div&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2025-05-28-fixed-my-migraine-weather-sports-headaches/this-much-salt.webp&#34; alt=&#34;Pinch of salt&#34; width=&#34;500&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;At first, it took some weeks to notice much fewer days with headache or headache onset. I started the intervention in January 2024 and still got 7 headache days in that month. In March and April, I was down to only 2 headache days each month. Incredible!&lt;/strong&gt; Since the effect doesn&amp;#8217;t come from one day to another, it doesn&amp;#8217;t feel like a miracle cure but I only realized after some weeks that something was strongly improved in my life. This wasn&amp;#8217;t the end of the story though, so please read on about the safety research I did. And if you&amp;#8217;re still interested by then, there&amp;#8217;s a section at the end explaining what the theory behind this solution is, and how a large group of people may already have known, and benefited from this for over 10 years. It felt bad for me that the knowledge was out there on the internet all the time, me having no clue about it. My migraine could have been solved many years ago.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;A common recommendation is to drink lots of water together with electrolytes, but my own data says that &lt;strong&gt;drinking too much&lt;/strong&gt; is bad for my headaches:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;div class=&#34;title&#34;&gt;Headache severity (0-3) vs. water intake in milliliters (data from 2024-06-01 to 2025-05-27; insufficient data for the [3500,4000) ml bucket)&lt;/div&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2025-05-28-fixed-my-migraine-weather-sports-headaches/stats-2025-05-27-headache-vs-water.webp&#34; alt=&#34;Graph&#34; width=&#34;700&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;For the probability of feeling any migraine prodrome on a day, the results are similar:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;div class=&#34;title&#34;&gt;Prodrome probability (0 or 1) vs. water intake in milliliters (data from 2024-06-01 to 2025-05-27; insufficient data for the [3500,4000) ml bucket)&lt;/div&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2025-05-28-fixed-my-migraine-weather-sports-headaches/stats-2025-05-27-prodrome-vs-water.webp&#34; alt=&#34;Graph&#34; width=&#34;700&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;For me, 2000-2500 ml of water might be optimal, with more water making it worse. I can only guess that dilution could be the problem. Important: I only analyzed the same-day water intake. For example, if I analyze headache vs. &lt;em&gt;yesterday&amp;#8217;s&lt;/em&gt; water intake, the results are similar, but less pronounced. Also, I only consider salted water here and not which other electrolytes I did or didn&amp;#8217;t take with it, such as magnesium. Significant linear-looking relationships in my data however often turned out as meaningful, so I go with roughly 2500 ml as my optimal amount, with more on sports days.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Intense sports or a full-day in a sauna and thermal spa can still evoke rather strong headaches for me.&lt;/strong&gt; I haven&amp;#8217;t figured this out fully and can&amp;#8217;t claim a great remedy just yet. I&amp;#8217;m wondering if electrolyte imbalance could explain those triggers as well.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Here are some additional recommendations:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hydration means water + electrolytes.&lt;/strong&gt; Electrolytes include sodium, potassium, magnesium and possibly other micronutrients if you&amp;#8217;re deficient. It&amp;#8217;s important to hydrate the day &lt;em&gt;before&lt;/em&gt; sports or another intense event, and then also during that day. Pee color and times-on-toilet are said to be good hints about over-hydrated vs. under-hydrated status, but I didn&amp;#8217;t research if that&amp;#8217;s true. Sugar-free electrolyte supplements might work as well, but don&amp;#8217;t overdo potassium supplementation since getting that from food is safer than drinking it all at once (&lt;a href=&#34;https://www.ncbi.nlm.nih.gov/books/NBK545424/&#34;&gt;article about potassium toxicity&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Warm up before sports&lt;/strong&gt;. My data doesn&amp;#8217;t show much benefit of warmup regarding migraine risk, but it reduces injury risk for sure. It&amp;#8217;s a no-brainer. Overall, my gym sessions are now long, structured, and with breaks, rather than intense 30-minute workouts that make me totally tired for the rest of the day.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I take &lt;strong&gt;breaks during sports, so that my heart rate doesn&amp;#8217;t go over a certain threshold&lt;/strong&gt; (for me: 170 🤷). This idea isn&amp;#8217;t data-backed; I only have a subjective clue that this could raise migraine risk on that day. I have a pretty high heart rate overall, typically at least 160 for &lt;em&gt;any&lt;/em&gt; speed of running and also with other cardio sports. The more volume (~ repetitions multiplied by weight), the higher the heart rate spikes will be. I&amp;#8217;m avoiding that by taking breaks, especially for compound/leg exercises, since those seem to require the most energy and therefore strongest heart pumping.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Another &lt;strong&gt;trigger: skipping a meal&lt;/strong&gt;. If intermittent fasting isn&amp;#8217;t good for you, leave it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In a &lt;strong&gt;sauna/thermal spa&lt;/strong&gt;, there are often very warm temperatures. Some indoor pools offer &#34;warm water days&#34;. Both &lt;strong&gt;warm air and water can quickly raise your body temperature&lt;/strong&gt;, while the body tries to stay in a small range of feel-good temperatures. So cool down outside or in the ice bath more often. Don&amp;#8217;t hop from sauna to sauna, and don&amp;#8217;t remain in the warm water or warm air without a cooldown break.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make typical modern health improvements: &lt;strong&gt;ditch alcohol and carb-loaded drinks (also alcohol-free beer), eat fresh, little-processed and rather low-carb food&lt;/strong&gt;. Alcohol screws up sleep and muscle growth. In my experience, the headache from alcohol hangover seems to be a different type from migraine, and should be avoided in addition. I noticed that &lt;strong&gt;certain, highly-processed foods gave me a headache within minutes&lt;/strong&gt;. That only happened rarely to me, but the trigger was obvious.&lt;/p&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I haven&amp;#8217;t written down food macros for long enough, but my current data shows that I should probably avoid a high-carb diet:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;div class=&#34;title&#34;&gt;Headache severity (0-3) vs. eaten carbohydrate amount on a day (data from 61 days of food data, year 2025, scores 0-3)&lt;/div&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2025-05-28-fixed-my-migraine-weather-sports-headaches/stats-2025-05-27-headache-vs-carbs.webp&#34; alt=&#34;Graph&#34; width=&#34;700&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In fact, the &lt;em&gt;Stanton Migraine Protocol&lt;/em&gt; which I&amp;#8217;ll mention in the next sections, recommends low-carb nutrition. I tried going low-carb/keto and it&amp;#8217;s definitely helpful to feel satiated for longer and not having to cook all the time. I&amp;#8217;d recommend it independently of my migraine research and data.&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you feel a headache coming up despite salt supplementation, there&amp;#8217;s still the chance to stop its progression. Put the aforementioned amount of salt on a table spoon, place it under your tongue and let it dissolve. The strong salty taste is a special experience you shouldn&amp;#8217;t miss. I&amp;#8217;m joking. If you&amp;#8217;re not too late, this can still make a difference on the same day. For me, it can sometimes still fight the onset, but it adds to the absolute amount of ingested salt, so safety is a concern.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sunstroke can lead to a similar, unstoppable headache as with migraine&lt;/strong&gt;, but this one is actually dangerous. It&amp;#8217;s often also associated with nausea, similar to alcohol hangover. The solution is simple: &lt;strong&gt;avoid long exposure of the head to strong sunlight&lt;/strong&gt;. A baseball cap can be enough on certain days. Shadow is best. And mind that air temperature and sunlight intensity aren&amp;#8217;t much related. You can easily get a sunburn or sunstroke in winter, just like solar panels can create lots of electrical energy despite freezing temperatures. Estimate sunlight energy, not temperature.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That&amp;#8217;s it ‒ some changes are simple, especially the salt part, and some take more effort and knowledge, like the dietary part. Mind that the intervention does not cure your migraine illness; it only prevents it, sorry!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_safety_of_the_salt_intervention&#34;&gt;Safety of the salt intervention&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The so-called &lt;em&gt;Stanton Migraine Protocol&lt;/em&gt;, one of the sources recommending salt ingestion in water as migraine remedy, prescribes a larger amount of salt. I initially salted each glass of water as suggested. At some point though, &lt;strong&gt;dizziness symptoms&lt;/strong&gt; started. With my previous dizziness phase caused by vitamin D (see my story above), I was already aware that the attempted interventions could be the likely culprit. And indeed, it turned out as too much salt which triggered the dizziness! (I&amp;#8217;m not taking vitamin D anymore, so that was ruled out.)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Eating more potassium, or supplementing with a 2:1 sodium-potassium salt mix instead of table salt, didn&amp;#8217;t change that.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Regarding the safety of sodium salt in general: &lt;a href=&#34;https://www.thelancet.com/journals/lancet/article/PIIS0140-67361630467-6/abstract&#34;&gt;too much and too little sodium both correlate with higher mortality&lt;/a&gt;. The WHO &lt;a href=&#34;https://www.who.int/news-room/fact-sheets/detail/sodium-reduction&#34;&gt;recommends&lt;/a&gt; reducing salt intake from the statistical average to less than 5 g/day salt (= 2 g elementary sodium). With processed foods, it&amp;#8217;s easy to get over that threshold, with fresh foods not at all. You&amp;#8217;ll need to judge your individual intake and read food labels.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Since experiencing dizziness, I tried a few variations of salt dosing. &lt;strong&gt;For a while, I turned back to not salting my water while still drinking 2.5 to 3 liters of water a day and keeping other things roughly the same as well. I tried without salt supplementation several times, as a &lt;a href=&#34;https://en.wikipedia.org/wiki/Crossover_study&#34;&gt;crossover experiment&lt;/a&gt;, and it seems that my body has roughly a 10-day buffer. After that, my headaches come back, but dizziness subsides.&lt;/strong&gt; These repeated, identical results also prove that the salt really works as preventative intervention. I didn&amp;#8217;t want dangerous side effects like dizziness, so I reckoned that taking much less salt, or every second day, might do it as well. So what works for me right now, as written above, is to dissolve only a pinch of salt per liter, several times a day. Less than a quarter tea spoon of table salt.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I&amp;#8217;ll keep testing this. In contrast, I&amp;#8217;m not writing down and analyzing dietary salt intake, but that&amp;#8217;s an option, too. &lt;strong&gt;Overall, my recommendation is to not treat the salt intervention as a perfect, final solution, and to observe whether it works for you without side effects.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;By the way, very intense gym sessions still give me temporary dizziness, independent from salt intake. It&amp;#8217;s a complex symptom.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_scientific_theory_of_electrolyte_imbalance_behind_migraine&#34;&gt;Scientific theory of electrolyte imbalance behind migraine&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;When I found electrolytes as possibly related to my headache, I didn&amp;#8217;t know much about brain neurology yet. That changed quickly. Angela Stanton, with her neuroscience background, pioneered both in creating a reasonable scientific theory and in bringing awareness to people about what works. Being a decades-long migraine sufferer herself, she&amp;#8217;s much more believable than strange healing stories on the internet. Creating a Facebook group for healing migraine, in which, as of 2025-05, around 19000 people have joined, takes dedication.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That said, I particularly like the neurons&#39; electrolyte imbalance theory as described in her book and articles. Here, I&amp;#8217;m summarizing a few resources:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://stantonmigraineprotocol.com/2021/12/06/migraine-treatment-and-prevention-by-the-stanton-migraine-protocol/&#34;&gt;Definition of Migraine&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Migraine is genetic, and a &#34;migraine brain&#34; is different than a healthy one. Problems with sodium/electrolyte homeostasis (balance) leads to different electrical properties, and that is critical for nerve cells (neurons).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Restricting carbohydrate consumption can improve electrolyte balance&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hydration isn&amp;#8217;t drinking lots of water&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Other possible triggers, e.g. weather changes, menstrual cycles, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Recommendations for salt intervention during air pressure increase/decrease&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.frontiersin.org/journals/nutrition/articles/10.3389/fnut.2024.1367570/full&#34;&gt;Specifically formulated ketogenic, low carbohydrate, and carnivore diets can prevent migraine: a perspective&lt;/a&gt;&lt;br&gt;&lt;/p&gt;
&lt;div class=&#34;paragraph title&#34;&gt;
&lt;p&gt;Front. Nutr., 30 April 2024, Sec. Nutrition, Psychology and Brain Health, Volume 11 - 2024, https://doi.org/10.3389/fnut.2024.1367570&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;An overview paper for her theory and what&amp;#8217;s behind it. The abstract greatly summarizes it and I have nothing to add to this great article.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;quoteblock&#34;&gt;
&lt;blockquote&gt;
This article presents a hypothesis explaining the cause of migraines, suggesting that electrolyte imbalance, specifically a lack of sufficient sodium in the extracellular space of sensory neurons, leads to failed action potentials. The author argues that migraines are triggered when sodium channels fail to initiate action potentials, preventing communication between neurons. The article discusses the evolutionary perspective of the migraine brain, stating that migraineurs have a hypersensitive brain with more sensory neuronal connections, making them more reactive to environmental stimuli and in need of more minerals for the increased sensory neuronal communication. Since glucose is often used to reduce serum hypernatremia, it follows that a high carbohydrate diet reduces sodium availability for use in the brain, causing an electrolyte imbalance. Low carbohydrate diets, such as ketogenic, low carb-high fat (LCHF), and carnivore (all animal products), can be beneficial for migraineurs by reducing/eliminating carbohydrate intake, thereby increasing sodium availability. In support, many research papers and some anecdotal evidences are referred to. The article concludes by proposing lifestyle modifications, such as dietary changes and sodium intake management. These will provide migraineurs with a long-term healthy metabolic foundation helping them to maintain strong nutritional adherence and with that aiding continued proper neuronal functioning and migraine free life.
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The book &#34;Fighting The Migraine Epidemic: A Complete Guide: How To Treat &amp;amp; Prevent Migraines Without Medicine&#34; was the first thing I&amp;#8217;ve read. It&amp;#8217;s much longer than the above resources, but worth a read for migraineurs or relatives, such as parents trying to help their kids, as the book is written for everyone (not just scientists). If you want to check out the complete protocol, the go-to places would be the book and the &lt;a href=&#34;https://www.facebook.com/groups/MigraineSufferers/&#34;&gt;Facebook group&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Hint: I&amp;#8217;m not advertising. Science should be as open, free and without financial interests as possible. It&amp;#8217;s just fair and important to mention my sources of information. If there&amp;#8217;s a sold book along a plethora of freely available resources from one scientist, that&amp;#8217;s totally fine. I could offer my endless writeup of &lt;em&gt;other&lt;/em&gt; resources from the last years. I must have read thousands of web pages and full-text studies. This article is already too long to list and explain everything. Therefore I refer to sources that give explanations in a single place, and which influenced me the most.&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The sodium-potassium homeostasis explanation makes sense to me. But I can&amp;#8217;t tell if it&amp;#8217;s the correct explanation. And it doesn&amp;#8217;t matter. The result ‒ getting rid of migraine pain ‒ is more important, as long as the intervention is safe to use. That said, I&amp;#8217;m not ruling out other explanations. Just like I&amp;#8217;m not excluding that I might have multiple causes for headache and other symptoms.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_the_end_of_the_fight_after_37_years_of_pain&#34;&gt;The end of the fight after 37 years of pain&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The whole endeavor was worth the effort. I became a hobby scientist, fixed more health issues afterwards, and invest even more effort into free and open science now: I&amp;#8217;ll publish my free data analysis program soon. I learned that some of my observation-derived ideas turned out to be true: I had my own theory that electrolytes were involved, and that&amp;#8217;s the case. Those observations should be followed &lt;em&gt;first&lt;/em&gt; rather than trying hundreds of likely unrelated ideas from the internet or from studies that average out effects on a large population. &lt;strong&gt;Most importantly, my life improved a lot by solving migraine. And even though it&amp;#8217;s not cured, and also not 100% fixed, the pain I have remaining is definitely something I can live with.&lt;/strong&gt; And I&amp;#8217;m happy being able to help others now by sharing my story, solution and specific instructions, fully backed by my own efficacy and safety data.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;With the problem now solved closer to the cause, rather than only treating symptoms, certain triggers are fully gone: Flights usually gave me nausea and headache; even before a flight, I would already have a bad feeling in my body. Also high-speed train rides used to give me a high headache risk, likely due to the fast and countless changes of air pressure and weather along the route. With the salt intervention, these are no longer a trigger.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The result is incredible. According to the recommended treatment goals, I&amp;#8217;m under &#34;optimal control&#34; with 1-2 monthly moderate-to-severe headaches (mid of 2025, much over a year into the intervention).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;div class=&#34;title&#34;&gt;From: Sacco S, Ashina M, Diener H-C, et al. Setting higher standards for migraine prevention: A position statement of the International Headache Society. Cephalalgia. 2025;45(2). doi:10.1177/03331024251320608, published by Sage &lt;a href=&#34;https://journals.sagepub.com/doi/10.1177/03331024251320608&#34;&gt;here&lt;/a&gt;. Figure 2. Aspirational goals of migraine prevention according to the position statement of the International Headache Society.&lt;/div&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2025-05-28-fixed-my-migraine-weather-sports-headaches/migraine-aspirational-goals.webp&#34; alt=&#34;Aspirational goals of migraine prevention according to the position statement of the International Headache Society&#34; width=&#34;600&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Thank you for reading, and best of luck to all sufferers!&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;My research on migraine will continue. I&amp;#8217;ll probably try again to sustain a strict low-carb diet for a longer time. This article will definitely be updated once I have new insights.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_related_reading&#34;&gt;Related reading&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If your issue turns out not being related to electrolytes, then I&amp;#8217;m sorry. There are other known causes, though, worth considering! Maybe you want to &lt;strong&gt;check for food triggers and read about histamine intolerance&lt;/strong&gt;, both related and documented to be potential causes for migraines as well. My next article might actually be about histamine intolerance (for other reasons), and I&amp;#8217;m going to observe in my data whether a low-histamine diet improves my migraine even more.&lt;/p&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;While Angela Stanton&amp;#8217;s protocol recommends balancing sodium and potassium intake from food, I currently believe that single food items can have very different effects on the body and should therefore be considered separately, not just as a food group. Avocado, high in potassium, is bad for my headache. Two portions? Even worse. In comparison, highly-processed potato chips, featuring an even higher content of potassium per portion, with a lot of carbohydrates and unhealthy oils, are rather on the positive side regarding headache risk in my data. Focusing on sodium and potassium alone probably can&amp;#8217;t fully explain headache risk. In this example, the histamine content could explain it better, for instance (avocados: high, potatoes: low), and gives a hint to look into histamine intolerance since that is known to be another cause for migraines.&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;strong&gt;effect of low-carbohydrate nutrition&lt;/strong&gt; could become really interesting. I haven&amp;#8217;t managed yet to sustain the keto diet for long enough without carbohydrate cheats, but my current data says that above 100 g of carbs per day, my headache risk is much higher (see graph shown above). There are studies such as the &lt;a href=&#34;https://pmc.ncbi.nlm.nih.gov/articles/PMC10548576/&#34;&gt;EMIKETO randomized controlled trial&lt;/a&gt; which point in this direction, too.&lt;/p&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Some researchers who pioneered in this field have turned to productizing their findings, now selling keto products instead of providing open science results. That makes some trials less believable. Therefore, it would be great to see single person reports, rather than only trusting the science here. Diet changes are definitely worth a try, in my opinion, but as they may not have a magic, live-changing effect &lt;em&gt;immediately&lt;/em&gt;, migraine severity, frequency and other symptoms should be accurately tracked and analyzed in order to prove whether it works or not.&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Cortical_spreading_depression&#34;&gt;Cortical spreading depression (CSD)&lt;/a&gt; has been researched, and even measured, at least for migraines with aura. It might correlate with potassium (and glutamate). This is another great explanation for pain spreading through head and sometimes neck. CSD may activate the trigeminal nerve and thereby cause neck pain. Or something like that. I guess this goes too far for someone who simply wants to get rid of symptoms. But these are terms you should&amp;#8217;ve heard when getting acquainted with migraine science.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As mentioned, online forums and groups can be great sources to find ideas how others solved their migraine. For example, &lt;a href=&#34;https://www.reddit.com/r/migraine/&#34;&gt;r/migraine&lt;/a&gt; can be an interesting starting place to ask or search for information.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
				<guid>https://andidog.de/blog/2025-05-28-fixed-my-migraine-weather-sports-headaches</guid>
			</item>
		
			<item>
				<pubDate>Thu, 21 Apr 2022 00:00:00 +0000</pubDate>
				
				<title>Grafana dashboards — best practices and dashboards-as-code</title>
				<link>https://andidog.de/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code</link>
				<description>&lt;div id=&#34;preamble&#34;&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://grafana.com/&#34;&gt;Grafana&lt;/a&gt; is a web-based visualization tool for observability, and also part of a whole stack of related technologies, all based on open source. You can configure various data sources&amp;#8201;&amp;#8212;&amp;#8201;time series sources like Prometheus, databases, cloud providers, Loki, Tempo, Jaeger&amp;#8201;&amp;#8212;&amp;#8201;and use or even combine them for your observability needs. As of April 2022, that means metrics, logs, traces, and visualizations based on those concepts. That is where dashboards come into play.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Dashboards are the typical first solution that even small companies or hobbyists can use to quickly get insights of their running software, infrastructure, network, and other data-generating things such as edge devices. In case of incidents, or for just glancing over them at will, dashboards are supposed to give a good overview to find and solve problems. Great dashboards make the difference of understanding an incident in 10 seconds vs. digging into &lt;a href=&#34;https://en.wikipedia.org/wiki/Red_herring&#34;&gt;red herrings&lt;/a&gt; for over 5 minutes. Meaningful dashboards also ease the path to setting correct alerts that do not wake you up unnecessarily.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;On top of dashboards, you can leverage alerts, logs and tracing which together form a simple and helpful look at your stuff, if done right&amp;#8201;&amp;#8212;&amp;#8201;or a complicated mess like your legacy software code, if done wrong 😏. Those other concepts are &lt;em&gt;out of scope&lt;/em&gt; in this article. I only focus on how to achieve &lt;em&gt;helpful, up-to-date dashboards&lt;/em&gt;, using private research and my production experience, where I extensively used Grafana dashboards&amp;#8201;&amp;#8212;&amp;#8201;and also logs&amp;#8201;&amp;#8212;&amp;#8201;to resolve incidents fast, and often with ease.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Typical examples on the internet present dashboards as a huge screen full of graphs, sometimes a collection of numbers or percentages. A lot to look at for human eyes. I will show you how to visualize better, with realistic examples. This article showcases solutions for Grafana and Prometheus, but can also be applied generically for other platforms.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&#34;_table_of_contents&#34; class=&#34;discrete dog-blog-breakpoint&#34;&gt;Table of contents&lt;/h2&gt;
&lt;div id=&#34;toc&#34; class=&#34;toc&#34;&gt;
&lt;div id=&#34;toctitle&#34; class=&#34;title&#34;&gt;&lt;/div&gt;
&lt;ul class=&#34;sectlevel1&#34;&gt;
&lt;li&gt;&lt;a href=&#34;#_goals_for_all_your_dashboards&#34;&gt;Goals for all your dashboards&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_spinning_up_a_grafana_playground_in_a_minute&#34;&gt;Spinning up a Grafana playground in a minute&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_getting_started_with_a_playground_dashboard&#34;&gt;Getting started with a playground dashboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_high_level_dashboard_creation_guidelines&#34;&gt;High-level dashboard creation guidelines&lt;/a&gt;
&lt;ul class=&#34;sectlevel2&#34;&gt;
&lt;li&gt;&lt;a href=&#34;#_choose_main_input_for_the_high_level_dashboard&#34;&gt;Choose main input for the high-level dashboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_metric_naming_and_cardinality&#34;&gt;Metric naming and cardinality&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_stat_instead_of_graph_for_human_understanding_within_milliseconds&#34;&gt;Stat instead of Graph for human understanding within milliseconds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_keep_panels_small_on_screen&#34;&gt;Keep panels small on screen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_avoid_dropdowns_for_variable_values&#34;&gt;Avoid dropdowns for variable values&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_dashboards_as_code_and_gitops_committed_dashboards&#34;&gt;Dashboards-as-code and GitOps (committed dashboards)&lt;/a&gt;
&lt;ul class=&#34;sectlevel2&#34;&gt;
&lt;li&gt;&lt;a href=&#34;#_dashboard_generation_from_jsonnet_code_using_the_grafonnet_library&#34;&gt;Dashboard generation from jsonnet code using the grafonnet library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_fast_develop_deploy_view_cycle&#34;&gt;Fast develop-deploy-view cycle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_automatic_provisioning_of_generated_dashboards_into_grafana_instance&#34;&gt;Automatic provisioning of generated dashboards into Grafana instance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_jsonnet_for_dashboardssome_tips&#34;&gt;jsonnet for dashboards&amp;#8201;&amp;#8212;&amp;#8201;some tips&lt;/a&gt;
&lt;ul class=&#34;sectlevel2&#34;&gt;
&lt;li&gt;&lt;a href=&#34;#_distinguish_environments&#34;&gt;Distinguish environments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_consider_jsonnet_as_full_programming_language&#34;&gt;Consider jsonnet as full programming language&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_grafana_specific_dashboard_tips&#34;&gt;Grafana-specific dashboard tips&lt;/a&gt;
&lt;ul class=&#34;sectlevel2&#34;&gt;
&lt;li&gt;&lt;a href=&#34;#_categorize_do_not_make_a_dashboard_mess&#34;&gt;Categorize, do not make a dashboard mess&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_grouping_within_a_dashboard&#34;&gt;Grouping within a dashboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_make_dashboards_editable&#34;&gt;Make dashboards editable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_tooltip_sort_order&#34;&gt;Tooltip sort order&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_y_axis_display_range&#34;&gt;Y axis display range&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_link_to_detailed_dashboards_logs_other_observability_tools&#34;&gt;Link to detailed dashboards, logs, other observability tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_use_variables_for_repetitive_values&#34;&gt;Use variables for repetitive values&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_clearly_differentiate_environments&#34;&gt;Clearly differentiate environments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_grid_positioning&#34;&gt;Grid positioning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_choose_the_right_data_unit&#34;&gt;Choose the right data unit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_utc_timezone_everywhere&#34;&gt;UTC timezone everywhere&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_do_not_rely_on_default_data_source&#34;&gt;Do not rely on &lt;code&gt;default&lt;/code&gt; data source&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_heatmaps&#34;&gt;Heatmaps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_display_interesting_events_as_annotations&#34;&gt;Display interesting events as annotations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_self_describing_visualization_titles&#34;&gt;Self-describing visualization titles&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_observability_tips_not_specific_to_grafana&#34;&gt;Observability tips not specific to Grafana&lt;/a&gt;
&lt;ul class=&#34;sectlevel2&#34;&gt;
&lt;li&gt;&lt;a href=&#34;#_stay_consistent_in_naming_metrics_and_labels&#34;&gt;Stay consistent in naming metrics and labels&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_no_need_to_create_a_metric_for_everything_how_to_easily_get_started_monitoring_an_uninstrumented_application&#34;&gt;No need to create a metric for everything / how to easily get started monitoring an uninstrumented application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_show_only_offenders_or_top_n_problematic_items&#34;&gt;Show only offenders or top N problematic items&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_mind_test_and_synthetic_traffic&#34;&gt;Mind test and synthetic traffic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_daytime_vs_nighttime&#34;&gt;Daytime vs. nighttime&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_do_not_use_rate_alone&#34;&gt;Do not use &lt;code&gt;rate(&amp;#8230;&amp;#8203;)&lt;/code&gt; alone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_prefer_counters_over_gauges&#34;&gt;Prefer counters over gauges&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_make_observed_components_distinguishable&#34;&gt;Make observed components distinguishable&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_summary&#34;&gt;Summary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_out_of_scope&#34;&gt;Out of scope&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#_related_reading&#34;&gt;Related reading&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_goals_for_all_your_dashboards&#34;&gt;Goals for all your dashboards&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;You cannot look only at best practices for a &lt;em&gt;single&lt;/em&gt; dashboard. If you do that, you will end up with 100 dashboards, each for a single, distinct purpose, such as one per microservice. But altogether, that becomes an unmanageable mess.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Think of your company: who is the &lt;strong&gt;main audience&lt;/strong&gt; of the dashboards? If you are using the &#34;you build it, you run it&#34; concept, it may be mostly developers (e.g. on-call engineers during an incident). For other organizational concepts, it might be &lt;a href=&#34;https://sre.google/&#34;&gt;SREs&lt;/a&gt; or infrastructure engineers. Or it may be multiple technical departments (operations + engineering). This article will focus on examples how to monitor the health of software systems (easy to apply to network and infrastructure likewise). If however your organization looks totally different and dashboards are for sales, management, compliance, information security, then the goals can be different&amp;#8201;&amp;#8212;&amp;#8201;the article may still be helpful nevertheless. Most importantly, &lt;strong&gt;you as author should be part of the audience yourself&lt;/strong&gt;, or else you are not a good fit to develop a reasonable dashboard. On the same note: great dashboards help in many ways, such as against following red herrings, but nevertheless you need application experts to resolve incidents, so those should definitely be part of the audience.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This is what we want to achieve for users:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fast resolution of incidents&lt;/strong&gt;, by finding the root cause and impacted services/customers fast&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Users should have one browser bookmark&lt;/strong&gt;, leading to a main, high-level dashboard. It will be the first page you open when you get called for an incident. Within seconds, it tells you which parts could be problematic, and which ones are okay (as operators in Star Trek say: &#34;operating within normal parameters&#34;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Show health at a glance, with a simple indicator&lt;/strong&gt; that the human eyes can quickly consume (e.g. green or red background color), for each component&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Allow drilling down into more detail&lt;/strong&gt; (low-level) in order to come closer to the root cause if the high-level dashboard is not enough&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;How this can roughly work:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a high-level overview dashboard.&lt;/strong&gt; It depends on your company how many of those make sense. The scope could be one system, service, product domain, or for small companies even the whole landscape at once.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Represent each component or microservice of a system&lt;/strong&gt; in the high-level overview&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For fine-grained analysis, it also often makes sense to create a &lt;strong&gt;separate, detailed (low-level) dashboard for each component&lt;/strong&gt;. The &lt;strong&gt;high-level dashboard links to those&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;From each visualization&lt;/strong&gt; (those are the rectangles on your dashboard, such as graphs), &lt;strong&gt;link&lt;/strong&gt; to detailed dashboards, prepared &lt;a href=&#34;https://grafana.com/docs/loki/latest/logql/&#34;&gt;log queries&lt;/a&gt;, debugging tools on your intranet, the system/website itself, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create dashboards solely through code&lt;/strong&gt;, to avoid having a mess of manually created, unreviewed, inconsistent dashboards after a few weeks, and the need for a company-wide &#34;tooling switch&#34; after a few months or years, only to clean up all of that. &lt;strong&gt;Users nevertheless get write access to Grafana, since that allows temporarily adapting a dashboard for own usage&lt;/strong&gt;, such as special investigation during incidents. They should however be trained that &lt;strong&gt;changes should not be saved&lt;/strong&gt;, and &lt;strong&gt;any saved changes will regularly be overwritten by the dashboards committed as code&lt;/strong&gt;. Those get &lt;strong&gt;automatically deployed, for example by a CI pipeline&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You give &lt;strong&gt;no training to users&lt;/strong&gt;. Yes, you heard right! A well-designed dashboard is 100% obvious and requires no explanation to use it, given the user knows the relevant terminology of your monitored system. Training for incidents anyway mostly happens through practice. Therefore, I recommend you present the dashboards on screen during incidents, so that other users see the capabilities they offer, and less obvious features such as the hyperlinks that can be added to the clickable top-left corner of each visualization. &lt;strong&gt;Code review for dashboards, and reviewers who are application experts&lt;/strong&gt; (who understand the meaning of the displayed metrics), are essential to keep up good quality and really make the dashboards plain simple to use without explanations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For medium to large companies in terms of head count, introducing such a consistent concept will be impossible unless technical leadership supports the full switch from the old or non-existing monitoring solution to Grafana with dashboards-as-code. It is key to document and communicate that codifying dashboards is the only way to go, listing the rationale for your company and also how a developer can start creating or modifying dashboards. This requires no more than &lt;strong&gt;one-page documentation/guide&lt;/strong&gt; and an introduction by leadership or engineering managers.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_spinning_up_a_grafana_playground_in_a_minute&#34;&gt;Spinning up a Grafana playground in a minute&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;You only need this if you want to follow along with the blog article recommendations, play around with random sample data, and do not have a live Grafana instance with real application metrics at hand.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Some solutions exist&amp;#8201;&amp;#8212;&amp;#8201;most of them using docker-compose&amp;#8201;&amp;#8212;&amp;#8201;which allow you to easily and quickly spin up Grafana and data sources in a minute. Here, I describe the official devenv that Grafana developers and contributors use (see &lt;a href=&#34;https://github.com/grafana/grafana/tree/main/devenv&#34;&gt;Grafana&amp;#8217;s devenv README&lt;/a&gt;):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;git clone --depth 1 https://github.com/grafana/grafana.git
cd grafana/devenv

# As of 2022-04, these are the instructions.
# Check `README.md` files for more information.
./setup.sh

cd ..

# See directory `devenv/docker/blocks` for more supported sources.
# &#34;grafana&#34; is not a source - this value ensures you don&#39;t have to
# build Grafana, and an official image is used instead.
make devenv sources=grafana,loki,prometheus

# To tear down later: `make devenv-down`&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Now open &lt;a href=&#34;http://localhost:3001/&#34; class=&#34;bare&#34;&gt;http://localhost:3001/&lt;/a&gt; and log in with user &lt;code&gt;admin&lt;/code&gt; and password &lt;code&gt;admin&lt;/code&gt;. Navigate to &lt;em&gt;Explore&lt;/em&gt; mode on the lefthand navigation bar, choose &lt;code&gt;gdev-prometheus&lt;/code&gt; as data source and query an example metric such as &lt;code&gt;counters_logins&lt;/code&gt;. If it shows data, you are ready to play around.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_getting_started_with_a_playground_dashboard&#34;&gt;Getting started with a playground dashboard&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Mind that a good dashboard takes hours or days to create! As a start, the graphical way of clicking one together is the fastest. Once you have found out a good concept and layout, codifying it for the first time is some work, but worth the effort&amp;#8201;&amp;#8212;&amp;#8201;more on that later.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;If you have to experiment on a live instance, start by adding a name and hint so that your testing dashboard will not be touched by others. You can use a text visualization for that. Save the dashboard with a meaningful name. Do not use filler words like &#34;monitoring&#34; or &#34;dashboard&#34;&amp;#8201;&amp;#8212;&amp;#8201;of course it is a dashboard&amp;#8230;&amp;#8203; the screenshot only does this for the temporary &#34;it&amp;#8217;s a test&#34; hint in the title. Now you can follow along with the recommendations and examples in this blog post.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code/create-dashboard.png&#34; alt=&#34;Create a dashboard&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_high_level_dashboard_creation_guidelines&#34;&gt;High-level dashboard creation guidelines&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_choose_main_input_for_the_high_level_dashboard&#34;&gt;Choose main input for the high-level dashboard&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;By first concentrating on &lt;strong&gt;monitoring and alerting for the main function of your business and system, you can cover almost all critical problems in subcomponents and infrastructure resources&lt;/strong&gt;, without having to monitor those explicitly.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;That needs explanation&amp;#8230;&amp;#8203; &lt;strong&gt;The business in this blog article&amp;#8217;s example is to process payments. So if payments fail, people cannot pay, and the business is at risk. Anything else is not as important, and therefore not worth to observe as the first thing.&lt;/strong&gt; If a critical issue arises in our systems or network, the &lt;code&gt;payment_errors_total&lt;/code&gt; metric will most likely cover that! To use IT terminology: the metric of payment failures is a significant &lt;a href=&#34;https://sre.google/sre-book/service-level-objectives/&#34;&gt;service level indicator (SLI)&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Admittedly, that will not cover if the internet, a customer, or our API are down, because payment requests would not even reach the system and therefore cannot produce logs or error metrics. That can be covered by a metric describing the payment request rate, probably by customer and payment method, since each of those have different typical traffic rates (minimum/maximum, different per timezone or day/night, etc.). We keep this shortcoming out of scope to keep the blog article simple. The point is: &lt;strong&gt;choose very few, essential business metrics as a start, not technical metrics&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Often, you would select the &lt;strong&gt;most business-relevant Prometheus metric offered by the system you want to monitor&lt;/strong&gt;. Metrics are stored as time series and therefore very fast to query, as opposed to logs. If you use other observability tools, such as an &lt;a href=&#34;https://www.elastic.co/what-is/elk-stack&#34;&gt;ELK stack&lt;/a&gt;, you can check &lt;a href=&#34;https://grafana.com/docs/grafana/latest/datasources/&#34;&gt;if Grafana supports the relevant data source&lt;/a&gt;. This metric would typically pertain to the methods &#34;RED&#34; (requests/rate, errors, duration) or &lt;a href=&#34;https://www.brendangregg.com/usemethod.html&#34;&gt;&#34;USE&#34;&lt;/a&gt; (utilization, saturation, errors). The &lt;a href=&#34;https://sre.google/sre-book/monitoring-distributed-systems/#xref_monitoring_golden-signals&#34;&gt;Four Golden Signals&lt;/a&gt; of Google&amp;#8217;s SRE book additionally distinguishes traffic from saturation. An error metric is a good choice to start, since it is easy to determine which error rate is acceptable, and at which threshold you would consider it a serious problem.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Throughout this blog post, &lt;strong&gt;we will use the following example metric and simple terminology from the payments world&lt;/strong&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Imagine we are in a company that processes payments, offering different &lt;em&gt;payment methods&lt;/em&gt;, with each of those methods (e.g. credit card, voucher, bank transfer) having a separate microservice implementation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Counter &lt;code&gt;payment_errors_total&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cardinality&amp;#8201;&amp;#8212;&amp;#8201;the counter has these labels:&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;payment_method&lt;/code&gt; (example values &lt;code&gt;credit_card&lt;/code&gt;, &lt;code&gt;voucher&lt;/code&gt;, &lt;code&gt;bank_transfer&lt;/code&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;error_type&lt;/code&gt; (example values &lt;code&gt;connectivity_through_internet&lt;/code&gt;, &lt;code&gt;remote_service_down&lt;/code&gt;, &lt;code&gt;local_configuration_error&lt;/code&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_metric_naming_and_cardinality&#34;&gt;Metric naming and cardinality&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We do not want to have separate metrics &lt;code&gt;credit_card_payment_errors_total&lt;/code&gt; and &lt;code&gt;bank_transfer_payment_errors_total&lt;/code&gt;! If you have microservices of the same type, as in this example one service per payment method, the metrics really mean the same thing. So rather &lt;strong&gt;improve your consistency and use just one metric name&lt;/strong&gt;. Easy to do if your code is structured in a monorepo, by the way. &lt;strong&gt;If you have inconsistent names, it will take extra effort to repeat each dashboard visualization for each of the conventions&lt;/strong&gt;, instead of just using labels to distinguish and plot the services (or other traits that you define as label dimensions, such as customers).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Metric names should be easy to find in code&lt;/strong&gt;, so that developers can make sense of them fast in a stressful situation, or find out if/where a metric (still) exists. Here is a bad example where the metric name &lt;code&gt;mysystem_payment_errors_total&lt;/code&gt; cannot be found in code: &lt;code&gt;for request_type in [&#39;payment&#39;, &#39;refund&#39;, &#39;status&#39;]: prometheus.Counter(name=f&amp;#8217;mysystem_{request_type}_errors_total&#39;)&lt;/code&gt; (Python pseudocode).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Avoid high-cardinality metrics (many label combinations)&lt;/strong&gt;, since those take up lots of space, and queries take longer. Like for the logging rate of your systems, you might want to check for large metrics sporadically, or you may run into unnecessary cost and performance issues.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_stat_instead_of_graph_for_human_understanding_within_milliseconds&#34;&gt;Stat instead of Graph for human understanding within milliseconds&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;A &lt;em&gt;graph&lt;/em&gt; (nowadays called &lt;a href=&#34;https://grafana.com/docs/grafana/latest/visualizations/time-series/&#34;&gt;Time series visualization&lt;/a&gt;) for our example metric, showing payment method and error type combinations, looks like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code/dumb-graph.png&#34; alt=&#34;Dumb graph&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Cool graph, right? And we&amp;#8217;re already done and have a monitored system! &lt;strong&gt;No, this is very, very bad! Great observability requires much more than just clicking together some visuals.&lt;/strong&gt; The example is not sufficient to monitor a service. A graph visualization is a bad way to get an impression within milliseconds. The eyes have to scan the whole rendered graph, potentially containing multiple lines on varying bounds of the Y axis. You also need to know which thresholds are bad, or configure horizontal lines on the graph which represent warning and errors thresholds. That means lots of lines, colors, and points to look at before getting your question answered: &#34;is this normal or do we have a problem, and where?&#34;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Graphs can be helpful if you set them up nicely, but definitely not in the high-level part of your overview dashboard.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Instead, a &lt;strong&gt;&lt;a href=&#34;https://grafana.com/docs/grafana/latest/visualizations/stat-panel/&#34;&gt;&lt;em&gt;Stat&lt;/em&gt; visualization&lt;/a&gt;, combined with traffic light colors, gives you the answer in milliseconds&lt;/strong&gt;: green is good, amber (yellow) is noteworthy, red is bad. In addition, I tend to use blue as &#34;noteworthy but may not be problematic&#34;&amp;#8201;&amp;#8212;&amp;#8201;kind of an early warning sign or unusually high amount of traffic, such as during sales/promotion seasons. So for me personally, I like the order green-blue-amber-red. Grafana allows choosing to &lt;strong&gt;color the background instead of the value line&lt;/strong&gt;, which I recommend since then your whole screen should look green most of the time (click &lt;em&gt;Panel &amp;gt; Display &amp;gt; Color mode &amp;gt; Background&lt;/em&gt;), and your &lt;strong&gt;eyes do not need to focus on the color of tiny graph lines&lt;/strong&gt;. Exactly one value is shown&amp;#8201;&amp;#8212;&amp;#8201;typically a number or human description.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code/stats-many.png&#34; alt=&#34;Stat (many items)&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Settings for the above screenshot:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Prometheus query: &lt;code&gt;sum by (payment_method, error_type) (increment(payment_errors_total[2m]))&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Legend: &lt;code&gt;{{payment_method}} / {{error_type}}&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Choose &lt;em&gt;Calculation &amp;gt; Last&lt;/em&gt;.&lt;/strong&gt; That will give the latest metric value, since &lt;em&gt;now&lt;/em&gt; is the most interesting time point to show. Aggregations such as &lt;em&gt;Mean&lt;/em&gt; may be a useless &#34;all problems averaged away&#34; view if you pick a big time range such as &lt;em&gt;Last 24 hours&lt;/em&gt;, and would therefore show different values to different people. Since the &lt;em&gt;Last&lt;/em&gt; setting does not average at all, your query should do that instead of sampling a single raw value: Prometheus queries such as &lt;code&gt;increment(the_metric[2m])&lt;/code&gt;, or &lt;code&gt;rate(the_metric[2m])&lt;/code&gt; if you prefer a consistent unit to work with, will average for you. The &lt;code&gt;[2m]&lt;/code&gt; in there should be selected depending on how stable the metric is and how fast you need to react once the metric reaches a threshold (mind the averaging!). Magic variables like &lt;a href=&#34;https://grafana.com/docs/grafana/latest/variables/variable-types/global-variables/#__rate_interval&#34;&gt;&lt;code&gt;$__rate_interval&lt;/code&gt;&lt;/a&gt; may sound promising, but also have the issue that a different time range selection shows different results, and that could lead to confusion if you exchange links to dashboard views with other people during an incident.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;To show the colors, you need to set thresholds on the &lt;em&gt;Field&lt;/em&gt; tab. Setting them as static numbers (with the queried unit, e.g. &#34;errors per 2 minutes&#34;) may work for the start. That is called &lt;em&gt;Absolute&lt;/em&gt; in Grafana.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In our example though, the different payment methods and error types have very different thresholds: for instance, let&amp;#8217;s say the &lt;code&gt;credit_card&lt;/code&gt; payment method has &lt;code&gt;remote_service_down&lt;/code&gt; errors very frequently because the 3rd party provider is unreliable and we cannot help it, so we want to set a higher threshold because it otherwise unnecessarily shows a problem. Or instead of a higher threshold, you could consider querying the error rate increment over 10 minutes, to even out any short spikes.  To &lt;strong&gt;use relative thresholds&lt;/strong&gt;, click &lt;em&gt;Percentage&lt;/em&gt; and fill some values. They will use the &lt;em&gt;Min&lt;/em&gt;/&lt;em&gt;Max&lt;/em&gt; settings. For example: if you set &lt;code&gt;Min = 0&lt;/code&gt; and &lt;code&gt;Max = 200&lt;/code&gt;, red background color above the 66% threshold will be shown above &lt;code&gt;66% * 200 = 132&lt;/code&gt; (unit in this example: errors within 2 minutes). Everything above 66% will be red. Everything between 16% and 33% will be blue. And so on.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code/relative-thresholds.png&#34; alt=&#34;Relative (percentage) thresholds&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;To set &lt;strong&gt;specific thresholds per value combination&lt;/strong&gt; (here: &#34;payment method / error type&#34;), &lt;strong&gt;adjust &lt;em&gt;Max&lt;/em&gt;&lt;/strong&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code/max-override.png&#34; alt=&#34;Override Max setting&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Since Grafana live-previews your changes, it should be simple to choose good values for &lt;em&gt;Max&lt;/em&gt;. Select a healthy time range for your system, and it should be green (note that the right-most time point is displayed, as we chose &lt;em&gt;Calculation &amp;gt; Last&lt;/em&gt;). Select an incident time window, and choose a &lt;em&gt;Max&lt;/em&gt; value to make it red. The other values (amber/blue) might then just work, since they are based on percentages. Start with values that work, and adjust them if you later see false positives (red when system is fine) or false negatives (green when system has problems). If you want human descriptions instead of numbers, you can also use the override feature (&lt;em&gt;Field &amp;gt; Value mappings&lt;/em&gt;, or for specific fields: &lt;em&gt;Overrides &amp;gt; [create an override] &amp;gt; Add override property &amp;gt; Value Mappings / No value&lt;/em&gt;), for instance to replace 0 with the text &#34;no errors&#34;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Example: our query shows the number of errors in 2 minutes. By looking at the graphed data of the last few days (paste query into &lt;em&gt;Explore&lt;/em&gt; mode), we might find that 20 errors in 2 minutes are acceptable and should be shown as green. We therefore choose a slightly higher threshold of 25 to still be within the green color. Since we switch to blue color from 16%, we get &lt;code&gt;Max = 25 * 100% / 16% = 156&lt;/code&gt;. As a result, red background color&amp;#8201;&amp;#8212;&amp;#8201;which shouts &#34;something is seriously wrong&#34;&amp;#8201;&amp;#8212;&amp;#8201;would be shown above &lt;code&gt;Max * 66% = 103&lt;/code&gt; errors in 2 minutes. You should experiment a little so that in healthy times, your dashboard remains green.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Side note: for &#34;higher is better&#34; metrics such as customer conversion rate (100% = all customer purchases succeed), you can just turn around the colors (green on top, red on bottom). The &lt;em&gt;Max&lt;/em&gt; setting also defines the upper bound of the graph which is shown as part of the &lt;em&gt;Stat&lt;/em&gt; visualization, so if values are higher, the line will cross the top of the Y axis and therefore becomes invisible. Not a big deal if &lt;em&gt;Min&lt;/em&gt;/&lt;em&gt;Max&lt;/em&gt; cover the expected range. You may also have the rare case of &#34;too high and too low are both bad&#34; metrics, e.g. a counter for payment requests where you always expect some traffic to be made, but also want to be warned if the request rate is soaring. The colors could be adapted to show both low range and high range as red, with green for the expected, normal range.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_keep_panels_small_on_screen&#34;&gt;Keep panels small on screen&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Pack &lt;strong&gt;only few visualizations horizontally, so the font stays large&lt;/strong&gt; enough. Other &lt;strong&gt;people may work on a smaller screen&lt;/strong&gt; than yours, or do not use full screen sizing. The repeat feature (&lt;em&gt;Panel &amp;gt; Repeat options&lt;/em&gt;) makes Grafana create and align them automatically. In our example, the repeat feature is unused, but since we pulled different combinations of payment method and error type out of our (single, consistently named and labeled) metric, that will also show multiple rectangles in one &lt;em&gt;Stat&lt;/em&gt; visualization, and try to align them on screen. In the screenshot further above, the titles are barely readable, and the visualization is large and could require scrolling on small screens. To solve that, you could:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Keep as-is and show a separate rectangle for each combination. With each added or newly monitored product/feature (here: payment methods), the whole dashboard size grows, so the page does not always look the same or fit on one screen. &lt;strong&gt;I&amp;#8217;m not telling you it should fit on one screen, but a high-level dashboard must not be an endless scrolling experience.&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Show only problematic items&amp;#8201;&amp;#8212;&amp;#8201;for instance, only yellow and worse. The downside is that in healthy cases, nothing gets shown, making users unaware of how it should normally look like. See below for a better option.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Show the top&lt;/strong&gt; 10 &lt;strong&gt;highest error rates&lt;/strong&gt; (Prometheus: &lt;a href=&#34;https://prometheus.io/docs/prometheus/latest/querying/operators/#aggregation-operators&#34;&gt;&lt;code&gt;topk&lt;/code&gt;&lt;/a&gt;). This can be combined with traffic light coloring. If only one shows red, you will think that one payment method is down, while if multiple show red, you may think of a larger issue. With this solution, the visualization will never show as empty, so you&amp;#8217;ll see ~10 green rectangles in healthy scenarios (the section &lt;a href=&#34;#_show_only_offenders_or_top_n_problematic_items&#34;&gt;Show only offenders or top N problematic items&lt;/a&gt; later explains why it may not be exactly 10, and how to fix that). Compared to the above option, this ensures that the visualization remains at the same size and does not jump around on the web page, and you know that the dashboard is still working. Just like software, dashboards can become buggy and not show you the right things, for example if someone renames a metric!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code/small-on-screen.png&#34; alt=&#34;Top items only to keep panels small on screen&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_avoid_dropdowns_for_variable_values&#34;&gt;Avoid dropdowns for variable values&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Typical &lt;a href=&#34;https://github.com/prometheus-operator/kube-prometheus&#34;&gt;pre-built, open source dashboards&lt;/a&gt; may show variables like these:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code/variables.png&#34; alt=&#34;Variables&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Such low-level investigation dashboards are helpful, but for high-level purposes, your dashboard should show everything at one glance. If you have clusters A and B, of which one serves traffic at a time and the other one is the passive backup, you should not be required to know by heart which cluster is active. Instead, the dashboard should show health across clusters. You can still repeat your visualizations for each cluster, or query for &lt;code&gt;by (cluster)&lt;/code&gt; if it proves helpful&amp;#8201;&amp;#8212;&amp;#8201;but probably rather on low-level dashboards. For our example of an error metric, you want to know if it goes above a threshold, and &lt;code&gt;sum(rate(&amp;#8230;&amp;#8203;))&lt;/code&gt; does not strictly require distinction by cluster in the high-level visualizations.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_dashboards_as_code_and_gitops_committed_dashboards&#34;&gt;Dashboards-as-code and GitOps (committed dashboards)&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The &lt;a href=&#34;https://grafana.com/docs/grafana/latest/administration/provisioning/&#34;&gt;Grafana provisioning documentation&lt;/a&gt; describes how to use a &lt;em&gt;local&lt;/em&gt; directory which Grafana will watch and load dashboards from. However, you cannot just write dashboards as plain JSON as a human. Also, more ergonomic ways of importing dashboards, e.g. from a Git repo, are not supported yet but Grafana Labs is &lt;a href=&#34;https://github.com/grafana/grafana/issues/13823&#34;&gt;considering improvements&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Here is the rough plan:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Generate Grafana-compatible JSON&lt;/strong&gt; containing dashboard objects. The &lt;a href=&#34;https://grafana.github.io/grafonnet-lib/&#34;&gt;Grafonnet library&lt;/a&gt; is the official way to develop dashboards using the &lt;a href=&#34;https://jsonnet.org/learning/tutorial.html&#34;&gt;Jsonnet language&lt;/a&gt;. There is also Weaveworks&#39; &lt;a href=&#34;https://github.com/weaveworks/grafanalib&#34;&gt;grafanalib for Python&lt;/a&gt; which is not presented in this article.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Add that build to CI&lt;/strong&gt;. Deployment means that you have to make the JSON files available to Grafana in some directory.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configure Grafana to pick up files from that directory&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Also, support a &lt;strong&gt;developer workflow&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Advantages of not creating dashboards visually through the Grafana UI:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;You get a &lt;strong&gt;developer workflow&lt;/strong&gt;. The later section &lt;a href=&#34;#_fast_develop_deploy_view_cycle&#34;&gt;Fast develop-deploy-view cycle&lt;/a&gt; explains how that works. It is surely worse than WYSIWYG. But a programming language such as jsonnet makes the repetitive parts so much more expressive and consistent. With file watching tools and a Grafana API key, you can deploy each saved change within a second and only need to reload in your browser. Very soon, it will be a great experience, once you have assembled some basic functionality and learned the language. While jsonnet is not the best or most well-known language, better alternatives such as &lt;a href=&#34;https://github.com/aws/aws-cdk&#34;&gt;CDK&lt;/a&gt; integration or other libraries may arise in the future. And once you have developed a dashboard, it is easy to improve in small increments, similar to software code. In fact, just like the main parts of your software code, dashboard code will typically be written once and then not touched for a long time. Codifying dashboards therefore leads to long-term consistency, yet making large changes easy. If you tell people to visually create dashboards instead of dashboard-as-code, after a few months you will see a bloat of outdated, awful, non-informative and unreviewed dashboards, with lots of them probably unused. Coded dashboards improve quality and allow you to throw out old stuff easily and with the needed 4-eye principle. You can still allow people to visually author dashboards, but tell them they will be automatically destroyed every &lt;em&gt;Deleteday&lt;/em&gt;. &lt;strong&gt;Changes can be tested visually (at best with production data!) but should then be ported back into code&lt;/strong&gt;. Once coded, a dashboard should go through &lt;strong&gt;review&lt;/strong&gt;, and it is very likely that most changes &lt;strong&gt;reuse homegrown jsonnet functions instead of reinventing each dashboard from scratch. Simple improvements should become one-line changes&lt;/strong&gt;. Reviewed dashboards are much more robust, stable and avoid outdated parts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Consistent annotations such as deployment events&lt;/strong&gt;, for instance by reusing a custom function which adds them everywhere&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;With such a custom base library of functionality, &lt;strong&gt;nobody needs to be an expert to get started making changes to monitoring&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vendor lock-in can be avoided to some extent&lt;/strong&gt;. The Grafonnet library and custom object properties are highly Grafana-specific. No way around that. Even if you use WYSIWYG editing and storage, the dashboard is stored as Grafana-specific JSON, not transferable at all to other providers. I recommend to choose one observability platform and stick with it for years&amp;#8201;&amp;#8212;&amp;#8201;just like you would for an infrastructure platform such as Kubernetes and its ecosystem. This article shows you how to cleanly manage your dashboards as code. That way, improving or fixing all dashboards at once is done within minutes, and you get the benefit of code review. If you write some high-level jsonnet functions such as &lt;code&gt;addDashboard(prometheusQuery, yellowThreshold, redThreshold)&lt;/code&gt; (pseudocode), you can even abstract Grafana-specific stuff to some extent and later port more easily once the company switches to another observability provider or cloud product. I cannot provide experience or examples (yet) whether such an abstraction layer is worth the effort.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Old and unused stuff is easy to detect and delete&lt;/strong&gt;. For example, you can &lt;code&gt;grep&lt;/code&gt; for metric names or other things that do not exist anymore in your software, and delete those dashboards or visualizations from the code. Likewise, it is easy for a developer to find out where and if a metric is actually used for monitoring.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A &lt;strong&gt;monorepo keeps all observability-related things in one place&lt;/strong&gt;. You do not want to copy the solution into every engineering team&amp;#8217;s projects, since it may take some effort upfront to include it with your existing CI/CD/GitOps tooling, and decentralizing the solution defeats many advantages (consistency, shared base library functions, availability of good examples for new joiners to learn from). If you can reuse your software (mono)repository, even better, since that makes it easier to put relevant changes together&amp;#8201;&amp;#8212;&amp;#8201;such as adding/removing/extending metrics or log fields.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_dashboard_generation_from_jsonnet_code_using_the_grafonnet_library&#34;&gt;Dashboard generation from jsonnet code using the grafonnet library&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Let&amp;#8217;s set up the generation of our dashboard from code. First, the necessary tools. &lt;a href=&#34;https://github.com/jsonnet-bundler/jsonnet-bundler&#34;&gt;&lt;code&gt;jb&lt;/code&gt;&lt;/a&gt; (jsonnet-bundler) will be used as jsonnet package manager, and &lt;a href=&#34;https://github.com/google/go-jsonnet&#34;&gt;go-jsonnet&lt;/a&gt; (not the &lt;a href=&#34;https://github.com/google/jsonnet&#34;&gt;much slower C++ implementation&lt;/a&gt;!) for the language itself.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;# macOS + Homebrew
brew install go-jsonnet jsonnet-bundler
# Any other OS / package manager combination
go install -a github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb@latest
go install github.com/google/go-jsonnet/cmd/jsonnet@latest&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We need jsonnet libraries for the outputs we want to generate. In this case, Grafonnet for Grafana dashboards is enough. If you want to generate non-Grafana resources, consider the &lt;a href=&#34;https://github.com/prometheus-operator/kube-prometheus&#34;&gt;kube-prometheus collection&lt;/a&gt; which covers much of the Kubernetes landscape (but mind its Kubernetes version compatibility matrix).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;cd my/version/control/repository
jb init
jb install https://github.com/grafana/grafonnet-lib/grafonnet
echo &#34;/vendor&#34; &amp;gt;&amp;gt;.gitignore&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Commit &lt;code&gt;jsonnetfile.json&lt;/code&gt; and &lt;code&gt;jsonnetfile.lock.json&lt;/code&gt;. The lock file ensures that the next user gets the same version of libraries, so you do not need to commit the downloaded modules in the &lt;code&gt;vendor&lt;/code&gt; directory. But that probably starts a flame war among Go developers, so please decide yourself&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Instead of &lt;code&gt;jb&lt;/code&gt;, you could also use Git submodules, but probably will regret it after adding more dependencies&amp;#8201;&amp;#8212;&amp;#8201;I did not test that alternative.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;First write a minimal dashboard as code and save as &lt;code&gt;dashboards/payment-gateway.jsonnet&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;local grafana = import &#39;grafonnet/grafana.libsonnet&#39;;

grafana.dashboard.new(
  timezone=&#39;utc&#39;,
  title=&#39;Payment gateway (high-level)&#39;,
  uid=&#39;payment-gateway&#39;,
)
.addPanel(
  grafana.text.new(
    content=&#39;Yippie&#39;,
    mode=&#39;markdown&#39;,
  ),
  gridPos={
    x: 0,
    y: 0,
    w: 24,
    h: 2,
  },
)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Play around manually:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;# This may fail if you forget the newline at the end of the file, or the code is
# otherwise not compatible with jsonnetfmt&#39;s expectations
jsonnetfmt --test dashboards/payment-gateway.jsonnet || echo &#34;ERROR: File must be reformatted&#34; &amp;gt;&amp;amp;2 # use in CI and IDE ;)

export JSONNET_PATH=&#34;$(realpath vendor)&#34; # same as using `-J vendor` argument for the below commands
jsonnet-lint dashboards/payment-gateway.jsonnet # use in CI and IDE ;)
jsonnet dashboards/payment-gateway.jsonnet&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The last command outputs a valid Grafana dashboard as JSON. To manually apply it, open the test dashboard in your Grafana instance, then &lt;em&gt;⚙️ &amp;gt; JSON Model &amp;gt; copy-paste generated JSON &amp;gt; Save Changes&lt;/em&gt;. You should now see the dashboard as described by code&amp;#8201;&amp;#8212;&amp;#8201;containing only a text panel that says &#34;Yippie&#34;. This is the simplest development workflow. But it is very tiring to always go and copy-paste some generated blob and save it with many clicks. And the workflow is not visual (WYSIWYG). The next section explains a better way.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_fast_develop_deploy_view_cycle&#34;&gt;Fast develop-deploy-view cycle&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;While there is no WYSIWYG editor for the whole conversion from jsonnet to a visual dashboard in Grafana, here is an alternative which works right now (in 2022):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Create a personal &lt;em&gt;API key&lt;/em&gt; (&lt;em&gt;side bar &amp;gt; Configuration &amp;gt; API Keys&lt;/em&gt;) with &lt;em&gt;Editor&lt;/em&gt; permission&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;a href=&#34;http://eradman.com/entrproject/&#34;&gt;entr&lt;/a&gt; or other file watching tool to execute a script whenever you save your jsonnet files. IDEs may offer this action-on-save feature as well.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;That script uses your API key to overwrite dashboards in your Grafana instance&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Preparation in your shell:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;export GRAFANA_API_KEY=&#34;THE_API_KEY_YOU_CREATED_WITH_EDITOR_PERMISSION&#34;
export GRAFANA_URL=&#34;THE_GRAFANA_URL&#34; # if you use devenv: `export GRAFANA_URL=&#34;http://localhost:3001/&#34;`&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Next, store the following script as &lt;code&gt;watch.sh&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;#!/usr/bin/env bash
set -eu -o pipefail

error() {
	&amp;gt;&amp;amp;2 echo &#34;ERROR:&#34; &#34;${@}&#34;
	exit 1
}

[ -n &#34;${GRAFANA_API_KEY:-}&#34; ] || error &#34;Invalid GRAFANA_API_KEY&#34;
[[ &#34;${GRAFANA_URL:-}&#34; =~ ^https?://[^/]+/$ ]] || error &#34;Invalid GRAFANA_URL (example: &#39;http://localhost:3001/&#39; incl. slash at end)&#34;

[ $# = 1 ] || error &#34;Usage: $(basename &#34;${0}&#34;) JSONNET_FILE_OF_DASHBOARD&#34;
dashboard_jsonnet_file=&#34;${1}&#34;

rendered_json_file=&#34;/tmp/$(basename &#34;${dashboard_jsonnet_file%.jsonnet}&#34;).rendered.json&#34;

cat &amp;gt;/tmp/render-and-upload-dashboard.sh &amp;lt;&amp;lt;-EOF
	#!/usr/bin/env bash
	set -euo pipefail
	clear

	# Render
	echo &#34;Will render to \${2}&#34;
	JSONNET_PATH=&#34;\$(realpath vendor)&#34;
	export JSONNET_PATH
	jsonnet-lint &#34;\${1}&#34;
	jsonnet -o &#34;\${2}&#34; &#34;\${1}&#34;

	# Enable editable flag and upload via Grafana API
	cat &#34;\${2}&#34; \
		| jq &#39;{&#34;dashboard&#34;:.,&#34;folderId&#34;:0,&#34;overwrite&#34;:true} | .dashboard.editable = true&#39; \
		| curl \
			--fail-with-body \
			-sS \
			-X POST \
			-H &#34;Authorization: Bearer \${GRAFANA_API_KEY}&#34; \
			-H &#34;Content-Type: application/json&#34; \
			--data-binary @- &#34;${GRAFANA_URL}api/dashboards/db&#34; \
		&amp;amp;&amp;amp; printf &#39;\nDashboard uploaded at: %s\n&#39; &#34;$(date)&#34; \
		|| { &amp;gt;&amp;amp;2 printf &#39;\nERROR: Failed to upload dashboard\n&#39;; exit 1; }
EOF
chmod +x /tmp/render-and-upload-dashboard.sh

echo &#34;${dashboard_jsonnet_file}&#34; | entr /tmp/render-and-upload-dashboard.sh /_ &#34;${rendered_json_file}&#34;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Run the script, passing the source files as argument.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;# Make script executable
chmod +x watch.sh

./watch.sh dashboards/payment-gateway.jsonnet&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The script listens for changes to the source file and then overwrites the dashboard in your Grafana instance with an API request. Open your Grafana instance and find the dashboard by its title. Mind that the &lt;code&gt;uid&lt;/code&gt; field in source code must be set to a fixed value per dashboard in order to overwrite the dashboard instead of creating new ones.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This workflow gives you results within seconds and you only need to refresh in your browser to see saved changes. You may want to keep an eye on your terminal, since jsonnet is a compiled language and therefore spits out errors if you make coding mistakes.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_automatic_provisioning_of_generated_dashboards_into_grafana_instance&#34;&gt;Automatic provisioning of generated dashboards into Grafana instance&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Grafana &lt;a href=&#34;https://grafana.com/docs/grafana/latest/administration/provisioning/&#34;&gt;provisioning&lt;/a&gt; allows automatic reloading of dashboards from a certain place. We want to load the committed, generated dashboards. On the other hand, we will not fully recreate Grafana and its database on every commit to some control repository&amp;#8201;&amp;#8212;&amp;#8201;I&amp;#8217;d call that &lt;em&gt;murder by GitOps&lt;/em&gt;, and the sheer idea does not sound useful, as users and their settings are stored in the database, so we do not want to manage everything as code.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;We can set up Grafana in various ways: via Ansible on a single server, with containers on Docker or Kubernetes, manually run on the company&amp;#8217;s historic Raspberry Pi in the CEO&amp;#8217;s closet, etc. They luckily all work the same way for configuration: local files.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In the &lt;a href=&#34;https://grafana.com/docs/grafana/latest/administration/provisioning/#dashboards&#34;&gt;dashboard provisioning section&lt;/a&gt;, it says you can put &#34;one or more YAML configuration files in the &lt;code&gt;provisioning/dashboards&lt;/code&gt; directory&#34;. We try that with a realistic setup of Grafana, and for the sake of simplicity, we assume a GitOps model, meaning that Grafana loads dashboards from committed files. You have to adapt this article yourself to your respective setup.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The following instructions show you how to do this on a self-hosted Kubernetes setup of Grafana (see their &lt;a href=&#34;https://grafana.com/docs/grafana/latest/installation/kubernetes/&#34;&gt;setup instructions&lt;/a&gt;). As I do not have a Grafana Cloud account right now, I cannot tell if the cloud offering provides this much flexibility, or any good way of using the GitOps model&amp;#8201;&amp;#8212;&amp;#8201;if they do, the documentation misses this important piece (as of 2022-04). We use &lt;a href=&#34;https://kind.sigs.k8s.io/&#34;&gt;kind&lt;/a&gt; to simulate a production Kubernetes cluster.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;# Create Kubernetes cluster and a target namespace
kind create cluster --kubeconfig ~/.kube/config-kind
export KUBECONFIG=~/.kube/config-kind
kubectl create ns monitoring

# Install Prometheus so we have a data source to play with
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm upgrade --install -n monitoring prometheus prometheus-community/prometheus&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;To install from &lt;a href=&#34;https://github.com/grafana/helm-charts/tree/main/charts/grafana&#34;&gt;Grafana&amp;#8217;s Helm chart&lt;/a&gt;, you need to configure it. Store the following content in &lt;code&gt;grafana-values.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;adminUser: admin
adminPassword: admin

# Disable persistence so all data is lost on restart. That&#39;s a little unfair to your users,
# though, so you may want to instead combine GitOps with a delete-every-Sunday concept.
# A real production setup would provide persistence, but that is out of scope for this article.
persistence:
  enabled: false

datasources:
  datasources.yaml:
    apiVersion: 1
    datasources:
      - name: prometheus
        type: prometheus
        url: http://prometheus-server
        access: server
        isDefault: true

dashboardProviders:
  dashboardproviders.yaml:
    apiVersion: 1
    providers:
      - name: default
        orgId: 1
        folder: &#34;&#34;
        type: file
        disableDeletion: false
        updateIntervalSeconds: 10 # how often Grafana will scan for changed dashboards
        allowUiUpdates: true
        options:
          path: /var/lib/grafana/dashboards/default
          foldersFromFilesStructure: false

rbac:
  extraRoleRules:
    # Allow k8s-sidecar image to read ConfigMap objects in same namespace
    - apiGroups: [&#34;&#34;]
      resources: [&#34;configmaps&#34;]
      verbs: [&#34;get&#34;, &#34;watch&#34;, &#34;list&#34;]

extraContainers: |
  - name: collect-dashboard-configmaps-in-directory
    image: kiwigrid/k8s-sidecar:latest
    volumeMounts:
      - name: collection
        mountPath: /tmp/collection
    env:
      - name: LABEL
        value: &#34;collect-me&#34;
      - name: LABEL_VALUE
        value: &#34;grafana-dashboard&#34;
      - name: FOLDER
        value: /tmp/collection
      - name: RESOURCE
        value: configmap

extraVolumeMounts:
  # This will implicitly create an `emptyDir` volume as well (quite surprising),
  # so we do not require the value `extraContainerVolumes`.
  - name: collection
    mountPath: /var/lib/grafana/dashboards/default
    readOnly: true&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;And continue installation:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;# Install Grafana
helm repo add grafana https://grafana.github.io/helm-charts
helm upgrade --install -f grafana-values.yaml -n monitoring grafana grafana/grafana

# Wait until the installation is ready, then keep this running in order to access
# Grafana in the browser
kubectl port-forward -n monitoring svc/grafana 7878:80&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Now open &lt;code&gt;&lt;a href=&#34;http://127.0.0.1:7878/&#34; class=&#34;bare&#34;&gt;http://127.0.0.1:7878/&lt;/a&gt;&lt;/code&gt; and log in with &lt;code&gt;admin:admin&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Grafana reads dashboards from a directory structure. In the Kubernetes world, we can put generated dashboards into a &lt;code&gt;ConfigMap&lt;/code&gt; in order to mount it into the Grafana directory structure. They however have a 1 MiB limit each. An example high-level dashboard of mine takes 115 kiB when Base64-encoded, so you also will not be able to say &#34;we can fix this problem later&#34;, since you will reach the limit very soon. We will render all dashboards into one manifest file. That YAML file will contain one &lt;code&gt;ConfigMap&lt;/code&gt; object per dashboard. Committing that file in a GitOps fashion is easy to add in your CI (&lt;code&gt;git clone &amp;amp;&amp;amp; git add &amp;amp;&amp;amp; git commit &amp;amp;&amp;amp; git push&lt;/code&gt;), but that is out of scope for this article. You could also do &lt;a href=&#34;https://www.weave.works/blog/kubernetes-anti-patterns-let-s-do-gitops-not-ciops&#34;&gt;CIOps&lt;/a&gt; (&lt;code&gt;kubectl apply&lt;/code&gt; from CI; not recommended), or just &lt;code&gt;rsync -r --delete&lt;/code&gt; if you have Grafana on physical, mutable hardware and not on Kubernetes, or whatever other way of deployment to the directory structure. Make sure you overwrite during deployment instead of only adding new files/dashboards, since deletion and cleanup of technical debt is just as important as it is for writing software. Treat your Grafana instance and database as something that gets reset regularly, from a committed state. This avoids people making manual, unreviewed edits.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;As you can see in the configuration, we use &lt;a href=&#34;https://github.com/kiwigrid/k8s-sidecar&#34;&gt;k8s-sidecar&lt;/a&gt; to automatically collect all dashboard JSON files into one directory for use by Grafana. Each &lt;code&gt;ConfigMap&lt;/code&gt; must have the label &lt;code&gt;collect-me: grafana-dashboard&lt;/code&gt; to get picked up. The following script creates such &lt;code&gt;ConfigMap&lt;/code&gt; manifests. I do not explain here how to integrate it with your specific CI tool, but that should be easy if it works locally. Save the script as &lt;code&gt;render-and-configmap.sh&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;#!/usr/bin/env bash
set -eu -o pipefail

error() {
	&amp;gt;&amp;amp;2 echo &#34;ERROR:&#34; &#34;${@}&#34;
	exit 1
}

[ $# = 1 ] || error &#34;Usage: $(basename &#34;${0}&#34;) JSONNET_FILE_OF_DASHBOARD&#34;
dashboard_jsonnet_file=&#34;${1}&#34;

rendered_json_file=&#34;/tmp/$(basename &#34;${dashboard_jsonnet_file%.jsonnet}&#34;).rendered.json&#34;

# Render
JSONNET_PATH=&#34;$(realpath vendor)&#34;
export JSONNET_PATH
jsonnet-lint &#34;${dashboard_jsonnet_file}&#34;
jsonnet -o &#34;${rendered_json_file}&#34; &#34;${dashboard_jsonnet_file}&#34;

# Grafana wants `.json` file extension to pick up dashboards
kubectl create configmap &#34;$(echo &#34;${dashboard_jsonnet_file}&#34; | openssl sha1)&#34; \
	--from-file=&#34;$(basename &#34;${dashboard_jsonnet_file%.jsonnet}&#34;).json&#34;=&#34;${rendered_json_file}&#34; \
	--dry-run=client -o json \
	| jq &#39;.metadata.labels[&#34;collect-me&#34;]=&#34;grafana-dashboard&#34;&#39;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Ensure you are still pointing &lt;code&gt;KUBECONFIG&lt;/code&gt; to the desired Kubernetes cluster, and test dashboard deployment like so:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;# Make script executable
chmod +x render-and-configmap.sh

./render-and-configmap.sh dashboards/payment-gateway.jsonnet | kubectl apply -n monitoring -f -&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Head over to the Grafana instance running in Kubernetes, and you see that the dashboard was already loaded. Integrate this with your CI pipeline, et voilà, you have a GitOps workflow!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Once done with the cluster, you can delete it:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;kind delete cluster&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_jsonnet_for_dashboardssome_tips&#34;&gt;jsonnet for dashboards&amp;#8201;&amp;#8212;&amp;#8201;some tips&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Recommendations specifically for the jsonnet language.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_distinguish_environments&#34;&gt;Distinguish environments&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;You will surely have &lt;strong&gt;different environments&lt;/strong&gt;, such as dev/staging/prod. They have varying URLs, potentially different set of running systems, and thresholds for production not always make sense in pre-production environments. Pass &lt;code&gt;--ext-str myCompanyEnv=prod&lt;/code&gt; to the jsonnet tool to pass in a variable which you can use inside the source code. This allows previewing dashboards with development data before a software feature even goes live, and you will have very consistent views across environments. Example usage:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;assert std.extVar(&#39;myCompanyEnv&#39;) == &#39;dev&#39; || std.extVar(&#39;myCompanyEnv&#39;) == &#39;prod&#39;;

{
  my_company_environment_config:: {
    dev: {
      environment_title: &#39;Development&#39;,
      prometheus_cluster_selector: &#39;k8s_cluster=&#34;dev.mycompany.example.com&#34;&#39;,
    },
    prod: {
      environment_title: &#39;Production&#39;,
      prometheus_cluster_selector: &#39;k8s_cluster=&#34;prod.mycompany.example.com&#34;&#39;,
    },
  }[std.extVar(&#39;myCompanyEnvironment&#39;)],
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Alternatively, &lt;code&gt;--ext-code-file&lt;/code&gt; seems also a viable option, but I have no experience with it (see external blog post &lt;a href=&#34;https://www.prskavec.net/post/grafana-jsonnet/&#34;&gt;Grafana dashboards and Jsonnet&lt;/a&gt; which showcases this parameter).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This can also be interesting if you have a dev/prod split for your Grafana instances.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_consider_jsonnet_as_full_programming_language&#34;&gt;Consider jsonnet as full programming language&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;A simple dashboard should be a matter of only few lines of code. Follow the &lt;a href=&#34;https://jsonnet.org/learning/tutorial.html&#34;&gt;jsonnet tutorial&lt;/a&gt; to learn more how to achieve that. You will see some similarities with Python, for example string formatting with &lt;code&gt;%&lt;/code&gt;, slicing, array comprehension, modules/imports and other syntax that can make your code easier and shorter.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;If you think your users are not technical enough, jsonnet may not be a good fit unless you either provide high-level functions, or replace the whole jsonnet+Grafonnet rendering idea with your own custom solution that does the same thing: output dashboard definitions as Grafana-compatible JSON.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_grafana_specific_dashboard_tips&#34;&gt;Grafana-specific dashboard tips&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Some small tips and their solution, some with jsonnet examples.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_categorize_do_not_make_a_dashboard_mess&#34;&gt;Categorize, do not make a dashboard mess&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;strong&gt;Use the folder structure to organize your dashboards&lt;/strong&gt;. You and your colleagues will surely play around with test dashboards, and mixing them with production-ready, usable ones is not helpful. Also, particularly if you have many systems to watch, you want everything categorized for easy access. Product-unrelated dashboards, such as monitoring for Kubernetes clusters or infrastructure, can go into a separate category. Unfortunately, you cannot set the parent folder through jsonnet as of 2022-04, but it has to be achieved as part of deploying the generated dashboards.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_grouping_within_a_dashboard&#34;&gt;Grouping within a dashboard&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;For very detailed dashboards, you may have a lot of graphs. While this is typically discouraged, your software may really have so many important metrics. In such case, &lt;strong&gt;group them into rows&lt;/strong&gt;. They are collapsible and ease navigation. Maybe Grafana could consider adding a &#34;Table of contents&#34; feature to jump around quickly on a dashboard, using a navigation sidebar.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code/rows.png&#34; alt=&#34;Rows&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_make_dashboards_editable&#34;&gt;Make dashboards editable&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In the developer workflow above, we explicitly set dashboards to editable. You may want this for the GitOps/CI workflow as well. &lt;strong&gt;This is helpful because incidents sometimes require a bit of playing around&lt;/strong&gt; with shown data. Users should however not save changes, since they are supposed to be overwritten regularly by deploying dashboards from committed code.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_tooltip_sort_order&#34;&gt;Tooltip sort order&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;By default, hovering over a graph with many series shows them in a box in alphabetical order of the display label, e.g. sorted by &lt;code&gt;{{customer_name}}&lt;/code&gt;. Typically however, such as for error rate metrics, you want the top values shown first, since the bottom of the tooltip may be cut off in case of many entries. Go to setting &lt;em&gt;Display &amp;gt; Hover tooltip &amp;gt; Sort order&lt;/em&gt; and adjust to your liking (e.g. &lt;em&gt;Decreasing&lt;/em&gt;). With jsonnet, use &lt;code&gt;grafana.graphPanel.new(sort=&#34;decreasing&#34;)&lt;/code&gt; (not &lt;a href=&#34;https://grafana.github.io/grafonnet-lib/api-docs/#graphpanelnew&#34;&gt;documented&lt;/a&gt; as of 2022-04).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code/tooltip-sort-order.png&#34; alt=&#34;Tooltip sort order&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Do not confuse the &lt;em&gt;tooltip&lt;/em&gt; with the &lt;em&gt;legend&lt;/em&gt; (which also has a configurable sort order!).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_y_axis_display_range&#34;&gt;Y axis display range&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Many metrics only produce non-negative numbers. Graphs with such a metric on the Y axis should therefore have &lt;em&gt;Visualization &amp;gt; Axes &amp;gt; Y-Min&lt;/em&gt; set to &lt;code&gt;0&lt;/code&gt; instead of &lt;code&gt;auto&lt;/code&gt; in order to save screen space by not showing the negative area. Another problem is that you often want 0 to be the lower bound, or else Grafana chooses the display range based on the available data. In jsonnet: &lt;code&gt;grafana.graphPanel.new(min=0)&lt;/code&gt;. Setting the maximum may be helpful if you know the number range (e.g. disk full 0-100%) and want to have a consistent display.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;See how the bad example on the left makes you think of a fluctuating metric. The corrected example on the right shows that in reality, the value is quite stable. In general, make trends easier to recognize for the eyes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code/y-min-zero.png&#34; alt=&#34;y min zero&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Be cautious with your use case, though. If you want to display and warn when a disk gets full, for example, you better extrapolate and display the trend. Or use a &lt;em&gt;Stat&lt;/em&gt; visualization with a warning color once the trend reaches &#34;disk becomes full within 30 days&#34;. The respective alerts need to be designed in a similar way. Otherwise, if a short time range is selected, the user may not see that the disk usage is going up a lot, as the difference between 200 GiB and 210 GiB may not look dramatic with &lt;em&gt;Y-Min&lt;/em&gt; set to zero.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_link_to_detailed_dashboards_logs_other_observability_tools&#34;&gt;Link to detailed dashboards, logs, other observability tools&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Use &lt;a href=&#34;https://grafana.github.io/grafonnet-lib/api-docs/#graphpanelnew&#34;&gt;&lt;code&gt;grafana.graphPanel.new(&amp;#8230;&amp;#8203;).addLinks(&amp;#8230;&amp;#8203;)&lt;/code&gt;&lt;/a&gt; to create &lt;a href=&#34;https://grafana.com/docs/grafana/latest/linking/panel-links/&#34;&gt;panel links&lt;/a&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;grafana.graphPanel.new(
  // ...
).addTarget(
  prometheus.target(
    // ...
  )
).addLinks([
  {
    title: &#39;Logs - Payment gateway&#39;,
    url: ...,
  },
  // ...
])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;For links to detailed dashboards, consistently pre-select a reasonable time frame such as &lt;code&gt;now-30m&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;If you consistently tag dashboards, you can use &lt;a href=&#34;https://grafana.com/docs/grafana/latest/linking/dashboard-links/&#34;&gt;dashboard links&lt;/a&gt; to put clickable links to related dashboards on top. You can also add external links such as other company tools. I have not used this feature yet and typically rather repeat the links on each panel since that does not require scrolling all the way to the top. With jsonnet, it is easy to provide a consistent set of links (as dashboard or panel links).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_use_variables_for_repetitive_values&#34;&gt;Use variables for repetitive values&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In rare cases, you want a repetitive &lt;strong&gt;variable&lt;/strong&gt; such as &lt;code&gt;datacenter&lt;/code&gt; = &lt;code&gt;cluster=&#34;dc&#34;\,host=~&#34;server.*&#34;&lt;/code&gt; so that queries become less verbose: &lt;code&gt;sum by (payment_method, error_type) (rate(payment_errors_total{$datacenter}[2m]))&lt;/code&gt;. If the value is used in a label filter of a Prometheus query, as in this example, remember that commas need to be escaped with a backslash, or else Grafana treats the comma as separator between different choices for the variable value.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code/variable-custom.png&#34; alt=&#34;Custom variable&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Even if you use jsonnet, you should use variables instead of filling a hardcoded value into each query. This allows users to change all visualizations on a dashboard at once (at &lt;em&gt;⚙️ &amp;gt; Variables&lt;/em&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Consider &lt;strong&gt;hiding those variables&lt;/strong&gt; on the dashboard if their sole purpose is to avoid repeated, hardcoded values. See also below for some rationale.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_clearly_differentiate_environments&#34;&gt;Clearly differentiate environments&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;You do not want to be looking at a development dashboard while debugging a production issue, so make that mistake impossible to happen. Possible solutions:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Separate Grafana instance per environment. See &lt;a href=&#34;https://www.reddit.com/r/grafana/comments/ic48hr/multiple_grafanas_for_multiple_environments/&#34;&gt;this Reddit thread for some options&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the category and title of each dashboard so that non-production ones show a clear hint&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Different colors and backgrounds&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Different &lt;a href=&#34;https://grafana.com/docs/grafana/latest/administration/preferences/change-grafana-theme/&#34;&gt;Grafana UI theme&lt;/a&gt; per environment. I am not aware of an official way to customize styles using CSS or external themes. You could patch &lt;a href=&#34;https://github.com/grafana/grafana/tree/main/packages/grafana-ui/src/themes&#34;&gt;built-in themes&lt;/a&gt; and build Grafana yourself, or use the &lt;a href=&#34;https://grafana.com/grafana/plugins/yesoreyeram-boomtheme-panel/&#34;&gt;Boomtheme plugin&lt;/a&gt;. I did not test those options. Users can change their own preference (light vs. dark), so this idea anyway does not really help unless you hardcode one fixed, customized theme. The feature request &lt;a href=&#34;https://github.com/grafana/grafana/issues/10495&#34;&gt;Custom UI themes&lt;/a&gt; discusses solutions and describes drawbacks of the available plugin.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_grid_positioning&#34;&gt;Grid positioning&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The grid position must be specified explicitly:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;.addPanel(
  [...],
  gridPos={
    x: 0,
    y: 0,
    w: 24,
    h: 12,
  },
)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;See &lt;a href=&#34;https://grafana.com/docs/grafana/latest/dashboards/json-model/#panel-size-and-position&#34;&gt;Panel size and position&lt;/a&gt; documentation&amp;#8201;&amp;#8212;&amp;#8201;width is split in 24 columns, height is 30 pixels each. I recommend you use 12 or 24 columns width for readability on small screens, and set a reasonable, consistent height for all visualizations on a dashboard.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;As of 2022-04, you cannot easily align visualizations using jsonnet. You can hardcode &lt;code&gt;x&lt;/code&gt;/&lt;code&gt;y&lt;/code&gt; absolute values to your liking, but that is a hassle since you do not want to develop a user interface in an absolute grid, right? I recommend setting both to &lt;code&gt;0&lt;/code&gt; in order to automatically align the visualizations on screen.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_choose_the_right_data_unit&#34;&gt;Choose the right data unit&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Choose the &lt;strong&gt;right unit&lt;/strong&gt;, e.g. &lt;em&gt;Seconds&lt;/em&gt;, &lt;em&gt;Requests per second&lt;/em&gt;, etc.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code/data-unit.png&#34; alt=&#34;Data unit&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Mind &lt;strong&gt;subtle differences between the built-in choices&lt;/strong&gt;, e.g. &lt;em&gt;Duration / seconds&lt;/em&gt; will show long text such as &#34;412 milliseconds&#34; which makes it hard to put much information on one screen&amp;#8201;&amp;#8212;&amp;#8201;consider using &lt;em&gt;Time / seconds&lt;/em&gt; instead.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Also, &lt;strong&gt;do not confuse the order of magnitude&lt;/strong&gt;: if your data is provided in seconds, do not choose &lt;em&gt;Time / milliseconds&lt;/em&gt; since that would show falsified values.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_utc_timezone_everywhere&#34;&gt;UTC timezone everywhere&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Grafana&amp;#8217;s default is to use the browser timezone. Particularly for international companies or those who have international customers, consistent values and avoidance of confusion are important. Employees usually do not open the user settings page, for example to choose light/dark mode or their timezone preference, resulting in inconsistent customer and incident communication regarding dates and times. I am working from Germany and keep seeing confusion between CET/CEST once daylight saving time toggles, and sometimes even do such mistakes myself. Let&amp;#8217;s avoid that and &lt;strong&gt;communicate only in UTC, and default to UTC in tools such as Grafana&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;By writing a jsonnet wrapper function instead of using raw calls to &lt;code&gt;grafana.dashboard.new&lt;/code&gt;, you can set that as your default for generated dashboards.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Somewhat related xkcd comic: &lt;a href=&#34;https://xkcd.com/1179/&#34;&gt;ISO 8601&lt;/a&gt;. Did you know that the &lt;code&gt;Z&lt;/code&gt; suffix in &lt;code&gt;2022-04-21T17:13Z&lt;/code&gt; stands for UTC (&#34;Zulu time&#34;) and is therefore a pretty good abbreviation? Most non-technical people rather know the suffix &#34;UTC&#34;, so that one is preferable.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_do_not_rely_on_default_data_source&#34;&gt;Do not rely on &lt;code&gt;default&lt;/code&gt; data source&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Even if you rely on one Prometheus-compatible source in the beginning, you will very likely add more data sources, or migrate to another one, in the future. &lt;strong&gt;Therefore, explicitly define the source in each visualization.&lt;/strong&gt; In jsonnet, use for example &lt;code&gt;grafana.statPanel.new(datasource=&#39;thanos&#39;)&lt;/code&gt;. &lt;strong&gt;In general, do not ever name something &lt;code&gt;default&lt;/code&gt;, anywhere.&lt;/strong&gt; The same applies to the words &#34;old&#34; and &#34;new&#34;, since &#34;new&#34; is always the next &#34;old&#34;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_heatmaps&#34;&gt;Heatmaps&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Those are hard to set up since the UI does not give guidance. You have to set several options correctly to see reasonable results:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Prometheus query example: &lt;code&gt;sum by (le) (increase(prometheus_http_request_duration_seconds_bucket[1m]))&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Query &amp;gt; Format&lt;/em&gt;: Set to &lt;em&gt;Heatmap&lt;/em&gt; instead of &lt;em&gt;Time series&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Visualization&lt;/em&gt;: Choose type &lt;em&gt;Heatmap&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Visualization &amp;gt; Y Axis &amp;gt; Data format&lt;/em&gt;: &lt;em&gt;Time series buckets&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Visualization &amp;gt; Y Axis &amp;gt; Unit&lt;/em&gt;: Choose according to the metric, typically &lt;em&gt;seconds (s)&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Visualization &amp;gt; Y Axis &amp;gt; Decimals&lt;/em&gt;: For &lt;em&gt;seconds (s)&lt;/em&gt; or other time unit, use 0 decimals, as Grafana automatically shows the appropriate text &#34;ms&#34;/&#34;s&#34;/&#34;min&#34;, so the &lt;code&gt;.0&lt;/code&gt; decimal after each axis label is useless. This would best be fixed within Grafana source code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Y axis will only be sorted numerically once you change the query legend to &lt;code&gt;{{le}}&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Visualization &amp;gt; Display &amp;gt; Colors&lt;/em&gt;: I recommend opacity-based coloring with full blue (&lt;code&gt;rgb(0,0,255)&lt;/code&gt;) as strongest color, in order to see things without getting eye strain or having to come close to the monitor. Use a color that is visible with light and dark theme. I would love to see the thresholds feature for the heatmap visualization as well, so that good values can be colored green, and bad ones yellow or red. Right now, colors are assigned by how often a value range (&#34;bucket&#34;) appeared, not by the value itself&amp;#8201;&amp;#8212;&amp;#8201;that means your eyes have to rest on the visualization for some seconds to understand it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Visualization &amp;gt; Tooltip&lt;/em&gt;: Enable, and optionally show the histogram for fast interpretation of the value distribution on mouseover&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;This option seems not available through the UI anymore for Prometheus data sources, but let me put this here for the record: if the visualization is showing too detailed information (too many faded bars), limit &lt;em&gt;Query &amp;gt; Query options &amp;gt; Max data points&lt;/em&gt; to e.g. 24.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code/heatmap.png&#34; alt=&#34;Heatmap visualization&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Instead of a histogram, laying out the information as percentiles on a &lt;em&gt;Stat&lt;/em&gt; visualization may give a faster overview and is preferable on high-level dashboards. For example, p50 (median), p95 and p99 percentiles are often useful. Make sure you use the &lt;code&gt;rate&lt;/code&gt; function inside &lt;code&gt;histogram_quantile&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Example Prometheus query: &lt;code&gt;histogram_quantile(0.95, sum(rate(prometheus_http_request_duration_seconds_bucket[2m])) by (le))&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code/percentiles-stat.png&#34; alt=&#34;3 percentiles in a Stat visualization&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_display_interesting_events_as_annotations&#34;&gt;Display interesting events as annotations&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;a href=&#34;https://grafana.com/docs/grafana/latest/dashboards/annotations/&#34;&gt;Grafana annotations&lt;/a&gt; can mark interesting time points on graphs. Among many imaginable events to enrich on your dashboards, software and infrastructure deployments are the most interesting ones since change in a technology-driven company usually means risk and the potential for failure. In an incident, the starting point is often known quite soon by looking at dashboards. If graphs additionally show whether and when changes were made, you have better chances to find the cause.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Do not bother adding annotations manually (e.g. time window of every deployment), since people will forget the procedure, get the timezone wrong, and it only adds an unnecessary burden which should be automated.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Here is an example how to &lt;em&gt;consistently&lt;/em&gt; show &lt;a href=&#34;https://argo-cd.readthedocs.io/en/stable/&#34;&gt;Argo CD&lt;/a&gt; sync events on your dashboards. Those mostly relate to real deployments. When I developed that query, no better, human-level event type was available. You may want to tweak this to your own use cases.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;listingblock&#34;&gt;
&lt;div class=&#34;content&#34;&gt;
&lt;pre class=&#34;highlight&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;local grafana = import &#39;grafonnet/grafana.libsonnet&#39;;

{
  deployments:: grafana.annotation.datasource(
    name=&#39;Deployments related to payment methods and their infrastructure&#39;,
    datasource=&#39;loki&#39;,
    expr=|||
      {app_kubernetes_io_name=&#34;argocd-application-controller&#34;}
      |~ &#34;reason=(OperationStarted|ResourceUpdated)&#34;
      | logfmt
      | dest_namespace =~ &#34;payment-methods|ingress-nginx&#34;
        and
        msg =~ &#34;(?i).*?(?:initiated.*(?:sync|rollback)|sync status: OutOfSync -&amp;gt; Synced|health status: Progressing -&amp;gt;).*&#34;
      | line_format `App {{.application}}, namespace {{.dest_namespace}}, cluster {{.cluster}}: {{.msg}}`
    |||,
    iconColor=&#39;blue&#39;,
  ),
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;You can now use &lt;a href=&#34;https://grafana.github.io/grafonnet-lib/api-docs/#dashboardnew&#34;&gt;&lt;code&gt;grafana.dashboard.new(&amp;#8230;&amp;#8203;).addAnnotation(deployments)&lt;/code&gt;&lt;/a&gt; to add the annotations to your dashboard.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_self_describing_visualization_titles&#34;&gt;Self-describing visualization titles&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Each visualization&amp;#8217;s title should be self-describing. Bad: &#34;Error rate&#34;. Good: &#34;Payment methods&amp;#8201;&amp;#8212;&amp;#8201;error rate of requests to provider&#34;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;One reason is because you can link to a single visualization which is helpful during incidents to tell others what exactly you are looking at (or to present one detail on a really large TV):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;&lt;span class=&#34;image&#34;&gt;&lt;img src=&#34;/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code/view-single-visualization.png&#34; alt=&#34;View single visualization&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;And again, it helps the eyes to quickly get a full picture instead of having to look at multiple locations on screen.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In Grafana, the dashboard title is always displayed, even for such single-visualization URLs. So if your dashboard is nicely titled &#34;Payment gateway (high-level)&#34;, that will already be a good starting point and you may not even need or want verbose visualization titles.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;For averaging queries like &lt;code&gt;sum(rate(metric[5m]))&lt;/code&gt;, which may constitute most of your dashboards, you should consider adding the interval hint (e.g. abbreviated &lt;code&gt;[5m]&lt;/code&gt;) to the visualization title&amp;#8201;&amp;#8212;&amp;#8201;and/or the Y axis&amp;#8201;&amp;#8212;&amp;#8201;so that users are aware how fast a recovered metric or an error peak will become visible.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_observability_tips_not_specific_to_grafana&#34;&gt;Observability tips not specific to Grafana&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;These tips relate for example to Prometheus query practices and other things that do not require Grafana in the monitoring stack per se.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_stay_consistent_in_naming_metrics_and_labels&#34;&gt;Stay consistent in naming metrics and labels&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The &lt;a href=&#34;https://prometheus.io/docs/practices/naming/&#34;&gt;Prometheus naming practices&lt;/a&gt; page gives very good guidance, such as to use &lt;code&gt;lower_snake_case&lt;/code&gt;, name counters &lt;code&gt;xxx_total&lt;/code&gt; or specify the unit such as &lt;code&gt;xxx_seconds&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_no_need_to_create_a_metric_for_everything_how_to_easily_get_started_monitoring_an_uninstrumented_application&#34;&gt;No need to create a metric for everything / how to easily get started monitoring an uninstrumented application&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The 3 &lt;em&gt;current&lt;/em&gt; pillars of observability&amp;#8201;&amp;#8212;&amp;#8201;metrics, logs and traces&amp;#8201;&amp;#8212;&amp;#8201;may not remain considered the best solution forever. We can expect tooling to try and combine them in the future, such as &#34;metrics from logs&#34; features. You want to observe your applications with minimum instrumentation effort? Then sometimes, a &lt;a href=&#34;https://grafana.com/docs/loki/latest/logql/&#34;&gt;LogQL query&lt;/a&gt; such as &lt;code&gt;sum(count_over_time(&amp;#8230;&amp;#8203; [15m]))&lt;/code&gt; to look for specific log lines may be what you want (temporarily), instead of developing and maintaining a new metric. Beware however that log text tends to change much more frequently than metric names, and how much slower and more expensive it is to query logs. A totally uninstrumented application can easily be monitored if you have access to its logs. Later on, you can make the dashboards more efficient once you learned which indicators are important to show the application health, and which ones are not. Very helpful if you are just getting started with observability.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_show_only_offenders_or_top_n_problematic_items&#34;&gt;Show only offenders or top N problematic items&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;You can use &lt;code&gt;&amp;gt; 0&lt;/code&gt; or &lt;code&gt;topk(&amp;#8230;&amp;#8203;) &amp;gt; 5&lt;/code&gt; to display only offenders in your high-level dashboard (please also read &lt;a href=&#34;#_keep_panels_small_on_screen&#34;&gt;Keep panels small on screen&lt;/a&gt; above).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;For example, the customers with the highest concurrency of API requests. Use &lt;em&gt;Value mappings&lt;/em&gt; feature to map &#34;null&#34; to e.g. &#34;currently low concurrency&#34; for better understanding in humans (since &lt;em&gt;Stat&lt;/em&gt; visualizations always show something). Together with green/yellow/red thresholds, this explains in 2 seconds what the current value is and whether it is problematic. As explained before, use &lt;em&gt;Calculation &amp;gt; Last&lt;/em&gt; if only the latest value is relevant&amp;#8201;&amp;#8212;&amp;#8201;you do not care about the &lt;em&gt;Average&lt;/em&gt; API concurrency over 3 hours while debugging an incident, right?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In our payment example, we could alternatively show the payment methods with the highest rate of errors. Or depending on the business, define each payment method&amp;#8217;s business importance in code and then only show the most critical products with a label filter (e.g. &lt;code&gt;importance=&#34;boss_says_this_is_super_critical&#34;&lt;/code&gt;; or name them &#34;Tier1&#34;, &#34;Tier2&#34;, etc.).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Note that &lt;code&gt;topk(5, &amp;#8230;&amp;#8203;)&lt;/code&gt; may not show you the top 5 items if evaluated for a graph, since the &#34;top 5&#34; are checked for many time points and all resulting items are shown. The same applies to &lt;em&gt;Stat&lt;/em&gt; visualizations&amp;#8201;&amp;#8212;&amp;#8201;unless you choose &lt;em&gt;Instant&lt;/em&gt; to only choose the end time point, but that can falsify the desired data to show. If you really want only up to 5 items to be shown, use the &lt;a href=&#34;https://prometheus.io/blog/2021/02/18/introducing-the-@-modifier/&#34;&gt;&lt;code&gt;@ end()&lt;/code&gt; modifier&lt;/a&gt; to evaluate only the latest top-5 values in the range (thanks to a blog reader for pointing this out! – available since Prometheus v2.25.0).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_mind_test_and_synthetic_traffic&#34;&gt;Mind test and synthetic traffic&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In a modern infrastructure, you might run synthetic &lt;strong&gt;test traffic&lt;/strong&gt; to verify the end-to-end health of your applications. Since those are not from real customers, you should &lt;strong&gt;check if that should be shown differently or excluded&lt;/strong&gt; from certain dashboards or visualizations.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_daytime_vs_nighttime&#34;&gt;Daytime vs. nighttime&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;If your business is mostly in a certain region or timezone of the world, such as European payments, traffic goes down at night. Consider different error and request thresholds at day and night, respectively. Visualizations should be clearly distinguished with e.g. 🔆 or 🌒 in the title.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Prometheus allows the time distinction with &lt;code&gt;and&lt;/code&gt;/&lt;code&gt;unless hour() &amp;gt;=6 &amp;lt;21&lt;/code&gt;. This can be tricky, though: in special cases such as calculations &lt;code&gt;sum(&amp;#8230;&amp;#8203;)/sum(&amp;#8230;&amp;#8203;) and hour() &amp;gt;=6 &amp;lt;21&lt;/code&gt;, label set matching will surprise you with an empty result. Example to fix that: &lt;code&gt;(sum by (something) (rate(some_metric[15m]))) / sum by (something) (rate(some_metric2[15m])) and ignoring(something) hour() &amp;gt;=6 &amp;lt;21&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;This is cumbersome and should be avoided for the start, unless you really need such a strong distinction by time.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_do_not_use_rate_alone&#34;&gt;Do not use &lt;code&gt;rate(&amp;#8230;&amp;#8203;)&lt;/code&gt; alone&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;The same applies to calculations like &lt;code&gt;rate(&amp;#8230;&amp;#8203;) / rate(&amp;#8230;&amp;#8203;)&lt;/code&gt;. Why? Any change to the labels will make them explode into many series. Combine &lt;code&gt;rate&lt;/code&gt; with &lt;code&gt;sum&lt;/code&gt; or &lt;code&gt;sum by&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_prefer_counters_over_gauges&#34;&gt;Prefer counters over gauges&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;A &lt;a href=&#34;https://prometheus.io/docs/concepts/metric_types/&#34;&gt;counter&lt;/a&gt; in Prometheus represents a value that can only increase. In contrast, a gauge can take an arbitrary value.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;In regular scrape intervals, a metric&amp;#8217;s value gets collected by Prometheus. A longer scrape interval means less storage and cost, but can mean that a short spike of a gauge&amp;#8217;s value is not stored at all, and therefore also will not produce an alert. So prefer a counter if possible for your for use case, since its value does not lose increments (but on the other hand, it &lt;em&gt;only&lt;/em&gt; supports increments).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Good example for using a gauge: queue size. Items can be processed, i.e. removed from the queue, or added. The more interesting metrics for queues however are error rate and per-item processing time.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect2&#34;&gt;
&lt;h3 id=&#34;_make_observed_components_distinguishable&#34;&gt;Make observed components distinguishable&lt;/h3&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;To find a root cause quickly in case of problems, dashboards must allow drilling down into details. In our example of payment methods as products, each of them could fail separately, or several/all at once. This must be visible in visualizations and alert messages.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Examples why this distinction is important:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;1 payment method failing&amp;#8201;&amp;#8212;&amp;#8201;only that application&amp;#8217;s code might be affected, for example from a bad change recently deployed&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Multiple payment methods failing&amp;#8201;&amp;#8212;&amp;#8201;perhaps those have something in common, such as serving traffic from a certain cloud region or Kubernetes cluster, or which are otherwise special (in the middle of a migration, feature toggled, traffic pattern changed, rate limit of database reached, etc.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;All payment methods failing&amp;#8201;&amp;#8212;&amp;#8201;bad code change affecting all those applications was introduced, networking issues, infrastructure down, other catastrophic scenario&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;Other ideas for details to drill down into: per customer, per Kubernetes cluster, per cloud region, per API endpoint. For some of these, you may be able to leverage variables (mind &lt;a href=&#34;#_avoid_dropdowns_for_variable_values&#34;&gt;Avoid dropdowns for variable values&lt;/a&gt;), while some value ranges may simply be too large&amp;#8201;&amp;#8212;&amp;#8201;for instance if you have a million customers&amp;#8201;&amp;#8212;&amp;#8201;and you should rather show the top N problematic ones (&lt;a href=&#34;#_show_only_offenders_or_top_n_problematic_items&#34;&gt;Show only offenders or top N problematic items&lt;/a&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_summary&#34;&gt;Summary&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;paragraph&#34;&gt;
&lt;p&gt;I showed how high-level dashboards and main business metrics cover most of your monitoring and incident resolution needs. On top of that, the article explains the advantages of dashboards as code and how to apply that concept, using jsonnet, the Grafonnet library and working scripts to integrate in your developer and CI/CD/GitOps workflow. Lastly, I listed the best practices for dashboard creation and visualization so that your monitoring becomes easier and faster to use.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_out_of_scope&#34;&gt;Out of scope&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Detailed &lt;strong&gt;relation to logs, traces, alerting, and other tools&lt;/strong&gt;. Great dashboards can help you shape alerting&amp;#8201;&amp;#8212;&amp;#8201;particularly, I mean that if you have built an understandable and quickly navigable dashboard without any clutter, then alerts should cover those observed areas. For example, if your revenue is driven by successful outcomes of payments, that should be on your main dashboard of the payment gateway, and represented in alerts. Such a high-level alert can replace a hundred fine-grained alerts. How? Here&amp;#8217;s an example alert: &#34;for payment method SuperFastPay, alert if there are more than 50 failed payments per minute&#34; (set this value based on an expected failure rate). Once such an alert is received, and the on-call engineer opens the main dashboard, or the SuperFastPay-specific dashboard (if that even makes sense), it should show red for that component. The detailed dashboard may show things like failure type statistics based on metrics, or the most common recent errors in logs. If it shows you mainly internet/connectivity issues, follow your way to the payment logs and infrastructure dashboards, for example (which at best would be linked). In the end, you may find that one of your cloud availability zones A/B/C, in which the software runs, does not have internet access. And that only by getting alerted about the most important business symptom, not because you had put large effort into monitoring internet connectivity from those availability zones. If only your dashboards make sense, allowing you to navigate quickly from symptom to root cause, you can probably live with fewer alert definitions overall. This example is not from production, but a wild dream of mine if all the suggestions are optimally applied. Surely you still want alerts for symptoms in infrastructure/platform/network, particularly if the company reaches a scale where those are handled by separate teams, but those alerts then may not need highest priority (&#34;P1&#34;)&amp;#8201;&amp;#8212;&amp;#8201;while business-critical symptoms like failing payments of your customers should be P1 alerts. The fewer high priority alerts you have, the better people&amp;#8217;s work life, sleep and therefore productivity will be.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;How hard it is to convince people of doing dashboards in code. There are very valid points against it, such as the missing WYSIWYG support as of 2022-04. Those can mostly be resolved with good tooling or a reasonable &#34;how to develop a dashboard&#34; README file. Other concerns are often just opinionated, and you will simply need to take the decision &#34;do we allow it to become a mess or not&#34;. I recommend vendors to make codifying resources easier, so that even less technical people will be able to work with this concept. Exporting a visually-crafted dashboard to JSON is unfortunately not a solution, since that diminishes many of the advantages explained in this article (such as consistency).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;strong&gt;article is all about live monitoring of a service/system&lt;/strong&gt; which could have incidents at any time. For example, an API serving requests for customers. There are lots of &lt;strong&gt;other use cases&lt;/strong&gt; where monitoring, alerting and tracing may help, such as performance issues, SLOs, business statistics and intelligence.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Accessibility&lt;/strong&gt; / color blindness support. Red and green may not be the best options, but I do not have the experience to give help here.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Installation and maintenance of the observability stack&lt;/strong&gt; does not belong in this article. Dashboards are most helpful if you can also look at &lt;strong&gt;historical data&lt;/strong&gt; and not only use them for short-term review of incidents. Therefore, prefer using &lt;strong&gt;long-term storage&lt;/strong&gt; such as &lt;a href=&#34;https://thanos.io/&#34;&gt;Thanos&lt;/a&gt; or &lt;a href=&#34;https://grafana.com/oss/cortex/&#34;&gt;Cortex&lt;/a&gt; (and since recently in March 2022: &lt;a href=&#34;https://grafana.com/blog/2022/03/30/announcing-grafana-mimir/&#34;&gt;Mimir&lt;/a&gt;). Those solutions provide a very good backup solution as well.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The current &lt;strong&gt;jsonnet+Grafonnet solution for generated dashboards is not the final stage of evolution&lt;/strong&gt;. Tooling like &lt;a href=&#34;https://aws.amazon.com/de/cdk/&#34;&gt;CDK&lt;/a&gt; could be adapted so dashboards can be written in a Grafana-agnostic way, using great languages like TypeScript. For now, if you go with jsonnet, I recommend you &lt;strong&gt;implement common functions&lt;/strong&gt; that abstract the Grafana details away and &lt;strong&gt;set reasonable defaults everywhere&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Observing only the main business metric(s) is not sufficient.&lt;/strong&gt; Particularly when you have split into several engineering teams or even have a platform infrastructure / DevOps / SRE team, specific monitoring depending on the teams&#39; respective responsibility makes a lot of sense. In our example business, watching the health of partner or provider companies can make sense, since they may not have the most modern health monitoring in place. For examples, Grafana Labs has acquired &lt;a href=&#34;https://github.com/grafana/k6&#34;&gt;k6&lt;/a&gt; which can be used for load tests, but in the future hopefully also to &lt;a href=&#34;https://github.com/grafana/k6/issues/2498&#34;&gt;monitor TLS certificate expiry&lt;/a&gt; (until that feature exists, &lt;a href=&#34;https://github.com/prometheus/blackbox_exporter&#34;&gt;Blackbox exporter&lt;/a&gt; is a reasonable tool). Try a &#34;pre-mortem&#34; brainstorming session to think of what could go wrong, and you will find many things to monitor which are not covered by the main metrics. Consider also &#34;value &lt;em&gt;under&lt;/em&gt; threshold&#34; checks, since an error rate of zero could simply come from zero requests per second, and that can mean a whole service or feature is not working, or customers cannot reach your API.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Recommendations in this article were collected mainly in 2020-2021, before &lt;strong&gt;&lt;a href=&#34;https://grafana.com/oss/tempo/&#34;&gt;Tempo&lt;/a&gt;/tracing, &lt;a href=&#34;https://grafana.com/docs/grafana/latest/basics/exemplars/&#34;&gt;exemplars&lt;/a&gt; and &lt;a href=&#34;https://github.com/grafana/k6&#34;&gt;k6&lt;/a&gt;&lt;/strong&gt; were in wide-spread use. All these can prove helpful in combination with metrics-based monitoring.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Training.&lt;/strong&gt; As mentioned, I think a good solution survives without training, but instead has &lt;strong&gt;proper and concise documentation, and the code speaks for itself&lt;/strong&gt;. There are very few professional training and recommendation videos on the internet around dashboarding, and the available beginner content often showcases &#34;The more metrics/graphs on a dashboard, the better&#34; 😬. I cannot disagree more, so please try my &#34;high-level dashboard + most important business metric&#34; approach first and see if you prefer that, or rather a jungle of messy, unreviewed stuff which fosters a useless and long-winded tooling replacement every 2-3 years. See also the Grafana webinar &lt;a href=&#34;https://grafana.com/go/webinar/guide-to-dashboard-design/&#34;&gt;Getting started with Grafana dashboard design&lt;/a&gt; for a gentle introduction which requires less upfront knowledge about Grafana compared to my article. The video however has some examples where dashboards are too crowded for my taste.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Advanced observability features.&lt;/strong&gt; Grafana and its competitors offer quite interesting features such as &lt;a href=&#34;https://docs.datadoghq.com/monitors/create/types/anomaly/&#34;&gt;anomaly detection (Datadog)&lt;/a&gt; (also &lt;a href=&#34;https://blog.davidvassallo.me/2021/10/01/grafana-prometheus-detecting-anomalies-in-time-series/&#34;&gt;possible with Prometheus&amp;#8201;&amp;#8212;&amp;#8201;interesting blog post&lt;/a&gt;), &lt;a href=&#34;https://sentry.io/for/full-stack/&#34;&gt;error/crash tracking (Sentry)&lt;/a&gt; and others. Those deserve a place on dashboards if reasonably applicable to your products.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Auto-deletion of manually authored changes&lt;/strong&gt;: Remember my term &lt;em&gt;Deleteday&lt;/em&gt; from above? Make sure to implement that. At best, your deployment from CI simply takes care to replace all existing dashboards, including those not created by code. Think of the deployment like &lt;code&gt;rsync -a --delete committed-dashboards production-grafana-instance&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;sect1&#34;&gt;
&lt;h2 id=&#34;_related_reading&#34;&gt;Related reading&lt;/h2&gt;
&lt;div class=&#34;sectionbody&#34;&gt;
&lt;div class=&#34;ulist&#34;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=YE2aQFiMGfY&#34;&gt;Fool-Proof Kubernetes Dashboards for Sleep-Deprived Oncalls - David Kaltschmidt, Grafana Labs&lt;/a&gt; explains maturity levels of using dashboards, and provides other ideas than my article. I did not take any ideas from that talk, as I had watched it only later, so it is a very interesting addition.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://sre.google/sre-book/being-on-call/&#34;&gt;Google SRE book: Being On-Call chapter&lt;/a&gt; contains many important points, including why stress and cognitive load for humans on-call must be reduced by any means, for the sake of both employee and company health. I recommend skimming through all parts of the free book which seem relevant for you (even if you now scream &#34;We are not Google!&#34;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There are many links to Grafana documentation and other tools within this article. Give them a read, and look for realistic examples that you can try.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
				<guid>https://andidog.de/blog/2022-04-21-grafana-dashboards-best-practices-dashboards-as-code</guid>
			</item>
		

	</channel>
</rss>
