<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: CatBytes Community</title>
    <description>The latest articles on DEV Community by CatBytes Community (@catbytes-community).</description>
    <link>https://dev.to/catbytes-community</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F10782%2F8ebbbdd2-54c5-4762-b006-3701e559e5c0.jpeg</url>
      <title>DEV Community: CatBytes Community</title>
      <link>https://dev.to/catbytes-community</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/catbytes-community"/>
    <language>en</language>
    <item>
      <title>Send Node.js logs from Docker to Grafana Cloud with Alloy</title>
      <dc:creator>aliona matveeva</dc:creator>
      <pubDate>Fri, 02 May 2025 10:34:30 +0000</pubDate>
      <link>https://dev.to/catbytes-community/send-nodejs-logs-from-docker-to-grafana-cloud-with-alloy-54b5</link>
      <guid>https://dev.to/catbytes-community/send-nodejs-logs-from-docker-to-grafana-cloud-with-alloy-54b5</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;tl;dr:&lt;/em&gt;&lt;/strong&gt; alloy config, docker-compose.&lt;/p&gt;

&lt;p&gt;Any service that's meant to live more than couple of weeks eventually reaches the stage where you feel the need to properly monitor it. You usually start with simple &lt;code&gt;console.log&lt;/code&gt; logging, but soon realize it's not readable enough, it's not searchable enough and it's only available on your server. Probably inside Docker container.&lt;/p&gt;

&lt;p&gt;I was exactly at that point, annoyed by constant need to &lt;code&gt;ssh&lt;/code&gt; into my server to check one log line. I've wanted to play with Grafana ecosystem for a while, too. So it seemed to be the perfect moment.&lt;/p&gt;

&lt;p&gt;In this post, I’ll walk you through a simple and minimal setup that streams my &lt;strong&gt;Node.js&lt;/strong&gt; application's logs into the &lt;strong&gt;Grafana Cloud&lt;/strong&gt; dashboard using &lt;strong&gt;Grafana Alloy&lt;/strong&gt; and &lt;strong&gt;Loki&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;This is what my final setup looks like:&lt;/p&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%2Ftl1fmtlnzctqlma68xwi.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%2Ftl1fmtlnzctqlma68xwi.png" alt="Final setup with Grafana" width="685" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s break down how to make it work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Producing Logs
&lt;/h2&gt;

&lt;p&gt;I'm using &lt;code&gt;pino&lt;/code&gt; to generate logs from my service. I won't dive deep into the setup as the library outputs raw JSON to stdout by default. An example log line would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"time"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1746117737323&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"pid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"hostname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"96773881a0b3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"server.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"development"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"msg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Server is running"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docker’s default logging behavior captures all stdout and stderr from your container and writes them into a file. &lt;code&gt;json-file&lt;/code&gt; is the default logging driver in Docker, you can confirm this using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker info --format '{{.LoggingDriver}}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also find out the actual log file location for a specific container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker inspect -f '{{.LogPath}}' &amp;lt;container&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this exactly what &lt;strong&gt;Alloy&lt;/strong&gt; will be reading and forwarding to &lt;strong&gt;Grafana Cloud&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Onboarding to Grafana Cloud and Setting Up Loki
&lt;/h2&gt;

&lt;p&gt;Before we start wiring things up locally, let's prepare the Grafana Cloud workspace. &lt;/p&gt;

&lt;p&gt;Navigate to &lt;a href="https://grafana.com/" rel="noopener noreferrer"&gt;Grafana Cloud&lt;/a&gt; and sign up or log in. In the sidebar, select &lt;strong&gt;Connections&lt;/strong&gt; → &lt;strong&gt;Add new connection&lt;/strong&gt;, select &lt;strong&gt;Loki&lt;/strong&gt;. This is the place that prompts you to set up your Loki connection and allows you to generate an access token for Alloy.&lt;/p&gt;

&lt;p&gt;In section 2, &lt;strong&gt;Install Grafana Alloy,&lt;/strong&gt; click the "Run Grafana Alloy" button to retrieve necessary information. We're interested in the token, Loki username (&lt;code&gt;GCLOUD_HOSTED_LOGS_ID&lt;/code&gt;) and Loki URL (&lt;code&gt;GCLOUD_HOSTED_LOGS_URL&lt;/code&gt;). You'll need them later to set up Alloy config.&lt;/p&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%2Fjknafh6g376b20p4hskm.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%2Fjknafh6g376b20p4hskm.png" alt="Image description" width="800" height="658"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Alloy Config
&lt;/h2&gt;

