<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Kevin Petremann</title>
    <description>The latest articles on Forem by Kevin Petremann (@k_petrem).</description>
    <link>https://forem.com/k_petrem</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F916892%2F5c719739-624b-4ef4-bf5a-f6d444fc83c9.jpg</url>
      <title>Forem: Kevin Petremann</title>
      <link>https://forem.com/k_petrem</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/k_petrem"/>
    <language>en</language>
    <item>
      <title>How I do technology watch</title>
      <dc:creator>Kevin Petremann</dc:creator>
      <pubDate>Thu, 07 Mar 2024 08:19:02 +0000</pubDate>
      <link>https://forem.com/k_petrem/how-i-do-technology-watch-lmf</link>
      <guid>https://forem.com/k_petrem/how-i-do-technology-watch-lmf</guid>
      <description>&lt;h2&gt;
  
  
  A vast world
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgh9yqdskvoxjgrxqn7pu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgh9yqdskvoxjgrxqn7pu.png" alt="Image description" width="600" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The current IT ecosystem has one main characteristic: this is a wide and rapidly growing range of topics. Every day, a new project, library or application emerges. It can be about databases, observability, cloud, systems, network, programming and so on. These topics can be quite broad themselves, e.g. programming itself covers a LOT of things. We live in a fabulous time for tech enthusiasts. But there is one issue: how to follow this big fast train?!&lt;/p&gt;

&lt;p&gt;This article aims to share my tips to navigate all of this. Of course, I don’t know all the tricks, and mine may not be suitable for you. But if you have your own, feel free to share them in the comments!&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub
&lt;/h2&gt;

&lt;p&gt;The Open Source community is an amazing driver for innovation. When it comes to Open Source, one place stands out: GitHub. This is a great place to start our daily routine.&lt;/p&gt;

&lt;p&gt;GitHub provides some useful tools: Trending and Explore.&lt;/p&gt;

&lt;p&gt;The first one exposes current trends. If you use it correctly, it will allow you to discover great projects. I set ‘Today’ to the date range filter to have finer results, as the other values tend to be more static. I also like navigating between languages I use the most, like Go or Python. This can help you discover specific libraries which might be useful to you later.&lt;/p&gt;

&lt;p&gt;The second tool is Explore, which is a curated list of projects that might interest you based on your GitHub usage. The main downside is the same as on social media: you stay in your bubble, and it does not help you discover new topics. But it is still a useful tool.&lt;/p&gt;

&lt;p&gt;Bonus: reading source code can help you improve your programming skills. Even if every piece of code is not perfect, you might learn new approaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Awesome Lists and newsletter
&lt;/h2&gt;

&lt;p&gt;Awesome lists are community driven repositories that provide a list of software or resources on many topics. They are often good starting points to find what you need.&lt;/p&gt;

&lt;p&gt;An easy way to find them is to search “[topic] awesome list” in the search engine of your choice.&lt;/p&gt;

&lt;p&gt;Some examples of awesome lists:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go: &lt;a href="https://github.com/avelino/awesome-go" rel="noopener noreferrer"&gt;https://github.com/avelino/awesome-go&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Python: &lt;a href="https://github.com/vinta/awesome-python" rel="noopener noreferrer"&gt;https://github.com/vinta/awesome-python&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;IoT: &lt;a href="https://github.com/phodal/awesome-iot" rel="noopener noreferrer"&gt;https://github.com/phodal/awesome-iot&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Kubernetes: &lt;a href="https://github.com/tomhuang12/awesome-k8s-resources" rel="noopener noreferrer"&gt;https://github.com/tomhuang12/awesome-k8s-resources&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Newsletters are also a way to receive curated content. I have to admit, I don’t follow many, and I prefer websites or RSS feeds. My favorite is &lt;a href="https://golangweekly.com/" rel="noopener noreferrer"&gt;Golang Weekly&lt;/a&gt;, which promotes articles, code and tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Social media
&lt;/h2&gt;

&lt;p&gt;I do not like social media. But I successfully tuned my Twitter account.&lt;/p&gt;

&lt;p&gt;The idea here is to play with the famous algorithm, to let Twitter know you are interested in software development, or any other tech topic you like. After some time, you end up with a social media showing off useful information.&lt;/p&gt;

