1694603c7221f5ffdd7f8bf0477f88f36bd2f05d
- Author
- td-jizdebski <jakub.izdebski@jrdltd.co.uk>
- Committer
- GitHub <noreply@github.com>
- Date
Message
Diff
This diff is truncated to protect this page.
1diff --git a/README.md b/README.md
2index 04e08cb25fbfa294132ead8c338add9c9b2992b8..d4f85bd5b8cdb7388f72806549ba8d9e87bbed9f 100644
3--- a/README.md
4+++ b/README.md
5@@ -37,13 +37,16 @@ Usage:
6 logfmt [OPTIONS]
7
8 Application Options:
9- -l, --level= Log level filter. One of DEBUG, INFO, WARN, ERROR, FATAL (default: INFO)
10- -o, --output= Output field selector (comma separated)
11- -e, --exclude= Exclude field selector (comma separated)
12- -f, --filter= Filter fields (key=value comma separated)
13- -n, --no-color Disable color output
14- -c, --force-color Force color output, even when outputting to a pipe
15- -s, --keep-empty Keep lines with no field present selected by output or with all excluded
16+ -l, --level= Log level filter. One of DEBUG, INFO, WARN, ERROR, FATAL (default: INFO)
17+ -o, --output= Output field selector (comma separated)
18+ -e, --exclude= Exclude field selector (comma separated)
19+ -f, --filter= Filter fields (key=value comma separated)
20+ -n, --no-color Disable color output
21+ -c, --force-color Force color output, even when outputting to a pipe
22+ -t, --no-time Disable time output
23+ -k, --keep-empty Keep lines with no field present selected by output or with all excluded
24+ -r, --raw Output only selected fields values (comma separated) lcut like
25+ -A, --all Output all field after the output fields effectivly making it ordered
26
27 Help Options:
28 -h, --help Show this help message
29@@ -98,6 +101,14 @@ you still want to have colorized output, for example when piping into `less`, yo
30
31 By default, `logfmt` doesn't output lines when no fields are selected. To **change that behavior** and **show empty lines**, pass the `-k` flag.
32
33+### Raw output
34+
35+Don't output keys just values (emulate lcut like behavior), also outputs timestamp and level keys by default. With -o singleField allow getting one field
36+
37+### Output All
38+
39+Output all keys if flag is set and treat output option as an order which fields should be displayed first
40+
41 ### Sponsors
42
43diff --git a/config/config.go b/config/config.go
44index 53ceded5163f5cffeb47e7605a180aa9127dad92..1d745a5616b0383a469f9f3a04278b74c63b3dc3 100644
45--- a/config/config.go
46+++ b/config/config.go
47@@ -29,17 +29,23 @@ type Config struct {
48 NoTime bool
49 // Keep lines with no fields
50 KeepEmpty bool
51+ // Only values
52+ Raw bool
53+ // All after output in record order (causes output to become order)
54+ All bool
55 }
56
57 type rawConfig struct {
58- LogLevel string `long:"level" short:"l" description:"Log level filter. One of DEBUG, INFO, WARN, ERROR, FATAL" default:"INFO"` // nolint:lll
59- OutputFields string `long:"output" short:"o" description:"Output field selector (comma separated)"`
60- ExcludeFields string `long:"exclude" short:"e" description:"Exclude field selector (comma separated)"`
61- Filter string `long:"filter" short:"f" description:"Filter fields (key=value comma separated)"`
62- NoColor bool `long:"no-color" short:"n" description:"Disable color output"`
63- ForceColor bool `long:"force-color" short:"c" description:"Force color output, even when outputting to a pipe"`
64- NoTime bool `long:"no-time" short:"t" description:"Disable time output"`
65- KeepEmpty bool `long:"keep-empty" short:"k" description:"Keep lines with no field present selected by output or with all excluded"`
66+ LogLevel string `long:"level" short:"l" description:"Log level filter. One of DEBUG, INFO, WARN, ERROR, FATAL" default:"INFO"` // nolint:lll
67+ OutputFields string `long:"output" short:"o" description:"Output field selector (comma separated)"`
68+ ExcludeFields string `long:"exclude" short:"e" description:"Exclude field selector (comma separated)"`
69+ Filter string `long:"filter" short:"f" description:"Filter fields (key=value comma separated)"`
70+ NoColor bool `long:"no-color" short:"n" description:"Disable color output"`
71+ ForceColor bool `long:"force-color" short:"c" description:"Force color output, even when outputting to a pipe"`
72+ NoTime bool `long:"no-time" short:"t" description:"Disable time output"`
73+ KeepEmpty bool `long:"keep-empty" short:"k" description:"Keep lines with no field present selected by output or with all excluded"`
74+ Raw bool `long:"raw" short:"r" description:"Output only selected fields values (comma separated) lcut like"`
75+ All bool `long:"all" short:"A" description:"Output all field after the output fields effectivly making it ordered"`
76 }
77
78 func Parse() (*Config, error) {
79@@ -51,7 +57,7 @@ func Parse() (*Config, error) {
80 return nil, err
81 }
82
83- if raw.ExcludeFields != "" && raw.OutputFields != "" {
84+ if raw.ExcludeFields != "" && raw.OutputFields != "" {
85 return nil, fmt.Errorf("cannot use both --exclude and --output")
86 }
87
88@@ -82,6 +88,12 @@ func Parse() (*Config, error) {
89 if raw.KeepEmpty {
90 cfg.KeepEmpty = true
91 }
92+ if raw.Raw {
93+ cfg.Raw = true
94+ }
95+ if raw.All {
96+ cfg.All = true
97+ }
98 return &cfg, nil
99 }
100
101diff --git a/parser/parser.go b/parser/parser.go
102index 90c6f266b825bba0d1618356f781444e59641b15..587ff88df12dc0a37db285e7d0122557bdbce6e1 100644
103--- a/parser/parser.go
104+++ b/parser/parser.go
105@@ -28,7 +28,7 @@ func NewParser(cfg *config.Config, input io.Reader, output io.Writer) *Parser {
106 func (p *Parser) Start() error {
107 decoder := logfmt.NewDecoder(p.input)
108 for decoder.ScanRecord() {
109- record, err := NewRecord(decoder)
110+ record, err := NewRecord(decoder, p.cfg)
111 if err != nil {
112 return err
113 }
114diff --git a/parser/record.go b/parser/record.go
115index 3b49fe427e8b80b4c2e10fb8d7f0f659d8f4ef73..f48dc63ca3685f9c4c3b97ed32f42d7ef3a93ce7 100644
116--- a/parser/record.go
117+++ b/parser/record.go
118@@ -44,7 +44,7 @@ type Record struct {
119 }
120
121 // NewRecord parses a new Record from a logfmt.Decoder
122-func NewRecord(decoder *logfmt.Decoder) (*Record, error) {
123+func NewRecord(decoder *logfmt.Decoder, cfg *config.Config) (*Record, error) {
124 var record Record
125 record.fields = make(map[string]string)
126 record.fieldOrder = make([]string, 0)
127@@ -57,14 +57,18 @@ func NewRecord(decoder *logfmt.Decoder) (*Record, error) {
128 key, value := string(decoder.Key()), string(decoder.Value())
129 if key == "level" {
130 record.parseLevel(value)
131- continue
132+ if !cfg.Raw {
133+ continue
134+ }
135 }
136 if slices.Contains(timestampLabels, key) {
137 err := record.parseTime(value)
138 if err != nil {
139 return nil, err
140 }
141- continue
142+ if !cfg.Raw {
143+ continue
144+ }
145 }
146 record.fields[key] = value
147 record.fieldOrder = append(record.fieldOrder, key)
148@@ -144,11 +148,22 @@ func (r *Record) MatchesFilter(filter map[string]string) bool {
149 func (r *Record) String(cfg *config.Config) string {
150 line := ""
151
152- // If OutputFields is specified, iterate through it to determine order
153 outFields := r.fieldOrder
154 if len(cfg.OutputFields) > 0 {
155- outFields = cfg.OutputFields
156+ if cfg.All {
157+ var reorderedFields []string = cfg.OutputFields
158+
159+ for _, key := range r.fieldOrder {
160+ if !slices.Contains(reorderedFields, key) {
161+ reorderedFields = append(reorderedFields, key)
162+ }
163+ }
164+ outFields = reorderedFields
165+ } else {
166+ outFields = cfg.OutputFields
167+ }
168 }
169+
170 for _, key := range outFields {
171 if len(cfg.ExcludeFields) > 0 && slices.Contains(cfg.ExcludeFields, key) {
172 continue
173@@ -158,13 +173,21 @@ func (r *Record) String(cfg *config.Config) string {
174 continue
175 }
176 key := color.HiBlueString(key)
177- line += fmt.Sprintf(" %s=%s", key, getFormattedValue(value))
178+ if cfg.Raw {
179+ line += fmt.Sprintf(" %s", value)
180+ } else {
181+ line += fmt.Sprintf(" %s=%s", key, getFormattedValue(value))
182+ }
183 }
184
185 if line == "" && !cfg.KeepEmpty {
186 return ""
187 }
188
189+ if cfg.Raw {
190+ return strings.TrimSpace(line)
191+ }
192+
193 var fmtString strings.Builder
194 if !cfg.NoTime {
195 fmtString.WriteString("%s ")