Skip to content

Commit

Permalink
colored labels output for logcli (#2470)
Browse files Browse the repository at this point in the history
* colored labels output for logcli

* add period to all cli description
  • Loading branch information
adityacs authored Aug 8, 2020
1 parent 36164bb commit 68568f1
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 33 deletions.
12 changes: 7 additions & 5 deletions cmd/logcli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ var (
statistics = app.Flag("stats", "Show query statistics").Default("false").Bool()
outputMode = app.Flag("output", "Specify output mode [default, raw, jsonl]. raw suppresses log labels and timestamp.").Default("default").Short('o').Enum("default", "raw", "jsonl")
timezone = app.Flag("timezone", "Specify the timezone to use when formatting output timestamps [Local, UTC]").Default("Local").Short('z').Enum("Local", "UTC")

cpuProfile = app.Flag("cpuprofile", "Specify the location for writing a CPU profile.").Default("").String()
memProfile = app.Flag("memprofile", "Specify the location for writing a memory profile.").Default("").String()

Expand Down Expand Up @@ -119,8 +118,9 @@ func main() {
}

outputOptions := &output.LogOutputOptions{
Timezone: location,
NoLabels: rangeQuery.NoLabels,
Timezone: location,
NoLabels: rangeQuery.NoLabels,
ColoredOutput: rangeQuery.ColoredOutput,
}

out, err := output.NewLogOutput(*outputMode, outputOptions)
Expand All @@ -140,8 +140,9 @@ func main() {
}

outputOptions := &output.LogOutputOptions{
Timezone: location,
NoLabels: instantQuery.NoLabels,
Timezone: location,
NoLabels: instantQuery.NoLabels,
ColoredOutput: instantQuery.ColoredOutput,
}

out, err := output.NewLogOutput(*outputMode, outputOptions)
Expand Down Expand Up @@ -280,6 +281,7 @@ func newQuery(instant bool, cmd *kingpin.CmdClause) *query.Query {
cmd.Flag("include-label", "Include labels given the provided key during output.").StringsVar(&q.ShowLabelsKey)
cmd.Flag("labels-length", "Set a fixed padding to labels").Default("0").IntVar(&q.FixedLabelsLen)
cmd.Flag("store-config", "Execute the current query using a configured storage from a given Loki configuration file.").Default("").StringVar(&q.LocalConfig)
cmd.Flag("colored-output", "Show ouput with colored labels").Default("false").BoolVar(&q.ColoredOutput)

return q
}
Expand Down
47 changes: 24 additions & 23 deletions docs/sources/getting-started/logcli.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ A command-line for loki.
Flags:
--help Show context-sensitive help (also try --help-long and --help-man).
--version Show application version.
-q, --quiet Suppress query metadata
--stats Show query statistics
-q, --quiet Suppress query metadata.
--stats Show query statistics.
-o, --output=default Specify output mode [default, raw, jsonl]. raw suppresses log labels and timestamp.
-z, --timezone=Local Specify the timezone to use when formatting output timestamps [Local, UTC]
-z, --timezone=Local Specify the timezone to use when formatting output timestamps [Local, UTC].
--cpuprofile="" Specify the location for writing a CPU profile.
--memprofile="" Specify the location for writing a memory profile.
--addr="http://localhost:3100"
Expand Down Expand Up @@ -164,10 +164,10 @@ instead.
Flags:
--help Show context-sensitive help (also try --help-long and --help-man).
--version Show application version.
-q, --quiet Suppress query metadata
--stats Show query statistics
-q, --quiet Suppress query metadata.
--stats Show query statistics.
-o, --output=default Specify output mode [default, raw, jsonl]. raw suppresses log labels and timestamp.
-z, --timezone=Local Specify the timezone to use when formatting output timestamps [Local, UTC]
-z, --timezone=Local Specify the timezone to use when formatting output timestamps [Local, UTC].
--cpuprofile="" Specify the location for writing a CPU profile.
--memprofile="" Specify the location for writing a memory profile.
--addr="http://localhost:3100"
Expand All @@ -182,22 +182,23 @@ Flags:
bypassing an auth gateway.
--limit=30 Limit on number of entries to print.
--since=1h Lookback window.
--from=FROM Start looking for logs at this absolute time (inclusive)
--to=TO Stop looking for logs at this absolute time (exclusive)
--from=FROM Start looking for logs at this absolute time (inclusive).
--to=TO Stop looking for logs at this absolute time (exclusive).
--step=STEP Query resolution step width, for metric queries. Evaluate the query at the specified step over the time
range.
--interval=INTERVAL Query interval, for log queries. Return entries at the specified interval, ignoring those between.
**This parameter is experimental, please see Issue 1779**
**This parameter is experimental, please see Issue 1779**.
--forward Scan forwards through logs.
--no-labels Do not print any labels
--no-labels Do not print any labels.
--exclude-label=EXCLUDE-LABEL ...
Exclude labels given the provided key during output.
--include-label=INCLUDE-LABEL ...
Include labels given the provided key during output.
--labels-length=0 Set a fixed padding to labels
--labels-length=0 Set a fixed padding to labels.
--store-config="" Execute the current query using a configured storage from a given Loki configuration file.
-t, --tail Tail the logs
--delay-for=0 Delay in tailing by number of seconds to accumulate logs for re-ordering
-t, --tail Tail the logs.
--delay-for=0 Delay in tailing by number of seconds to accumulate logs for re-ordering.
--colored-output Show ouput with colored labels.
Args:
<query> eg '{foo="bar",baz=~".*blip"} |~ ".*error.*"'
Expand All @@ -210,10 +211,10 @@ Find values for a given label.
Flags:
--help Show context-sensitive help (also try --help-long and --help-man).
--version Show application version.
-q, --quiet Suppress query metadata
--stats Show query statistics
-q, --quiet Suppress query metadata.
--stats Show query statistics.
-o, --output=default Specify output mode [default, raw, jsonl]. raw suppresses log labels and timestamp.
-z, --timezone=Local Specify the timezone to use when formatting output timestamps [Local, UTC]
-z, --timezone=Local Specify the timezone to use when formatting output timestamps [Local, UTC].
--cpuprofile="" Specify the location for writing a CPU profile.
--memprofile="" Specify the location for writing a memory profile.
--addr="http://localhost:3100"
Expand All @@ -227,8 +228,8 @@ Flags:
--org-id="" adds X-Scope-OrgID to API requests for representing tenant ID. Useful for requesting tenant data when
bypassing an auth gateway.
--since=1h Lookback window.
--from=FROM Start looking for labels at this absolute time (inclusive)
--to=TO Stop looking for labels at this absolute time (exclusive)
--from=FROM Start looking for labels at this absolute time (inclusive).
--to=TO Stop looking for labels at this absolute time (exclusive).
Args:
[<label>] The name of the label.
Expand All @@ -241,10 +242,10 @@ Run series query.
Flags:
--help Show context-sensitive help (also try --help-long and --help-man).
--version Show application version.
-q, --quiet Suppress query metadata
--stats Show query statistics
-q, --quiet Suppress query metadata.
--stats Show query statistics.
-o, --output=default Specify output mode [default, raw, jsonl]. raw suppresses log labels and timestamp.
-z, --timezone=Local Specify the timezone to use when formatting output timestamps [Local, UTC]
-z, --timezone=Local Specify the timezone to use when formatting output timestamps [Local, UTC].
--cpuprofile="" Specify the location for writing a CPU profile.
--memprofile="" Specify the location for writing a memory profile.
--addr="http://localhost:3100"
Expand All @@ -258,8 +259,8 @@ Flags:
--org-id="" adds X-Scope-OrgID to API requests for representing tenant ID. Useful for requesting tenant data when
bypassing an auth gateway.
--since=1h Lookback window.
--from=FROM Start looking for logs at this absolute time (inclusive)
--to=TO Stop looking for logs at this absolute time (exclusive)
--from=FROM Start looking for logs at this absolute time (inclusive).
--to=TO Stop looking for logs at this absolute time (exclusive).
--match=MATCH ... eg '{foo="bar",baz=~".*blip"}'
```
5 changes: 5 additions & 0 deletions pkg/logcli/output/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ func (o *DefaultOutput) Format(ts time.Time, lbls loghttp.LabelSet, maxLabelsLen
return fmt.Sprintf("%s %s", color.BlueString(timestamp), line)
}

if o.options.ColoredOutput {
labelsColor := getColor(lbls.String()).SprintFunc()
return fmt.Sprintf("%s %s %s", color.BlueString(timestamp), labelsColor(padLabel(lbls, maxLabelsLen)), line)
}

return fmt.Sprintf("%s %s %s", color.BlueString(timestamp), color.RedString(padLabel(lbls, maxLabelsLen)), line)
}

Expand Down
43 changes: 43 additions & 0 deletions pkg/logcli/output/default_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,49 @@ func TestDefaultOutput_FormatLabelsPadding(t *testing.T) {
}
}

func TestColorForLabels(t *testing.T) {
tests := map[string]struct {
labels loghttp.LabelSet
otherLabels loghttp.LabelSet
expected bool
}{

"different labels": {
loghttp.LabelSet(map[string]string{
"type": "test",
"app": "loki",
}),
loghttp.LabelSet(map[string]string{
"type": "test",
"app": "grafana-loki",
}),
false,
},
"same labels": {
loghttp.LabelSet(map[string]string{
"type": "test",
"app": "loki",
}),
loghttp.LabelSet(map[string]string{
"type": "test",
"app": "loki",
}),
true,
},
}

for testName, testData := range tests {
testData := testData

t.Run(testName, func(t *testing.T) {
t.Parallel()
labelsColor := getColor(testData.labels.String())
otherLablesColor := getColor(testData.otherLabels.String())
assert.Equal(t, testData.expected, labelsColor.Equals(otherLablesColor))
})
}
}

func findMaxLabelsLength(labelsList []loghttp.LabelSet) int {
maxLabelsLen := 0

Expand Down
31 changes: 29 additions & 2 deletions pkg/logcli/output/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,39 @@ package output

import (
"fmt"
"hash/fnv"
"time"

"github.com/fatih/color"

"github.com/grafana/loki/pkg/loghttp"
)

// Blue color is excluded since we are already printing timestamp
// in blue color
var colorList = []*color.Color{
color.New(color.FgHiCyan),
color.New(color.FgCyan),
color.New(color.FgHiGreen),
color.New(color.FgGreen),
color.New(color.FgHiMagenta),
color.New(color.FgMagenta),
color.New(color.FgHiYellow),
color.New(color.FgYellow),
color.New(color.FgHiRed),
color.New(color.FgRed),
}

// LogOutput is the interface any output mode must implement
type LogOutput interface {
Format(ts time.Time, lbls loghttp.LabelSet, maxLabelsLen int, line string) string
}

// LogOutputOptions defines options supported by LogOutput
type LogOutputOptions struct {
Timezone *time.Location
NoLabels bool
Timezone *time.Location
NoLabels bool
ColoredOutput bool
}

// NewLogOutput creates a log output based on the input mode and options
Expand All @@ -41,3 +60,11 @@ func NewLogOutput(mode string, options *LogOutputOptions) (LogOutput, error) {
return nil, fmt.Errorf("unknown log output mode '%s'", mode)
}
}

func getColor(labels string) *color.Color {
hash := fnv.New32()
hash.Write([]byte(labels))
id := hash.Sum32() % uint32(len(colorList))
color := colorList[id]
return color
}
2 changes: 1 addition & 1 deletion pkg/logcli/output/output_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

func TestNewLogOutput(t *testing.T) {
options := &LogOutputOptions{time.UTC, false}
options := &LogOutputOptions{time.UTC, false, false}

out, err := NewLogOutput("default", options)
assert.NoError(t, err)
Expand Down
4 changes: 2 additions & 2 deletions pkg/logcli/query/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ type Query struct {
IgnoreLabelsKey []string
ShowLabelsKey []string
FixedLabelsLen int

LocalConfig string
ColoredOutput bool
LocalConfig string
}

// DoQuery executes the query and prints out the results
Expand Down

0 comments on commit 68568f1

Please sign in to comment.