&lt;p&gt;The configuration for the collector is stored in a file with &lt;code&gt;*.alloy&lt;/code&gt; extension. Let's create &lt;code&gt;config.alloy&lt;/code&gt; in the project root.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Discover&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Docker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;containers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;extract&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;metadata.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;discovery.docker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"linux"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"unix:///var/run/docker.sock"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Extract&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;relabeling&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;rule.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;discovery.relabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"logs_integrations_docker"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;targets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;discovery.docker.linux.targets&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="err"&gt;rule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;source_labels&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"__meta_docker_container_name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;regex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/(.*)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;target_label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"service_name"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Collect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;logs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Docker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;containers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;together&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;relabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;information&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;forward&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Loki&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;receiver.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;loki.source.docker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"unix:///var/run/docker.sock"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;targets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;discovery.relabel.logs_integrations_docker.output&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;labels&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"platform"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"docker"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;forward_to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;loki.write.cloud.receiver&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Send&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;logs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Grafana&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Cloud&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Loki.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;loki.write&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cloud"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;endpoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;sys.env(&lt;/span&gt;&lt;span class="s2"&gt;"GRAFANA_LOKI_URL"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;basic_auth&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;username&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;sys.env(&lt;/span&gt;&lt;span class="s2"&gt;"GRAFANA_LOKI_USERNAME"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;password&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;sys.env(&lt;/span&gt;&lt;span class="s2"&gt;"GRAFANA_CLOUD_API_KEY"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This config basically defines a pipeline of operations Alloy performs to &lt;em&gt;collect&lt;/em&gt;, &lt;em&gt;transform&lt;/em&gt; and &lt;em&gt;deliver&lt;/em&gt; the data. In our case, we want to send logs from Docker to &lt;strong&gt;Grafana Cloud Loki&lt;/strong&gt;. To do that, we'll pass the credentials you got earlier to config - using environment variables for safety.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;&lt;em&gt;Tip:&lt;/em&gt;&lt;/strong&gt; Grafana has a &lt;a href="https://github.com/grafana/alloy-scenarios/tree/main" rel="noopener noreferrer"&gt;great Alloy scenarios repo&lt;/a&gt; with examples for different setups and logs sources. It helped me a lot in understanding how the pieces fit together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting It All Together in Docker Compose
&lt;/h2&gt;

&lt;p&gt;Since I’m already using docker-compose to run my service, integrating &lt;strong&gt;Alloy&lt;/strong&gt; was as simple as adding another service definition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${NODE_ENV}&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;8080:8080'&lt;/span&gt;

    &lt;span class="na"&gt;alloy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;grafana/alloy:latest&lt;/span&gt;
        &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alloy&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;12345:12345'&lt;/span&gt;
        &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# mount config file&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./config.alloy:/etc/alloy/config.alloy'&lt;/span&gt; 
            &lt;span class="c1"&gt;# give access to running docker containers for discovery.docker&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/run/docker.sock:/var/run/docker.sock&lt;/span&gt; 
            &lt;span class="c1"&gt;# give access to docker's log files directory (optional)&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/lib/docker/containers:/var/lib/docker/containers:ro&lt;/span&gt; 
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# pass environment variables for config.alloy&lt;/span&gt;
            &lt;span class="na"&gt;GRAFANA_LOKI_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${GRAFANA_LOKI_URL}&lt;/span&gt;
            &lt;span class="na"&gt;GRAFANA_LOKI_USERNAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${GRAFANA_LOKI_USERNAME}&lt;/span&gt;
            &lt;span class="na"&gt;GRAFANA_CLOUD_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${GRAFANA_CLOUD_API_KEY}&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;run&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--server.http.listen-addr=0.0.0.0:12345&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--storage.path=/var/lib/alloy/data&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/etc/alloy/config.alloy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Grafana Cloud credentials might be stored in a &lt;code&gt;.env&lt;/code&gt; file on your server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run and Verify
&lt;/h2&gt;