&lt;p&gt;If you already have an account, I suggest creating a dedicated one.&lt;/p&gt;

&lt;p&gt;Some examples of the accounts I like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://twitter.com/golangch" rel="noopener noreferrer"&gt;golangch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/GolangTrends" rel="noopener noreferrer"&gt;GolangTrends&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/pycoders" rel="noopener noreferrer"&gt;pycoders&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/ThePracticalDev" rel="noopener noreferrer"&gt;ThePracticalDev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Video, podcast, blog
&lt;/h2&gt;

&lt;p&gt;Another channel that can be leveraged is what I would put under the “content creation” umbrella. Twitch, YouTube, blogs, podcasts are ideal places for everyone to share their knowledge and passion. As with any subject, there is of course good content and not so good content.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I often go to dev.to to see if some articles catch my attention.&lt;/li&gt;
&lt;li&gt;I also like ThePrimeagen - I guess many people watch his channel - who comments on content such as articles or videos, and shares his takes. Bonus point: he brings fun into it!&lt;/li&gt;
&lt;li&gt;There are many content creators sharing tips and tricks, The Linux Experiment, Jonathan Blow, and so on. Just pick the ones you like.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Don’t fall into the trap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw062uvgwlze1pt5f0qza.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw062uvgwlze1pt5f0qza.png" alt="Image description" width="553" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As mentioned earlier, there are a bunch of new things every day. This creates many new trends, some shorter than others. The trap here is to follow every trend. It is ok to be curious and enthusiastic, but do not change your stack too often.&lt;/p&gt;

&lt;p&gt;Do not think you can try and follow everything! There is simply too much. On the one hand this is a good thing because you can literally learn something new every day. On the other hand this is also a bad thing, because you can quickly feel overwhelmed. This prevents you from deepening your skills or knowledge because trying to do too many things keeps you on the surface. It is important to have many skills and many tools, but it is also important to sometimes go deeper. But, make sure to keep time for yourself and your loved ones too!&lt;/p&gt;

&lt;p&gt;You should prioritize. Do tests and experiments if you have enough time. If you do not, you can always bookmark your new find and come back later to see if you are still interested.&lt;/p&gt;

&lt;p&gt;Last but not least, you can also participate by sharing what you found with your colleagues.&lt;/p&gt;

&lt;h2&gt;
  
  
  A great time to live
&lt;/h2&gt;

&lt;p&gt;We live in a wonderful time, where millions of things are available. You just need to get organized to enjoy all of this :)&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Salt Exporter: the story behind the tool</title>
      <dc:creator>Kevin Petremann</dc:creator>
      <pubDate>Thu, 05 Oct 2023 11:00:00 +0000</pubDate>
      <link>https://forem.com/k_petrem/salt-exporter-the-story-behind-the-tool-56ml</link>
      <guid>https://forem.com/k_petrem/salt-exporter-the-story-behind-the-tool-56ml</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;In a nutshell&lt;/strong&gt;&lt;br&gt;
I have written a Saltstack Prometheus exporter in Go and I am here to share my experience working on it.&lt;/p&gt;

&lt;p&gt;It is fully open-source:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/kpetremann/salt-exporter" rel="noopener noreferrer"&gt;Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kpetremann.github.io/salt-exporter/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Infrastructure and development
&lt;/h2&gt;

&lt;p&gt;When talking about tech, I like many things…&lt;/p&gt;

&lt;h3&gt;
  
  
  Prometheus
&lt;/h3&gt;

&lt;p&gt;I like Prometheus, and I like to write Prometheus exporters. It truly is a game changer when you need to expose service metrics to get fancy dashboards and alerts. The metrics are elegant, efficient, and easy to operate thanks to PromQL. They are also easy to integrate to any development project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Metrics:
salt_expected_responses_total{function="cmd.run", state=""} 6
salt_function_responses_total{function="cmd.run",state="",success="true"} 6

// Prometheus query to get number missing responses:
salt_expected_responses_total - on(function) salt_function_responses_total

// elegant, is it not?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Saltstack
&lt;/h3&gt;

