Parse Log Severity Levels with Pipelines
Overview
In many logging setups, severity information is embedded within JSON structures in the log body. You might have severity fields like severity_text
and severity_number
that you want to extract and map to the standard OpenTelemetry severity fields to enable proper log level filtering and alerting.
Example Log
Throughout this guide, we'll reference the following example raw log entry:
{"message":"applying telemetry collection strategy for region","otel":{"trace_id":"000000000000000018c51935df0b93b9","span_id":"18c51935df0b93b9","severity_text":"info","severity_number":"4"}}
- The
body
field contains a JSON string with fields likemessage
andotel.severity_text
. - The severity information is nested within the
otel
object in the JSON body. - We need to extract this severity information to enable proper log level categorization.
Desired Outcome
By the end of this guide, we want to:
- Parse the JSON string in
body
into structured fields underattributes
. - Extract the severity information from the nested
otel
object. - Map the severity values to standard OpenTelemetry severity fields.
Here's how the log should look after we apply our pipeline transformations:
{
"body": "applying telemetry collection strategy for region",
"id": "0h1FsDchlAnA8giHLlSkdd4UNnz",
"timestamp": 1750417406945,
"attributes": {
"log.file.name": "app.log",
"parsed_body": "{\"otel\":{\"severity_number\":\"4\",\"severity_text\":\"info\",\"span_id\":\"18c51935df0b93b9\",\"trace_id\":\"000000000000000018c51935df0b93b9\"}}"
},
"resources": {},
"scope": {},
"severity_text": "INFO",
"severity_number": 9,
"trace_id": "",
"span_id": "",
"trace_flags": 0
}
Steps to Parse JSON and Extract Severity
We'll use three processors in SigNoz Logs Pipeline to transform the example log into the desired format:
- JSON Parser – Convert the JSON in
body
into structured fields underattributes
. - Move Processor – Move the
message
field from the parsed JSON intobody
. - Severity Parser – Extract and map severity information from the nested
otel
object.
Let's walk through each step in detail.
body
to Structured Attributes
Step 1: JSON Parser – Convert JSON in Our first step is to parse the raw JSON string residing in the body
field so we can work with its fields directly (e.g., message
, otel.severity_text
) under attributes
.
Before Parsing
{"message":"applying telemetry collection strategy for region","otel":{"trace_id":"000000000000000018c51935df0b93b9","span_id":"18c51935df0b93b9","severity_text":"info","severity_number":"4"}}
Processor Configuration
- Type: JSON Parser
- Name: ParseBodyJson
- Parse From:
body
- Parse To:
attributes.parsed_body

After Parsing
{
"body": "{\"message\":\"applying telemetry collection strategy for region\",\"otel\":{\"trace_id\":\"000000000000000018c51935df0b93b9\",\"span_id\":\"18c51935df0b93b9\",\"severity_text\":\"info\",\"severity_number\":\"4\"}}",
"id": "0h1FsDchlAnA8giHLlSkdd4UNnz",
"timestamp": 1750417406945,
"attributes": {
"log.file.name": "app.log",
"parsed_body": "{\"message\":\"applying telemetry collection strategy for region\",\"otel\":{\"severity_number\":\"4\",\"severity_text\":\"info\",\"span_id\":\"18c51935df0b93b9\",\"trace_id\":\"000000000000000018c51935df0b93b9\"}}"
},
"resources": {},
"scope": {},
"severity_text": "",
"severity_number": 0,
"trace_id": "",
"span_id": "",
"trace_flags": 0
}
Key Observations:
- Fields like
message
andotel.severity_text
are now accessible inattributes.parsed_body
. - The original
body
field still holds the raw JSON string.
body
Step 2: Move Processor – Extract the Message Field to Now that message
is available at attributes.parsed_body.message
, we can move it to the top-level body
to clearly indicate that this is the main log message. This is an optional step and you can skip it if you want.
Before Moving Message
{
"body": "{\"message\":\"applying telemetry collection strategy for region\",\"otel\":{\"trace_id\":\"000000000000000018c51935df0b93b9\",\"span_id\":\"18c51935df0b93b9\",\"severity_text\":\"info\",\"severity_number\":\"4\"}}",
"id": "0h1FsDchlAnA8giHLlSkdd4UNnz",
"timestamp": 1750417406945,
"attributes": {
"log.file.name": "app.log",
"parsed_body": "{\"message\":\"applying telemetry collection strategy for region\",\"otel\":{\"severity_number\":\"4\",\"severity_text\":\"info\",\"span_id\":\"18c51935df0b93b9\",\"trace_id\":\"000000000000000018c51935df0b93b9\"}}"
},
"resources": {},
"scope": {},
"severity_text": "",
"severity_number": 0,
"trace_id": "",
"span_id": "",
"trace_flags": 0
}
Processor Configuration
- Type: Move
- Name: MoveMessageToBody
- From:
attributes.parsed_body.message
- To:
body

