'Helm `toYaml` does not retain the order

Trying to get log4j2 section form values.yml using toYaml but it does not retain the order.

log4j2.yml: |-
{{ toYaml .Values.log4j2 | indent 4 }}

output-

log4j2:
  Configuration:
    Appenders:
      Console:
        Filters:
          DuplicateLogFilter:
            ttlInSeconds: 60
          MarkerFilter:
            marker: TRACE
            onMatch: ACCEPT
            onMismatch: NEUTRAL
        PatternLayout:
          pattern: '%-5p | %d{yyyy-MM-dd HH:mm:ss,SSS} | [%t] [%X{AD.requestGUID}] [%X{trace.id}]
          %x %c{1.}:%L - %m%n'
        name: CONSOLE
        target: SYSTEM_OUT
    monitorInterval: 300
    shutdownHook: disable

Expected output-

log4j2:
  Configuration:
    monitorInterval: 300
    shutdownHook: disable
    Appenders:
      Console:
        name: CONSOLE
        target: SYSTEM_OUT
        Filters:
          MarkerFilter:
            marker: TRACE
            onMatch: ACCEPT
            onMismatch: NEUTRAL
          DuplicateLogFilter:
            ttlInSeconds: 60
        PatternLayout:
          pattern: "%-5p | %d{yyyy-MM-dd HH:mm:ss,SSS} | [%t] [%X{AD.requestGUID}] [%X{trace.id}] %x %c{1.}:%L - %m%n"


Solution 1:[1]

Values files are parsed to a map (or dictionary if you will), and map structures in general are not required to preserve the field order. So your issue is not a problem of the toYaml function as such, but of placing log4j configuration inside values.yaml.

What you could do is moving your log4j configuration in to a separate log4j2.yml file (in the root of your chart), and including it as a raw file:

log4j2.yml: |-
  {{- .Files.Get "log4j2.yml" | nindent 10 }}

(adjust the indent accordingly)

Solution 2:[2]

I got around this Log4j2 quirk by extracting the items that log4j2 enforces order for, and then outputting Configuration with those items ommitted using the omit function.

Configuration:
  packages: {{ .Values.log4j2.Configuration.packages | toYaml }}
  Appenders: {{ .Values.log4j2.Configuration.Appenders | toYaml | nindent 4 }}
{{- $theRest := omit .Values.log4j2.Configuration "packages" "Appenders" }}
{{ $theRest | toYaml | indent 2 }}

PS: Although packages has to be before references to it, no such requirement applies to Appenders AFAIK - I just put Appenders in for illustration.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Mafor
Solution 2 Jason Crease