&lt;p&gt;I like Salt to manage and operate multiple systems. It is one of the most known infrastructure automation system, among Ansible, Chef, Puppet and so on. I am using it for different needs, at work, for my home lab, and also for several associations I am operating the infrastructure for. The system is not perfect, but from my point of view it is one of the best (some might disagree and it is totally fine).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;salt &lt;span class="s2"&gt;"*"&lt;/span&gt; state.sls do_awesome_stuffs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Coding!
&lt;/h3&gt;

&lt;p&gt;There is also another thing I really enjoy doing: writing code. For the past 7 years I have been writing Python code, before that it was C++/C# and Java. But a couple of years ago, I found a new language to play with: &lt;a href="https://go.dev/" rel="noopener noreferrer"&gt;Golang&lt;/a&gt;. I may repeat myself in the adjectives, but Go is elegant, easy to learn and quite powerful.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="c"&gt;// straightforward concurrency!!&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;
    &lt;span class="c"&gt;// …&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// elegant, is...? (am I repeating myself?)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Open Source
&lt;/h3&gt;

&lt;p&gt;There is one last thing to add to the "I like" list: &lt;strong&gt;Open Source&lt;/strong&gt; :)&lt;/p&gt;

&lt;p&gt;It is always good to see that your work benefits to people. And if you are lucky enough, they can even contribute by reporting issues, requesting features or submitting changes. Most importantly, you do not need to have a big and well known project to start seeing people using it and contributing to it.&lt;/p&gt;

&lt;p&gt;By making it open-source, you usually end up with a better project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;features you did not think about&lt;/li&gt;
&lt;li&gt;fix of bugs you never encountered with your usecases&lt;/li&gt;
&lt;li&gt;a documentation you would have not written for yourself&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is something I was lucky to experience with my previous open-source project (&lt;a href="https://github.com/kpetremann/mqtt-exporter" rel="noopener noreferrer"&gt;mqtt-exporter&lt;/a&gt;) which reinforced my wish to continue on the Open Source journey.&lt;/p&gt;

&lt;h2&gt;
  
  
  The project: salt-exporter
&lt;/h2&gt;

&lt;p&gt;You might have noticed, I am kind of an enthusiast regarding technologies, especially regarding infra and code. &lt;strong&gt;Most importantly I like to mix them both.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You might wonder why I am telling you all of this.&lt;/p&gt;

&lt;p&gt;Well, I had what seems to be a simple need: metrics to know the good health of Salt jobs. It was a perfect opportunity to try my new preferred cocktail 🍸: some Salt, some Prometheus, some Go, with a pinch of Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  Obvious approaches != best approaches
&lt;/h2&gt;

&lt;p&gt;First thing first, to get metrics I needed to find the appropriate way to get the data.&lt;/p&gt;

&lt;p&gt;The first obvious approach was to leverage the Salt API. However, the API module is not running nor configured by default. Using it would mean requiring the users to start and monitor the Salt API. Users would also need to change the configuration of the Salt master to configure the authentication system and fine tune the permissions.&lt;/p&gt;

&lt;p&gt;My focus is always to have something that &lt;strong&gt;works out of the box&lt;/strong&gt; limiting any requirements to the minimum . &lt;strong&gt;Method rejected!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Another approach would be to create a Salt &lt;a href="https://docs.saltproject.io/en/latest/topics/engines/index.html#engines" rel="noopener noreferrer"&gt;engine&lt;/a&gt; or &lt;a href="https://docs.saltproject.io/en/latest/ref/returners/index.html" rel="noopener noreferrer"&gt;returner&lt;/a&gt;. But this would mean writing the exporter in Python while I want to write it in Go (because why not). And again, too much configuration to my taste. I had a feeling that I could create something that even the Salt master would ignore the existence of. &lt;strong&gt;Methods rejected!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deep dive in Salt internals
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8yz3lycfwgq5a1d1yh1g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8yz3lycfwgq5a1d1yh1g.png" alt="salt-internals" width="800" height="992"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To be completely honest with you, my first idea was actually to connect to the ZMQ of Salt. But I wanted to explore the other "interfaces" Salt is providing. Anyway, the ZMQ was now my best shot, or so I thought...&lt;/p&gt;