After Moving Message
{
"body": "applying telemetry collection strategy for region",
"id": "0h1FsDchlAnA8giHLlSkdd4UNnz",
"timestamp": 1750417406945,
"attributes": {
"log.file.name": "app.log",
"parsed_body": "{\"otel\":{\"severity_number\":\"4\",\"severity_text\":\"info\",\"span_id\":\"18c51935df0b93b9\",\"trace_id\":\"000000000000000018c51935df0b93b9\"}}"
},
"resources": {},
"scope": {},
"severity_text": "",
"severity_number": 0,
"trace_id": "",
"span_id": "",
"trace_flags": 0
}
Key Observations:
- The main log message is now in
body
. attributes.parsed_body.message
has been removed because Move transfers data rather than copying.
Step 3: Severity Parser – Extract and Map Severity Information
Now we'll use the Severity Parser to extract the severity information from the nested otel
object and map it to standard OpenTelemetry severity fields.
Before Parsing Severity
{
"body": "applying telemetry collection strategy for region",
"id": "0h1FsDchlAnA8giHLlSkdd4UNnz",
"timestamp": 1750417406945,
"attributes": {
"log.file.name": "app.log",
"parsed_body": "{\"otel\":{\"severity_number\":\"4\",\"severity_text\":\"info\",\"span_id\":\"18c51935df0b93b9\",\"trace_id\":\"000000000000000018c51935df0b93b9\"}}"
},
"resources": {},
"scope": {},
"severity_text": "",
"severity_number": 0,
"trace_id": "",
"span_id": "",
"trace_flags": 0
}
Processor Configuration
- Type: Severity Parser
- Name: ParseSeverityFromOtel
- Parse Severity Value From:
attributes.parsed_body.otel.severity_text
- Values for level INFO:
info, information
- Values for level DEBUG:
debug
- Values for level WARN:
warn, warning
- Values for level ERROR:
error, err
- Values for level FATAL:
fatal, critical

After Parsing Severity
{
"body": "applying telemetry collection strategy for region",
"id": "0h1FsDchlAnA8giHLlSkdd4UNnz",
"timestamp": 1750417406945,
"attributes": {
"log.file.name": "app.log",
"parsed_body": "{\"otel\":{\"severity_number\":\"4\",\"severity_text\":\"info\",\"span_id\":\"18c51935df0b93b9\",\"trace_id\":\"000000000000000018c51935df0b93b9\"}}"
},
"resources": {},
"scope": {},
"severity_text": "INFO",
"severity_number": 9,
"trace_id": "",
"span_id": "",
"trace_flags": 0
}
Key Observations:
severity_text
is now set to "INFO" at the top level.severity_number
is automatically set to 9 (the OpenTelemetry numeric value for INFO level).- The original severity fields remain in the nested structure.
Step 4 (Optional): Move and Clean Up – Organize Final Structure
Finally, let's move the trace information to a cleaner location and remove the temporary parsed_body
structure.
Before cleanup
{
"body": "applying telemetry collection strategy for region",
"id": "0h1FsDchlAnA8giHLlSkdd4UNnz",
"timestamp": 1750417406945,
"attributes": {
"log.file.name": "app.log",
"parsed_body": "{\"otel\":{\"severity_number\":\"4\",\"severity_text\":\"info\",\"span_id\":\"18c51935df0b93b9\",\"trace_id\":\"000000000000000018c51935df0b93b9\"}}"
},
"resources": {},
"scope": {},
"severity_text": "INFO",
"severity_number": 9,
"trace_id": "",
"span_id": "",
"trace_flags": 0
}
Move Trace Information
Processor Configuration:
- Type: Move
- Name: MoveOtelFields
- From:
attributes.parsed_body.otel
- To:
attributes.otel
Remove parsed_body attribute
Processor Configuration:
- Type: Remove
- Name: RemoveParsedBody
- From:
attributes.parsed_body
After cleanup
{
"body": "applying telemetry collection strategy for region",
"id": "0h1FsDchlAnA8giHLlSkdd4UNnz",
"timestamp": 1750417406945,
"attributes": {
"log.file.name": "app.log",
"otel": "{\"severity_number\":\"4\",\"severity_text\":\"info\",\"span_id\":\"18c51935df0b93b9\",\"trace_id\":\"000000000000000018c51935df0b93b9\"}"
},
"resources": {},
"scope": {},
"severity_text": "INFO",
"severity_number": 9,
"trace_id": "",
"span_id": "",
"trace_flags": 0
}
Final Outcome
After applying these three processors in sequence, your log now has:
- The main log message clearly displayed in
body
. - Properly mapped severity levels at the top level for filtering and alerting.
- Trace information preserved in
attributes.otel
.
With these steps, you've successfully extracted severity information from nested JSON structures and mapped it to standard OpenTelemetry severity fields, enabling proper log level categorization and filtering in SigNoz.