Diff
1diff --git a/README.md b/README.md
2index fad24f692ca9c155e88d19eb5055bec2c8ead75d..20bfca7aae996bf0771cda8a1b52dce9d0763705 100644
3--- a/README.md
4+++ b/README.md
5@@ -1,6 +1,6 @@
6 # logfmt CLI
7
8-This is a (very) simple logfmt CLI tool to make reading logfmt logs on your terminal easier.
9+This is a (very) simple CLI tool to make reading and parsing logfmt logs from your terminal easier.
10 It supports colorized output, output field selection, and log level and key value filtering.
11
12 ## What is logfmt?
13@@ -32,11 +32,12 @@ go install github.com/TheEdgeOfRage/logfmt
14
15 ```
16 Usage:
17- main [OPTIONS]
18+ logfmt [OPTIONS]
19
20 Application Options:
21 -l, --level= Log level filter. One of DEBUG, INFO, WARN, ERROR, FATAL (default: INFO)
22 -o, --output= Output field selector (comma separated)
23+ -e, --exclude= Exclude field selector (comma separated)
24 -f, --filter= Filter fields (key=value comma separated)
25 -n, --no-color Disable color output
26 -c, --force-color Force color output, even when outputting to a pipe
27@@ -69,6 +70,12 @@ show up.
28 You can pass in a comma separated list of fields to the `-o` flag that you want it to print to the output. The timestamp
29 and level are always printed, so this only applies to additional fields.
30
31+#### Excluding fields
32+
33+If you want to exclude some fields from the output, you can pass in a comma separated list of fields to the `-e` flag.
34+This can be useful in cases where you don't know what fields are going to be present in the logs, but want to exclude
35+some verbose ones.
36+
37 #### Filtering by values
38
39 If you want to only select records that have a specific value on a key, you can pass one or more comma separated filters
40diff --git a/config/config.go b/config/config.go
41index 0ab3ee2877aff3aa1115430c562ad28fe8d77cde..da4c70069c5499cfbaa212095ef524700bcccc77 100644
42--- a/config/config.go
43+++ b/config/config.go
44@@ -19,18 +19,21 @@ const (
45 type Config struct {
46 // LogLevel is the level filter for the log output
47 LogLevel int
48- // LogFormat is a list of fields to include on the log output
49+ // OutputFields is a list of fields to include on the log output
50 OutputFields []string
51+ // ExcludeFields is a list of fields to exclude from the log output
52+ ExcludeFields []string
53 // Filter is a map of fields and values which are used to filter the log output
54 Filter map[string]string
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- Filter string `long:"filter" short:"f" description:"Filter fields (key=value comma separated)"`
61- NoColor bool `long:"no-color" short:"n" description:"Disable color output"`
62- ForceColor bool `long:"force-color" short:"c" description:"Force color output, even when outputting to a pipe"`
63+ LogLevel string `long:"level" short:"l" description:"Log level filter. One of DEBUG, INFO, WARN, ERROR, FATAL" default:"INFO"` // nolint:lll
64+ OutputFields string `long:"output" short:"o" description:"Output field selector (comma separated)"`
65+ ExcludeFields string `long:"exclude" short:"e" description:"Exclude field selector (comma separated)"`
66+ Filter string `long:"filter" short:"f" description:"Filter fields (key=value comma separated)"`
67+ NoColor bool `long:"no-color" short:"n" description:"Disable color output"`
68+ ForceColor bool `long:"force-color" short:"c" description:"Force color output, even when outputting to a pipe"`
69 }
70
71 func Parse() (*Config, error) {
72@@ -42,8 +45,10 @@ func Parse() (*Config, error) {
73 return nil, err
74 }
75
76- cfg := Config{}
77- cfg.setOutputFields(raw.OutputFields)
78+ cfg := Config{
79+ OutputFields: parseFieldList(raw.OutputFields),
80+ ExcludeFields: parseFieldList(raw.ExcludeFields),
81+ }
82 err = cfg.setFilter(raw.Filter)
83 if err != nil {
84 return nil, err
85@@ -83,12 +88,12 @@ func (c *Config) setLevel(level string) error {
86 return nil
87 }
88
89-func (c *Config) setOutputFields(fields string) {
90+func parseFieldList(fields string) []string {
91 fields = strings.Trim(fields, " ")
92 if fields == "" {
93- return
94+ return nil
95 }
96- c.OutputFields = strings.Split(fields, ",")
97+ return strings.Split(fields, ",")
98 }
99
100 func (c *Config) setFilter(filter string) error {
101diff --git a/parser/parser.go b/parser/parser.go
102index ff76b7045abd78f6a5cff198efd7ccafbb872ab5..909d5fd0eb88ebf298832733711e81a2f830102b 100644
103--- a/parser/parser.go
104+++ b/parser/parser.go
105@@ -37,7 +37,7 @@ func (p *Parser) Start() error {
106 continue
107 }
108
109- _, err = fmt.Fprintf(p.output, "%s\n", record.String(p.cfg.OutputFields))
110+ _, err = fmt.Fprintf(p.output, "%s\n", record.String(p.cfg.OutputFields, p.cfg.ExcludeFields))
111 if err != nil {
112 return fmt.Errorf("failed to print log to output: %w", err)
113 }
114diff --git a/parser/record.go b/parser/record.go
115index fcc34e805523b304f7857b1a797e84dddc4bccae..d2c630a90fdd06872fd80ac524e7dab65792374a 100644
116--- a/parser/record.go
117+++ b/parser/record.go
118@@ -140,12 +140,15 @@ func (r *Record) MatchesFilter(filter map[string]string) bool {
119 }
120
121 // String returns a formatted string representation of the Record
122-func (r *Record) String(outputFields []string) string {
123+func (r *Record) String(outputFields []string, excludeFields []string) string {
124 line := ""
125 for _, key := range r.fieldOrder {
126 if len(outputFields) > 0 && !slices.Contains(outputFields, key) {
127 continue
128 }
129+ if len(excludeFields) > 0 && slices.Contains(excludeFields, key) {
130+ continue
131+ }
132 value := r.fields[key]
133 key = color.HiBlueString(key)
134 line += fmt.Sprintf("%s=%s ", key, getFormattedValue(value))