&lt;p&gt;To better understand how ZMQ was integrated, I read carefully the well written &lt;a href="https://docs.saltproject.io/salt/user-guide/en/latest/topics/execution-architecture.html" rel="noopener noreferrer"&gt;Salt architecture documentation&lt;/a&gt;. This very interesting reading was suddenly interrupted by one specific sentence:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The EventPublisher picks it up and distributes it to all connected event listeners on master_event_pub.ipc.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;💡 Eureka! It immediately appeared to me that this was my way into the Salt brain. I knew about IPC, but I never played with it. &lt;em&gt;Yay, something new to play with!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;IPC means inter-process communication. There are multiple methods to implement it. The only thing you need to know here is that Saltstack uses IPC sockets - which is like network communication but using a file.&lt;/p&gt;

&lt;p&gt;I also read that Salt was using &lt;a href="https://msgpack.org/" rel="noopener noreferrer"&gt;MessagePack&lt;/a&gt; to format their messages. MessagePack is a format like JSON, but more compact.&lt;/p&gt;

&lt;p&gt;See below an example of code to connect to the &lt;code&gt;master_event_pub.ipc&lt;/code&gt; file and then read and decode the MessagePack payload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;eventBus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"unix"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/var/run/salt/master/master_event_pub.ipc"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;decoder&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;msgpack&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventBus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;decoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DecodeMap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, the decoded message still needed work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{}{&lt;/span&gt;
  &lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="s"&gt;"head"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{}{},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The event details was in the &lt;code&gt;body&lt;/code&gt;. It almost looked like MessagePack but with a catch. This is where the deep dive in Salt architecture went deeper: I explored the source code of Salt. Fortunately, Salt developers wrote a comprehensive docstring explaining their intent:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the new style, when the tag is longer than 20 characters, an end of tag string is appended to the tag given by the string constant TAGEND, that is, two line feeds '\n\n'.  When the tag is less than 20 characters then the tag is padded with pipes "|" out to 20 characters as before.  When the tag is exactly 20 characters no padded is done.&lt;br&gt;
&lt;em&gt;source: &lt;a href="https://github.com/saltstack/salt/blob/master/salt/utils/event.py" rel="noopener noreferrer"&gt;https://github.com/saltstack/salt/blob/master/salt/utils/event.py&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The trick was that the topic was outside the MessagePack structure of the &lt;code&gt;body&lt;/code&gt;. So I wrote a quick function to parse the payload properly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SaltEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SplitN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;eventContent&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="c"&gt;// Parse message body&lt;/span&gt;
    &lt;span class="n"&gt;ev&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SaltEvent&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Tag&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;msgpack&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SaltEvent&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;note: The downside of reading from the IPC is that the exporter would be impacted if Salt changed the way its different processes communicate. But it is ok, I already have plenty of ideas to adapt if such cases happen.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Expose the metrics
&lt;/h2&gt;

&lt;p&gt;We have the events, the only remaining part was to expose these metrics.&lt;/p&gt;

&lt;p&gt;Again, Prometheus metrics were really easy to implement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"github.com/prometheus/client_golang/prometheus/promauto"&lt;/span&gt;

&lt;span class="n"&gt;newJobTotal&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;promauto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewCounterVec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;prometheus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CounterOpts&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"salt_new_job_total"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Help&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Total number of new jobs processed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"function"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;newJobTotal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithLabelValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"state.sls"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Inc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I just needed to make these metrics accessible from a webserver:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/prometheus/client_golang/prometheus/promhttp"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/metrics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;promhttp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;httpServer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Addr&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"0.0.0.0:2112"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;httpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Voilà.&lt;/p&gt;

&lt;p&gt;I had now everything I needed to fully write my exporter with all the requirements I had: something working out of the box without configuration in Salt and without possible impact on Salt itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Experience
&lt;/h2&gt;

&lt;p&gt;Let's talk a little about coding!&lt;/p&gt;

&lt;h3&gt;
  
  
  Go vs Python
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffe9mrsqzfp8x69p3k7zn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffe9mrsqzfp8x69p3k7zn.png" alt="go-vs-python" width="487" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was not my first Go project. But it was my first project using the Prometheus library.&lt;/p&gt;

&lt;p&gt;The development of the exporter was pleasant. Go itself is really easy to scale up using goroutines. It is good to play with concurrency without having to worry about &lt;a href="https://realpython.com/python-gil/" rel="noopener noreferrer"&gt;GIL&lt;/a&gt;, or about multiprocessing implementation, or about using asyncio compatible libraries, or even having to choose between threads, processes and async. In Go, everything is straightforward while allowing more control than in Python.&lt;/p&gt;

