Diff
1diff --git a/.golangci.yml b/.golangci.yml
2new file mode 100644
3index 0000000000000000000000000000000000000000..5cb0a2b1577094d6a2884a1fff78125d34ed0186
4--- /dev/null
5+++ b/.golangci.yml
6@@ -0,0 +1,22 @@
7+---
8+linters:
9+ enable:
10+ - goimports
11+ - stylecheck
12+ - lll
13+ - errcheck
14+
15+run:
16+ go: '1.22'
17+ timeout: 30s
18+
19+issues:
20+ exclude-rules:
21+ - linters:
22+ - lll
23+ source: "// nolint:lll"
24+ - linters:
25+ - unused
26+ - deadcode
27+ - varcheck
28+ source: "// nolint:unused"
29diff --git a/go.mod b/go.mod
30new file mode 100644
31index 0000000000000000000000000000000000000000..031cfca89a1f005ab8044e67a0fe62da86371e75
32--- /dev/null
33+++ b/go.mod
34@@ -0,0 +1,14 @@
35+module github.com/TheEdgeOfRage/logfmt
36+
37+go 1.22.0
38+
39+require (
40+ github.com/fatih/color v1.16.0
41+ github.com/go-logfmt/logfmt v0.6.0
42+)
43+
44+require (
45+ github.com/mattn/go-colorable v0.1.13 // indirect
46+ github.com/mattn/go-isatty v0.0.20 // indirect
47+ golang.org/x/sys v0.14.0 // indirect
48+)
49diff --git a/go.sum b/go.sum
50new file mode 100644
51index 0000000000000000000000000000000000000000..9fad359a24bf325299396920c3de725ae0c5341b
52--- /dev/null
53+++ b/go.sum
54@@ -0,0 +1,13 @@
55+github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
56+github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
57+github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
58+github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
59+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
60+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
61+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
62+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
63+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
64+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
65+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
66+golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
67+golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
68diff --git a/main.go b/main.go
69new file mode 100644
70index 0000000000000000000000000000000000000000..35a979dfa89d8395a798288aded0f72fc82cb569
71--- /dev/null
72+++ b/main.go
73@@ -0,0 +1,90 @@
74+package main
75+
76+import (
77+ "fmt"
78+ "os"
79+ "strconv"
80+ "strings"
81+
82+ "github.com/fatih/color"
83+ "github.com/go-logfmt/logfmt"
84+)
85+
86+const (
87+ Debug = "DEBUG"
88+ Info = "INFO"
89+ Warning = "WARN"
90+ Error = "ERROR"
91+ Fatal = "FATAL"
92+)
93+
94+var levelColors map[string]*color.Color
95+
96+func init() {
97+ levelColors = map[string]*color.Color{
98+ Debug: color.New(color.FgBlack).Add(color.BgCyan).Add(color.Bold),
99+ Info: color.New(color.FgBlack).Add(color.BgGreen).Add(color.Bold),
100+ Warning: color.New(color.FgBlack).Add(color.BgYellow).Add(color.Bold),
101+ Error: color.New(color.FgBlack).Add(color.BgRed).Add(color.Bold),
102+ Fatal: color.New(color.FgBlack).Add(color.BgRed).Add(color.Bold),
103+ }
104+}
105+
106+func isNumeric(s string) bool {
107+ _, err := strconv.ParseFloat(s, 64)
108+ return err == nil
109+}
110+
111+func isBoolean(s string) bool {
112+ _, err := strconv.ParseBool(s)
113+ return err == nil
114+}
115+
116+func isNull(s string) bool {
117+ return s == "null" || s == "NULL" || s == "nil" || s == "<nil>" || s == "None"
118+}
119+
120+func getLevel(level string) string {
121+ level = strings.ToUpper(level)
122+ if level == "WARNING" {
123+ level = Warning
124+ }
125+ val, ok := levelColors[level]
126+ if !ok {
127+ return levelColors[Info].Sprintf("[%s]", Info)
128+ }
129+ return val.Sprintf("[%s]", level)
130+}
131+
132+func getValue(value string) string {
133+ if isNumeric(value) || isBoolean(value) {
134+ return color.MagentaString(value)
135+ }
136+ if isNull(value) {
137+ return color.YellowString(value)
138+ }
139+ return color.HiGreenString(value)
140+}
141+
142+func main() {
143+ decoder := logfmt.NewDecoder(os.Stdin)
144+ for decoder.ScanRecord() {
145+ line := ""
146+ level := Info
147+ timestamp := ""
148+ for decoder.ScanKeyval() {
149+ key, value := string(decoder.Key()), string(decoder.Value())
150+ if key == "level" {
151+ level = getLevel(value)
152+ continue
153+ }
154+ if key == "time" || key == "timestamp" {
155+ timestamp = value
156+ continue
157+ }
158+ line += fmt.Sprintf("%s=%s ", color.HiBlueString(key), getValue(value))
159+ }
160+
161+ fmt.Printf("%s %26s %s\n", timestamp, level, line)
162+ }
163+}