Add a default value for label if a particular label doesn't exists

{
  "@t": "2025-04-30T14:20:16.0163472Z",
  "@m": "(\"foobar\") Attempting to clear buffer(1)...",
  "@i": "6a4fd379",
  "@l": "Debug",
  "BufferLength": 1
}

I want to have label of level which should be equal to the value of @l.
if the @l doesn’t exist, then the level should be info.

how do i achieve this?

My current config which doesn’t work


        stage.regex {
          expression = "^(?s)(?P<time>\\S+?) (?P<stream>stdout|stderr) (?P<flags>\\S+?) (?P<content>.*)$"
        }

        stage.drop {
          source     = "content"
          expression = "^[^\\{].*"
        }

        stage.replace {
          expression = `(\@t)`
          replace    = "timestamp"
        }

        stage.replace {
          expression = `(\@l)`
          replace    = "level"
        }


        stage.json {
          source = "content"
          expressions = {
            time  = "timestamp",
            level = "level",
          }
        }
        stage.timestamp {
          source = "time"
          format = "RFC3339Nano"
        }
        stage.labels {
          values = {
            level = coalesce("level", "info"),
          }
        }

        stage.output {
          source = "content"
        }

You can add a template stage, and within the template stage set a default value. Something like this (not tested):

stage.template {
    source   = "level_cleansed"
    template = `{{ default "Info" .level }}`
}

stage.labels {
  values = {
    level = "level_cleansed",
  }
}

oh that’s interesting, thanks.
but what if if the @l doesn’t exist. then the,


        stage.replace {
          expression = `(\@l)`
          replace    = "level_cleansed"
        }

doesn’t work right?

 stage.replace {
          expression = `(\@l)`
          replace    = "level_cleansed"
        }
        stage.json {
          source = "content"
          expressions = {
            time  = "timestamp",
            level = "level_cleansed"
          }
        }

        stage.timestamp {
          source = "time"
          format = "RFC3339Nano"
        }




        stage.template {
          source   = "level_cleansed"
          template = `{{ default "Info" .level }}`
        }

        stage.labels {
          values = {
            level = "level_cleansed",
          }
        }

Right, but you want to leave your replace stage as “level”, because you need that reference in the template stage. The source in template means the field to set the templated value in, not where it gets the value from.

So you want:

  1. stage.replace: “@l” to “level”
  2. stage.json: parse “timestamp” and “level”
  3. stage.template: set level_cleansed with value from .level, and if .level empty then set “Info”
  4. Set label “level” using the value of “level_cleansed”
1 Like

Thanks it works.

Though when i try to drop the @t at the end, it doesn’t work.

Earlier in the promtail config, i used to do

      - labels:
          level:
      - template:
          source: content 
          template: '{{ omit (mustFromJson .Entry) "@t" "@l" | mustToJson }}'
      - output:
          source: content

with alloy, when i tried the same config,

        stage.template {
          source = "content" 
          template = "{{ omit (mustFromJson .Entry) `"@t"` | mustToJson }}"
        }

        stage.output {
          source = "content"
        }

i get the following error:

template: gotpl:167:38: executing "gotpl" at <.Entry>: wrong type for value; expected string; got interface {}

I’ve had problem before with symbol characters in JSON key. I’d say do what you were originally doing, which is to get rid of the @ symbol first, before doing any other processing.