Summary
The VictoriaLogs capture path is complete and healthy, but the post-soak UX audit found that the shared Alloy feed does not expose the canonical fields expected by native VMUI or Grafana. This makes the VictoriaLogs presentation materially less coherent than Loki even though both backends receive the same entries.
This issue is a convergence gate for #470. Retain the current Loki dual-write until the normalization rollout is measured and the VictoriaLogs browsing experience is accepted; do not interpret it as approval for indefinite dual storage.
Evidence from the live audit
- Alloy sent the same 9,239 entries to Loki and VictoriaLogs over the measured ten-minute window, with zero drops and no retry increase.
- A 10,000-row VictoriaLogs sample had no top-level
level, service_name, or service_instance fields. 943 rows contained structured severity only as the collision-safe msg.level field, which VMUI does not recognize.
- Over a one-hour query, 2,630 rows had
msg.level: 2,621 info and 9 warn. Valid structured severity is therefore present but hidden from VMUI.
- VictoriaLogs v1.52.0 VMUI recognizes canonical top-level fields such as
level, severity_text, and detected_level; msg.level is outside that list, so the affected entries render as OTHER.
- Kubernetes application identity is available for 173 of 184 current containers through
app.kubernetes.io/name or legacy app; every generic container="app" workload has a usable application name. Container fallback covers the remainder.
- A recent 9,306-row sample contained 253 ANSI-colored rows. Global decolorization is safe after CRI reconstruction and improves both retained sinks.
- Apparent continuation-line candidates were dominated by intentional iperf separator output. There is no evidence supporting a global multiline rule.
- Loki improves presentation by synthesizing
service_name and detected_level, but its plaintext detector uses broad substring heuristics. Copying that inference into stored VictoriaLogs fields would create confidently wrong severity.
- Grafana Logs Drilldown remains Loki-query-API-specific. VictoriaLogs can improve standard Explore and native VMUI, but cannot become a Drilldown datasource through configuration alone.
Schema decision
Use a small, stable envelope while preserving application payload fields under msg.*:
- Stream identity:
cluster, namespace, service_name, pod, container, node.
- Event fields:
_time, _msg, stream, filename, normalized level, plus application fields under msg.*.
- Derive
service_name from app.kubernetes.io/name, then legacy app, then container.
- Preserve
app.kubernetes.io/instance separately as app_instance when present. It is commonly a Helm/release identity and must not be mislabeled as the OpenTelemetry service.instance.id.
- Normalize only explicit JSON or credible logfmt severity values into Grafana's canonical set
trace, debug, info, warning, error, and critical. Fold fatal/panic aliases into critical while retaining the original application payload.
- Keep
level, request IDs, trace IDs, users, and other per-event values out of VictoriaLogs stream identity.
- Do not add global plaintext severity inference or global multiline assembly.
Phase 1: platform baseline
Rollout acceptance
Phase 2: measured source inventory
After the platform baseline, inventory the remaining high-volume/plain-text emitters and enable native structured output only where the application documents it. Track noisy-log reduction and secret/PII redaction separately rather than adding generic collector regexes. A small Git-managed Logs Overview dashboard is optional follow-up; do not turn this issue into broad dashboard curation tracked by #50.
Related
Summary
The VictoriaLogs capture path is complete and healthy, but the post-soak UX audit found that the shared Alloy feed does not expose the canonical fields expected by native VMUI or Grafana. This makes the VictoriaLogs presentation materially less coherent than Loki even though both backends receive the same entries.
This issue is a convergence gate for #470. Retain the current Loki dual-write until the normalization rollout is measured and the VictoriaLogs browsing experience is accepted; do not interpret it as approval for indefinite dual storage.
Evidence from the live audit
level,service_name, orservice_instancefields. 943 rows contained structured severity only as the collision-safemsg.levelfield, which VMUI does not recognize.msg.level: 2,621infoand 9warn. Valid structured severity is therefore present but hidden from VMUI.level,severity_text, anddetected_level;msg.levelis outside that list, so the affected entries render asOTHER.app.kubernetes.io/nameor legacyapp; every genericcontainer="app"workload has a usable application name. Container fallback covers the remainder.service_nameanddetected_level, but its plaintext detector uses broad substring heuristics. Copying that inference into stored VictoriaLogs fields would create confidently wrong severity.Schema decision
Use a small, stable envelope while preserving application payload fields under
msg.*:cluster,namespace,service_name,pod,container,node._time,_msg,stream,filename, normalizedlevel, plus application fields undermsg.*.service_namefromapp.kubernetes.io/name, then legacyapp, thencontainer.app.kubernetes.io/instanceseparately asapp_instancewhen present. It is commonly a Helm/release identity and must not be mislabeled as the OpenTelemetryservice.instance.id.trace,debug,info,warning,error, andcritical. Fold fatal/panic aliases intocriticalwhile retaining the original application payload.level, request IDs, trace IDs, users, and other per-event values out of VictoriaLogs stream identity.Phase 1: platform baseline
service_nameand optionalapp_instancefrom Kubernetes discovery metadata with the documented fallbacks.levelwithout removing the originalmsg.levelor raw message.service_nameto the explicit VictoriaLogs stream-field set; leavelevelandapp_instanceas ordinary fields.msg.levelrows retained before the schema change.vmuiUrlso Grafana'sRun in VMUIaction carries the current query and time range tohttps://vlogs.home.kelch.io/select/vmui/instead of an unreachable cluster DNS URL.Rollout acceptance
service_nameas a stream facet.levelfields and retained historicalmsg.leveldata.Run in VMUIaction opens the external authenticated VMUI with the query and time range preserved._msgvalues and application fields.Phase 2: measured source inventory
After the platform baseline, inventory the remaining high-volume/plain-text emitters and enable native structured output only where the application documents it. Track noisy-log reduction and secret/PII redaction separately rather than adding generic collector regexes. A small Git-managed Logs Overview dashboard is optional follow-up; do not turn this issue into broad dashboard curation tracked by #50.
Related