@@ -69,6 +69,11 @@ type ConsoleWriter struct {
6969 // PartsExclude defines parts to not display in output.
7070 PartsExclude []string
7171
72+ // FieldsOrder defines the order of contextual fields in output.
73+ FieldsOrder []string
74+
75+ fieldIsOrdered map [string ]int
76+
7277 // FieldsExclude defines contextual fields to not display in output.
7378 FieldsExclude []string
7479
@@ -191,7 +196,12 @@ func (w ConsoleWriter) writeFields(evt map[string]interface{}, buf *bytes.Buffer
191196 }
192197 fields = append (fields , field )
193198 }
194- sort .Strings (fields )
199+
200+ if len (w .FieldsOrder ) > 0 {
201+ w .orderFields (fields )
202+ } else {
203+ sort .Strings (fields )
204+ }
195205
196206 // Write space only if something has already been written to the buffer, and if there are fields.
197207 if buf .Len () > 0 && len (fields ) > 0 {
@@ -324,6 +334,32 @@ func (w ConsoleWriter) writePart(buf *bytes.Buffer, evt map[string]interface{},
324334 }
325335}
326336
337+ // orderFields takes an array of field names and an array representing field order
338+ // and returns an array with any ordered fields at the beginning, in order,
339+ // and the remaining fields after in their original order.
340+ func (w ConsoleWriter ) orderFields (fields []string ) {
341+ if w .fieldIsOrdered == nil {
342+ w .fieldIsOrdered = make (map [string ]int )
343+ for i , fieldName := range w .FieldsOrder {
344+ w .fieldIsOrdered [fieldName ] = i
345+ }
346+ }
347+ sort .Slice (fields , func (i , j int ) bool {
348+ ii , iOrdered := w.fieldIsOrdered [fields [i ]]
349+ jj , jOrdered := w.fieldIsOrdered [fields [j ]]
350+ if iOrdered && jOrdered {
351+ return ii < jj
352+ }
353+ if iOrdered {
354+ return true
355+ }
356+ if jOrdered {
357+ return false
358+ }
359+ return fields [i ] < fields [j ]
360+ })
361+ }
362+
327363// needsQuote returns true when the string s should be quoted in output.
328364func needsQuote (s string ) bool {
329365 for i := range s {
0 commit comments