&lt;p&gt;The other aspects I really like about Go is its dependency management and how easy it is to build a binary. On the contrary, Python is an interpreted language, so you have to deal with dependencies at runtime, and packaging your code can be quite annoying.&lt;/p&gt;

&lt;p&gt;Building a Go program is simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go build ./...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Distributing a Go program is simple, and it is even better with GoReleaser and GitHub Actions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# GitHub actions job&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;goreleaser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run GoReleaser&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;goreleaser/goreleaser-action@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;distribution&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;goreleaser&lt;/span&gt;
          &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latest&lt;/span&gt;
          &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;release --clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;note: if you want a GoReleaser example, you can find the one I use &lt;a href="https://github.com/kpetremann/salt-exporter/blob/main/.goreleaser.yaml" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Last but not least, I really appreciate coming back to a typed language.&lt;/p&gt;

&lt;p&gt;I will not go deeper in the comparison of Go versus Python, there are a ton of articles out there. I really like both, but I have to admit the more I write Go code, the less I want to write Python code.&lt;/p&gt;

&lt;p&gt;But in the end, what really matters is to pick the most appropriate language for you and your project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inconsistencies?
&lt;/h3&gt;

&lt;p&gt;The most annoying aspect of the development was the inconsistency in some of Salt's internal behavior.&lt;/p&gt;

&lt;p&gt;For example, failing scheduled jobs sometimes return &lt;code&gt;success=true&lt;/code&gt;, sometimes &lt;code&gt;success=false&lt;/code&gt;. I found some GitHub issues about it, but nothing to explain the inconsistency. It was easy to find a safe workaround, but I will probably have a look at this particular issue to fix it at the source.&lt;/p&gt;

&lt;h3&gt;
  
  
  Salt security
&lt;/h3&gt;

&lt;p&gt;Earlier in the article I said "I immediately started to see events in MessagePack format", some of you might have noticed that it should not be that easy. Well, you would be right, but it is not as bad as you think.&lt;/p&gt;

&lt;p&gt;Prior to Salt 3006, the IPC file permissions were too permissive. Any user logged on the server could read the IPC, and then see all the events. By listening to these events, in certain situations, anyone could catch interesting information such as secrets. "But, there are no secrets in the events" some might argue, and you would be mostly right. But what if a user runs the command &lt;code&gt;pillar.items&lt;/code&gt;... anyone could get the result from the event queue. Reminder: pillars can be used to share secrets from the master to the minion…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;salt &lt;span class="s2"&gt;"*"&lt;/span&gt; pillar.items
node1:
    &lt;span class="nt"&gt;----------&lt;/span&gt;
    token: myVeryImportantSecretToken
    password: myVeryImportantAdminPassword
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anyway, after reaching them out, the Saltstack team fixed this issue and hardened the Salt Master in 3006 version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time to wrap up
&lt;/h2&gt;

&lt;p&gt;Yes, you see me coming... I &lt;strong&gt;liked&lt;/strong&gt; working on this exporter.&lt;/p&gt;

&lt;p&gt;It has been really cool to read tons of Python code when diving into the Salt codebase. I have deepened my knowledge in Salt making it easier for me to do advanced troubleshooting and design.&lt;/p&gt;

&lt;p&gt;Writing the exporter itself has been quite satisfying too. As expected, Go brought great performance and scalability, while keeping it maintainable. The build and distribution of the exporter was very easy to implement and automate.&lt;/p&gt;

&lt;p&gt;Next time I will talk about how a development tool became an actual debug/operation tool for production (spoiler, it is called Salt Live and it is on the same repository than Salt-exporter).&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Salt Exporter repository: &lt;a href="https://github.com/kpetremann/salt-exporter" rel="noopener noreferrer"&gt;https://github.com/kpetremann/salt-exporter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Documentation: &lt;a href="https://kpetremann.github.io/salt-exporter/" rel="noopener noreferrer"&gt;https://kpetremann.github.io/salt-exporter/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>prometheus</category>
      <category>saltstack</category>
      <category>salt</category>
      <category>go</category>
    </item>
  </channel>
</rss>