&lt;p&gt;Let's build and run the containers using &lt;code&gt;docker-compose up -d&lt;/code&gt; and verify everything is up by looking at the &lt;code&gt;docker ps&lt;/code&gt; output:&lt;/p&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%2Fh553g0lonbcvwei4yg8s.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%2Fh553g0lonbcvwei4yg8s.png" alt="Image description" width="800" height="39"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If both containers are up and healthy and there are no errors in logs, you can proceed to the Grafana Portal to verify the updates are reaching the Cloud. &lt;/p&gt;

&lt;p&gt;Navigate to &lt;strong&gt;Explore&lt;/strong&gt;, select your data source (&lt;strong&gt;Loki&lt;/strong&gt;) and apply filters. The &lt;code&gt;service_name&lt;/code&gt; filter label comes from the &lt;em&gt;relabelling&lt;/em&gt; step in the Alloy pipeline, so now you can easily search logs for your specific service.&lt;/p&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%2F6wu7vv1rmpvw6aepez8v.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%2F6wu7vv1rmpvw6aepez8v.png" alt="Image description" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And just like that - the logs are flowing! You can play more with additional filtering and processing, for now I just added a basic JSON parsing for more readable output.&lt;/p&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%2Fe6xsh5gmf795dudgr0h7.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%2Fe6xsh5gmf795dudgr0h7.png" alt="Image description" width="800" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Next?
&lt;/h2&gt;

&lt;p&gt;I’m still getting familiar with &lt;strong&gt;Grafana Dashboards&lt;/strong&gt;, so there’s more to explore. In particular:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pino logs use numeric levels (e.g. 30, 40), which aren’t parsed as human-readable levels by default in Grafana;&lt;/li&gt;
&lt;li&gt;I’d love to build some fancy filters and dashboards to better visualize logs;&lt;/li&gt;
&lt;li&gt;I'm eager to try pino-http logging and see how it can be visualized in Grafana.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These will probably be another blog post(s), so stay tuned :) Thanks for reading and I'd love to hear any suggestions or comments you may have! &lt;/p&gt;

</description>
      <category>grafana</category>
      <category>logging</category>
      <category>docker</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Hello World, We Are CatBytes</title>
      <dc:creator>aliona matveeva</dc:creator>
      <pubDate>Fri, 02 May 2025 10:10:26 +0000</pubDate>
      <link>https://dev.to/catbytes-community/hello-world-we-are-catbytes-18o1</link>
      <guid>https://dev.to/catbytes-community/hello-world-we-are-catbytes-18o1</guid>
      <description>&lt;p&gt;Hi everyone! We’re are the &lt;strong&gt;CatBytes Community&lt;/strong&gt; and we're excited to officially launch our presence here on DEV!&lt;/p&gt;

&lt;h3&gt;
  
  
  🐾 Who we are
&lt;/h3&gt;

&lt;p&gt;We're an online community built &lt;strong&gt;by women in tech, for women in tech&lt;/strong&gt;. CatBytes is all about creating a safe and genuinely supportive digital space for women who want to break into the tech world — whether you're just starting out or leveling up your skills.&lt;/p&gt;

&lt;p&gt;Our mission is simple: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;get more women into tech and lift each other up along the way. 🚀&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We run free weekly web development lessons, collaborate on real projects, and we’re lucky to have some amazing mentors — experienced software engineers and tech leads — guiding and cheering everyone on.&lt;/p&gt;

&lt;h3&gt;
  
  
  💻 What to expect
&lt;/h3&gt;

&lt;p&gt;Here on DEV, we are looking to &lt;strong&gt;learn, share, and connect&lt;/strong&gt;. So let's do that! 💜 &lt;/p&gt;

&lt;p&gt;Our first post is coming soon! We'll talk about the monitoring setup we're using for our community platform — streaming logs from a Dockerized Node.js app to Grafana Cloud using Alloy. &lt;/p&gt;

&lt;p&gt;More posts, insights, and stories to come. 🐱💬&lt;/p&gt;




&lt;p&gt;We’re just getting started here, so if this sounds interesting — follow along!&lt;br&gt;
Have questions, feedback, or just want to say hi? Drop a comment below — we’d love to hear from you.&lt;/p&gt;

&lt;p&gt;Thanks for stopping by — and we’re happy to be here!&lt;br&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%2F4fw3s2xq3l2pb26y1qp7.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%2F4fw3s2xq3l2pb26y1qp7.png" alt="Image description" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>welcome</category>
      <category>community</category>
      <category>womenintech</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
