tarkis
November 18, 2025, 5:38pm
1
Hello,
I would like to collect JSON formatted logs from a file UTF-8 encoded continuously alimented by a Java app but Alloy escapes all quote and not recognises the line as JSON.
For exemple :
Each line in my log file is JSON, terminates with \n and interpreted correctly by jq.
My pipeline is :
local.file_match → loki.source.file → loki.process → otelcol.receiver.loki → otelcol.exporter.otlphttp
my last test :
local.file_match "logs_json" {
path_targets = [
{__path__ = "/MIDDLELOGS/**/*.json.log.*", __path_exclude__ = "/MIDDLELOGS/**/*.gz", service_name = "m2m"},
]
ignore_older_than = "300s"
}
loki.process "process_logs" {
forward_to = [otelcol.receiver.loki.default.receiver]
stage.match {
selector = "{service_name = \"m2m\"} |= \"ENTRYPOINT\""
stage.static_labels {
values = {"log_type" = "ENTRYPOINT"}
}
stage.json {
expressions = {clienId = ""}
}
}
}
loki.source.file "logs_json" {
targets = local.file_match.logs_json.targets
forward_to = [loki.process.process_logs.receiver]
tail_from_end = true
}
If I add drop_malformed in stage.json all logs from the file are droped.
I don’t understand why Alloy ignore the format, have you any idea of what I have missed ?
Regards,
PS : for security reasons I have hidden some fileds name and content but the structure I think you can see the structure like the reality.
yosiasz
November 18, 2025, 7:53pm
2
Welcome to forum @tarkis
Can you please post a sample log file, obfuscating sensitive stuff but still keeping structure of it intact?
tarkis
November 19, 2025, 10:19am
3
Thanks !
I will try to convice my security manager, It’s not win at the moment
During waiting his response maybe you can tel me what do you want to check ? Event I can’t give you a sample, maybe I can give you details which is more easy to sanitize than a file
tarkis
November 19, 2025, 11:06am
4
@yosiasz I have attached an obfuscating sample.
m2m.1000.json (726.3 KB)
yosiasz
November 20, 2025, 1:15am
5
{“function”:“ENTRYPOINT”,“Datacenter”:“XXX”,“Host”:“https://www.services.com ”,“_IP”:“00.00.00.00%1”,“Ciphersuite”:“TLS13-AES128”,“Isp”:“beautifull isp”,“Country”:“_empty”,“Reputation”:“_empty”,“ReverseInstanceID”:“None”,“ReverseUniqueID”:“None”,“ResponseCodeHttpHeader”:“Suspicious-12”}}
What is the last bracket }}
tarkis
November 20, 2025, 8:22am
6
I think the visualisation from browser format wrongly the JSON.
Each log begin with
{“timestamp” :
For example :
{“timestamp”: “2025-11-19T00:00:19.505+01:00”,“level”: “INFO”,“service”: “h2h”,“application”: “h2h”,“_Id”: “239aa77f527e4f019ad74cc49524e1cd”,“mId”: “000000000000000”,“mAlias”: “mAlias”,“cAlias”: “Alias”,“message”: {“function”: “ENTRYPOINT”,“Datacenter”: “XXX”,“Host”: “https://www.services.com”,“_IP”: “00.00.00.00%1”,“Ciphersuite”: “TLS13-AES128”,“Isp”: “beautifull isp”, “Country”: “_empty”,“Reputation”: “_empty”,“ReverseInstanceID”: “None”, “ReverseUniqueID”: “None”,“ResponseCodeHttpHeader”: “Trusted-05”}}
1 Like
Judging from your screenshot, the logs you are sharing isn’t your actual raw log files, because it says msg={...}, so there must be another layer up.
I suspect you need to run your logs through a JSON stages, then set the msg as the log message, then deal with other labeling needs with nested JSON stages if needed. Something like (not tested):
stage.json {
expressions = {
msg = "",
}
}
stage.output {
source = "msg"
}
tarkis
November 21, 2025, 9:49am
8
msg={…] is the issue I can see in Grafana, I don’t understand what is happening and it’s why I ask help here ^^
Shared logs are updated because of security, but its the raw log file. I haven’t set anything else between the path of the logs and Alloy
I tested your suggestion, my last settings
logging {
level = "warn"
}
otelcol.receiver.loki "default" {
output {
logs = [otelcol.exporter.otlphttp.logs.input]
}
}
otelcol.exporter.otlphttp "logs" {
client {
endpoint = "******"
}
retry_on_failure {
enabled = true
max_elapsed_time = "2m"
}
}
local.file_match "logs_json" {
path_targets = [
{
__path__ = "/MIDDLELOGS/**/*.json.log.*",
__path_exclude__ = "/MIDDLELOGS/**/*.gz",
__path_exclude__ = "/MIDDLELOGS/**/*.bill",
},
]
ignore_older_than = "300s"
}
loki.process "process_logs" {
forward_to = [otelcol.receiver.loki.default.receiver]
stage.json {
expressions = {msg = "",}
}
stage.output {
source = "msg"
}
}
loki.source.file "sips_logs_json" {
targets = local.file_match.logs_json.targets
forward_to = [loki.process.process_logs.receiver]
tail_from_end = true
}
The issue still occured.
I continue tu find a way
tarkis
November 25, 2025, 4:46pm
9
I have tried this :
loki.process "json_process_logs" {
forward_to = [otelcol.receiver.loki.default.receiver]
stage.static_labels {
values = {
host = "tesips101v",
}
}
stage.regex {
expression = "^(?P<has_json>\\s*\\{\\s*\")"
}
stage.template {
source = "__tmp_format__"
template = "{{ if .has_json }}json{{ else }}plain{{ end }}"
}
stage.labels {
values = {
__tmp_format__ = "",
}
}
stage.match {
selector = "{__tmp_format__=\"json\"}"
pipeline_name = "json_logs"
stage.replace {
expression = "({\\\")"
replace = "{'"
}
stage.replace {
expression = "(\\\":{)"
replace = "':{"
}
stage.replace {
expression = "(\\\"})"
replace = "'}"
}
stage.replace {
expression = "(\\\":\\\")"
replace = "':'"
}
stage.replace {
expression = "(\\\",\\\")"
replace = "','"
}
stage.json {
expressions = {
merchantId = "",
application = "",
}
}
}
}
It is look like line is treated as logfmt, the msg= is added after Alloy processings.
I still don’t know why my logs are not considering as Json
I would say, share your source raw logs (without sensitive information of course), so I can test your configuration. You don’t need to share much, just a couple of lines would do.
Also, you can mock it with bogus values too, I just want to see what your raw source logs look like.
tarkis
December 2, 2025, 3:38pm
11
I have built a little python for generate json logs
import json,datetime
x = {
"name": "John",
"age": 30,
"city": "New York",
"timestamp" : datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"messsage" : {
"app" : "s2s",
"type" : "event",
"function" : "entrypoint"
}
}
y = json.dumps(x)
print(y)
I call it with this way :
while true; do python json_logs.py | tee -a /MIDDLELOGS/*********/***********/server/amc.json.log.251202; sleep 1; done
I got :
My settings
logging {
level = "warn"
}
otelcol.receiver.loki "default" {
output {
logs = [otelcol.exporter.otlphttp.logs.input]
}
}
otelcol.exporter.otlphttp "logs" {
client {
endpoint = "https://********"
}
retry_on_failure {
enabled = true
max_elapsed_time = "2m"
}
}
local.file_match "logs_json" {
path_targets = [
{
__path__ = "/MIDDLELOGS/**/*.json.log.*",
__path_exclude__ = "/MIDDLELOGS/**/*.gz",
__path_exclude__ = "/MIDDLELOGS/**/*.bill",
},
]
ignore_older_than = "300s"
}
loki.process "json_process_logs" {
forward_to = [otelcol.receiver.loki.default.receiver]
stage.static_labels {
values = {
host = "*****",
}
}
stage.regex {
expression = "^(?P<has_json>\\s*\\{\\s*\")"
}
stage.template {
source = "__tmp_format__"
template = "{{ if .has_json }}json{{ else }}plain{{ end }}"
}
stage.labels {
values = {
__tmp_format__ = "",
}
}
stage.match {
selector = "{__tmp_format__=\"json\"}"
pipeline_name = "json_logs"
stage.replace {
expression = "(attribute_log.*$)"
replace = ""
}
stage.replace {
expression = "({\\\")"
replace = "{\""
}
stage.replace {
expression = "(\\\":{)"
replace = "\":{"
}
stage.replace {
expression = "(\\\"})"
replace = "\"}"
}
stage.replace {
expression = "(\\\":\\\")"
replace = "\":\""
}
stage.replace {
expression = "(\\\",\\\")"
replace = "\",\""
}
stage.json {
expressions = {
merchantId = "",
application = "",
}
}
}
}
loki.source.file "logs_json" {
targets = local.file_match.logs_json.targets
forward_to = [loki.process.json_process_logs.receiver]
tail_from_end = true
}