DEV Community

Cover image for Stream Logs from Docker to Grafana Cloud with Alloy
Athreya aka Maneshwar
Athreya aka Maneshwar

Posted on • Edited on

Stream Logs from Docker to Grafana Cloud with Alloy

Hello, I'm Maneshwar. I'm building git-lrc, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. Star Us to help devs discover the project. Do give it a try and share your feedback for improving the product.

Hello, I'm Maneshwar. I'm working on FreeDevTools online currently building **one place for all dev tools, cheat codes, and TLDRs* — a free, open-source hub where developers can quickly find and use tools without any hassle of searching all over the internet.

Setting up logging inside containers can be annoying — especially when logs vanish with the container or you have to mess with volume mounts just to see what's going on.

Here's how I made it super simple using Grafana Alloy to send logs from a Flask server running inside a Docker container to Grafana Cloud, without touching host volumes.

Quick Demo App: Flask Logger

Let's start w
ith a super basic Flask app that just logs requests:

# app.py
from flask import Flask
import logging

app = Flask(__name__)

logging.basicConfig(filename="liveapi.log", level=logging.INFO)

@app.route("/")
def hello():
    app.logger.info("GET / was hit")
    return "Hello, World!"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)
Enter fullscreen mode Exit fullscreen mode

This will create a liveapi.log file in the current working directory.

☁️ Set Up Grafana Cloud + Loki

  1. Go to Grafana Cloud.
  2. Sign up or log in.
  3. In the sidebar, go to Connections → Data sources.
  4. Search for Loki and set it up.
  5. Copy the Loki Push URL from the connection config. It'll look like:
https://<username>:<api-key>@logs-prod-000.grafana.net/api/prom/push
Enter fullscreen mode Exit fullscreen mode

You'll use this in Alloy later.

🐳 Dockerfile: Flask + Alloy Without Volume Mounts

Here's the Dockerfile that installs everything, writes logs, and sends them to Grafana Loki using Alloy:

FROM debian:bookworm-slim

RUN apt-get update && apt-get install -y \
    python3 python3-pip gpg wget curl gnupg ca-certificates systemctl \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY requirements.txt .
RUN pip3 install --no-cache-dir --break-system-packages -r requirements.txt

# Install Alloy
RUN mkdir -p /etc/apt/keyrings/ && \
    wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | tee /etc/apt/keyrings/grafana.gpg > /dev/null && \
    echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" > /etc/apt/sources.list.d/grafana.list && \
    apt-get update && apt-get install -y alloy && \
    rm -rf /var/lib/apt/lists/*

COPY . .

RUN mkdir -p /etc/alloy/ && cp config.alloy /etc/alloy/config.alloy

EXPOSE 5000

CMD systemctl restart alloy && python3 app.py
Enter fullscreen mode Exit fullscreen mode

No volume mounts. No host bind paths. Everything is self-contained inside the container.

⚙️ config.alloy (Log Pipeline for Alloy)

Create config.alloy in your repo:

local.file_match "local_files" {
  path_targets = [{ "__path__" = "/app/liveapi.log" }]
  sync_period = "5s"
}

loki.source.file "log_scrape" {
  targets       = local.file_match.local_files.targets
  forward_to    = [loki.process.filter_logs.receiver]
  tail_from_end = true
}

loki.process "filter_logs" {
  forward_to = [loki.write.grafana_loki.receiver]

  stage.static_labels {
    values = {
      job          = "liveapi"
      service_name = "liveapi"
    }
  }
}

loki.write "grafana_loki" {
  endpoint {
    url = "https://<your-username>:<your-api-key>@logs-prod-000.grafana.net/api/prom/push"
  }
}
Enter fullscreen mode Exit fullscreen mode

Change the endpoint to match your Grafana Loki Push URL.

Build & Run

Build the Docker image:

docker build -t flask-alloy .
Enter fullscreen mode Exit fullscreen mode

Run it:

docker run -p 5000:5000 flask-alloy
Enter fullscreen mode Exit fullscreen mode

Now visit http://localhost:5000 to trigger logs. Check Grafana Cloud’s Explore tab and query:

{job="liveapi"}
Enter fullscreen mode Exit fullscreen mode

Boom — your logs are in the cloud. 🎉

Any Better Way?

Let me know in the comments — is there a simpler or cooler way you’re pushing logs to Grafana Loki from containers? Would love to steal it.


I’ve been building
A collection of UI/UX-focused tools crafted to simplify workflows, save time, and reduce friction in searching tools/materials.

Any feedback or contributors are welcome!

It’s online, open-source, and ready for anyone to use.

👉 Check it out:

⭐ Star it on GitHub:

Let’s make it even better together.

git-lrc
*AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production.

git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.*

Any feedback or contributors are welcome! It's online, source-available, and ready for anyone to use.

⭐ Star it on GitHub:

GitHub logo HexmosTech / git-lrc

Free, Unlimited AI Code Reviews That Run on Commit




AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production.

git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.

See It In Action

See git-lrc catch serious security issues such as leaked credentials, expensive cloud operations, and sensitive material in log statements

git-lrc-intro-60s.mp4

Why

  • 🤖 AI agents silently break things. Code removed. Logic changed. Edge cases gone. You won't notice until production.
  • 🔍 Catch it before it ships. AI-powered inline comments show you exactly what changed and what looks wrong.
  • 🔁 Build a

Top comments (2)

Collapse
 
nevodavid profile image
Nevo David

Amazing guide, and it's super simple to follow!

Collapse
 
lovestaco profile image
Athreya aka Maneshwar

Thanks @nevodavid :)