I’m migrating from Promtail to Grafana Alloy for reading systemd journal logs and want to avoid duplicate log entries in Loki during an in‑place migration.
I’ve read the migration and component docs, but the behavior of loki.source.journal’s legacy_position block with a Promtail positions.yaml file isn’t fully clear to me:
Migration docs:
-
Migrate from Promtail to Alloy[Migrate from Promtail]
-
Journal source docs:
loki.source.journalblocks /legacy_position[loki.source.journal]
Current setup
I currently have Promtail scraping the systemd journal:
scrape_configs:
- job_name: journal
journal:
max_age: 12h
labels:
env: {{ env }}
instance: {{ inventory_hostname.split('.')[0] }}
type: journal
relabel_configs:
- source_labels: ['__journal_container_name']
target_label: container_name
- source_labels: ['__journal__systemd_unit']
regex: '(loki|promtail|node-exporter)\.service'
target_label: service
Promtail’s positions file contains a journal cursor like:
cursor-journal: s=dcddee5661cb4e3ea558f754bff3d6fb;i=ff120;b=6b4b547c34e245f183cabbf196059460;m=107d7c7d6061;t=654fa564157de;x=ab7c87cba78afb6a
Planned Alloy config
I want to do an in‑place migration: stop Promtail, start Alloy, and continue from the same journal cursor without re‑reading the last 12h of logs.
My Alloy config for journal looks like:
discovery.relabel "journal" {
targets = []
rule {
source_labels = ["__journal__systemd_unit"]
regex = "(loki|promtail|node-exporter|alloy)\\.service"
target_label = "service"
}
}
loki.source.journal "journal" {
max_age = "12h0m0s"
legacy_position {
file = "/path/to/existing/promtail-position's-file/positions.yaml"
name = "journal"
}
relabel_rules = discovery.relabel.journal.rules
forward_to = [loki.write.default.receiver]
labels = {
env = "{{ env }}",
instance = "{{ inventory_hostname.split('.')[0] }}",
type = "journal",
}
}
The docs say:
“The translation of legacy position file will happens if there is no position file already and is a valid yaml file to convert.”[loki.source.journal: See this section, Not able to paste the url due to restriction from Grafna end]
But they don’t specify how this interacts with Promtail’s positions format and journal cursors.
Questions -
-
Is Promtail’s
positions.yamlofficially supported as a “legacy” positions file forloki.source.journal?- Specifically, will a key like
cursor-journal: <cursor>be recognized and used as the starting point for the Alloy journal reader?
- Specifically, will a key like
-
What does
legacy_position.nameneed to match?- In my example I use
name = "journal". - Should this match the Promtail
job_name(journal), or some other identifier in the positions file? - Is there a mapping example for Promtail → Alloy for journal positions?
- In my example I use
-
Duplicate‑log behavior with
max_ageduring migration- If I:
- Stop Promtail,
- Start Alloy with the config above (
max_age = "12h0m0s"andlegacy_positionpointing to Promtail’spositions.yaml),
- Will Alloy:
- Always honor the imported journal cursor and not re‑read older entries within the
max_agewindow, or - Potentially re‑read some portion of the last 12h, causing duplicates in Loki?
- Always honor the imported journal cursor and not re‑read older entries within the
- If I:
-
Failure / fallback behavior
- If the legacy positions file is valid YAML but doesn’t contain a usable journal cursor for the given
name, what is the exact behavior?- Does Alloy start from “now”, from
max_ageback, or from the beginning of the journal? - Is there a log message I can look for to confirm that the legacy position was successfully imported?
- Does Alloy start from “now”, from
- If the legacy positions file is valid YAML but doesn’t contain a usable journal cursor for the given
-
Recommended migration pattern
- For an in‑place migration from Promtail to Alloy for journal logs, is the recommended pattern:
- Stop Promtail,
- Start Alloy with
legacy_positionconfigured, - Verify in logs/metrics that the legacy position was imported,
- Then keep
max_ageas before (12h),
or is there a better/safer pattern to avoid duplicates?
- For an in‑place migration from Promtail to Alloy for journal logs, is the recommended pattern:
Any clarification or a small end‑to‑end example (Promtail positions.yaml → loki.source.journal with legacy_position) would be very helpful. I’m mainly trying to ensure that I don’t generate duplicate journal entries in Loki during the migration.
Thanks!