maddy

Fork https://github.com/foxcpp/maddy

git clone git://git.lin.moe/go/maddy.git

 1/*
 2Maddy Mail Server - Composable all-in-one email server.
 3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors
 4
 5This program is free software: you can redistribute it and/or modify
 6it under the terms of the GNU General Public License as published by
 7the Free Software Foundation, either version 3 of the License, or
 8(at your option) any later version.
 9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program.  If not, see <https://www.gnu.org/licenses/>.
17*/
18
19package log
20
21import (
22	"encoding/json"
23	"fmt"
24	"sort"
25	"strings"
26	"time"
27)
28
29// To support ad-hoc parsing in a better way we want to make order of fields in
30// output JSON documents determistics. Additionally, this will make them more
31// human-readable when values from multiple messages are lined up to each
32// other.
33
34type module interface {
35	Name() string
36	InstanceName() string
37}
38
39func marshalOrderedJSON(output *strings.Builder, m map[string]interface{}) error {
40	order := make([]string, 0, len(m))
41	for k := range m {
42		order = append(order, k)
43	}
44	sort.Strings(order)
45
46	output.WriteRune('{')
47	for i, key := range order {
48		if i != 0 {
49			output.WriteRune(',')
50		}
51
52		jsonKey, err := json.Marshal(key)
53		if err != nil {
54			return err
55		}
56
57		output.Write(jsonKey)
58		output.WriteString(":")
59
60		val := m[key]
61		switch casted := val.(type) {
62		case time.Time:
63			val = casted.Format("2006-01-02T15:04:05.000")
64		case time.Duration:
65			val = casted.String()
66		case LogFormatter:
67			val = casted.FormatLog()
68		case fmt.Stringer:
69			val = casted.String()
70		case module:
71			val = casted.Name() + "/" + casted.InstanceName()
72		case error:
73			val = casted.Error()
74		}
75
76		jsonValue, err := json.Marshal(val)
77		if err != nil {
78			return err
79		}
80		output.Write(jsonValue)
81	}
82	output.WriteRune('}')
83
84	return nil
85}