Skip to content

Commit

Permalink
Support logs panel types
Browse files Browse the repository at this point in the history
  • Loading branch information
K-Phoen committed Dec 29, 2021
1 parent 66b0fc6 commit cf26c84
Show file tree
Hide file tree
Showing 11 changed files with 582 additions and 6 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/K-Phoen/grabana
go 1.16

require (
github.com/K-Phoen/sdk v0.8.1
github.com/K-Phoen/sdk v0.8.3
github.com/blang/semver v3.5.1+incompatible
github.com/gosimple/slug v1.12.0 // indirect
github.com/prometheus/common v0.32.0
Expand Down
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/K-Phoen/sdk v0.0.0-20211119151408-adef1e5fdd11 h1:bcJqfzSQge+pyJ1beMzUmf3bh9bRyIzEFu8PXUx8Hgk=
github.com/K-Phoen/sdk v0.0.0-20211119151408-adef1e5fdd11/go.mod h1:fnbOsbRksULSfcXjOI6W1/HISz5o/u1iEhF/fLedqTg=
github.com/K-Phoen/sdk v0.8.1 h1:Z4niyQJKXZcBbBULLFw55axv56SxlL3REBZjNn1B/HA=
github.com/K-Phoen/sdk v0.8.1/go.mod h1:fnbOsbRksULSfcXjOI6W1/HISz5o/u1iEhF/fLedqTg=
github.com/K-Phoen/sdk v0.8.3 h1:UZU6UfWlIBkMH8rx/qUgTxcEYLtGyh49xvjJFePrVyI=
github.com/K-Phoen/sdk v0.8.3/go.mod h1:fnbOsbRksULSfcXjOI6W1/HISz5o/u1iEhF/fLedqTg=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
Expand Down
168 changes: 168 additions & 0 deletions logs/logs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package logs

import (
"github.com/K-Phoen/grabana/target/loki"
"github.com/K-Phoen/sdk"
)

// DedupStrategy represents a deduplication strategy.
type DedupStrategy string

const (
None DedupStrategy = "none"
Exact DedupStrategy = "exact"
Numbers DedupStrategy = "numbers"
Signature DedupStrategy = "signature"
)

// SortOrder represents a sort order.
type SortOrder string

const (
Asc SortOrder = "Ascending"
Desc SortOrder = "Descending"
)

// Option represents an option that can be used to configure a logs panel.
type Option func(logs *Logs)

// Logs represents a logs panel.
type Logs struct {
Builder *sdk.Panel
}

// New creates a new heatmap panel.
func New(title string, options ...Option) *Logs {
panel := &Logs{Builder: sdk.NewLogs(title)}
panel.Builder.IsNew = false
panel.Builder.LogsPanel.Options.EnableLogDetails = true

for _, opt := range append(defaults(), options...) {
opt(panel)
}

return panel
}

func defaults() []Option {
return []Option{
Span(6),
Order(Desc),
}
}

// DataSource sets the data source to be used by the panel.
func DataSource(source string) Option {
return func(logs *Logs) {
logs.Builder.Datasource = &source
}
}

// WithLokiTarget adds a loki query to the graph.
func WithLokiTarget(query string, options ...loki.Option) Option {
target := loki.New(query, options...)

return func(logs *Logs) {
logs.Builder.AddTarget(&sdk.Target{
RefID: target.Ref,
Expr: target.Expr,
LegendFormat: target.LegendFormat,
})
}
}

// Span sets the width of the panel, in grid units. Should be a positive
// number between 1 and 12. Example: 6.
func Span(span float32) Option {
return func(logs *Logs) {
logs.Builder.Span = span
}
}

// Height sets the height of the panel, in pixels. Example: "400px".
func Height(height string) Option {
return func(logs *Logs) {
logs.Builder.Height = &height
}
}

// Description annotates the current visualization with a human-readable description.
func Description(content string) Option {
return func(logs *Logs) {
logs.Builder.Description = &content
}
}

// Transparent makes the background transparent.
func Transparent() Option {
return func(logs *Logs) {
logs.Builder.Transparent = true
}
}

// Repeat configures repeating a panel for a variable
func Repeat(repeat string) Option {
return func(logs *Logs) {
logs.Builder.Repeat = &repeat
}
}

// Time displays the "time" column. This is the timestamp associated with the
// log line as reported from the data source.
func Time() Option {
return func(logs *Logs) {
logs.Builder.LogsPanel.Options.ShowTime = true
}
}

// UniqueLabels displays the "unique labels" column, which shows only non-common labels.
func UniqueLabels() Option {
return func(logs *Logs) {
logs.Builder.LogsPanel.Options.ShowLabels = true
}
}

// CommonLabels displays the "common labels".
func CommonLabels() Option {
return func(logs *Logs) {
logs.Builder.LogsPanel.Options.ShowCommonLabels = true
}
}

// WrapLines enables line wrapping.
func WrapLines() Option {
return func(logs *Logs) {
logs.Builder.LogsPanel.Options.WrapLogMessage = true
}
}

// PrettifyJSON pretty prints all JSON logs. This setting does not affect logs
// in any format other than JSON.
func PrettifyJSON() Option {
return func(logs *Logs) {
logs.Builder.LogsPanel.Options.PrettifyLogMessage = true
}
}

// HideLogDetails disables the log details view for each log row.
func HideLogDetails() Option {
return func(logs *Logs) {
logs.Builder.LogsPanel.Options.EnableLogDetails = false
}
}

// Order display results in descending or ascending time order.
// The default is Descending, showing the newest logs first.
// Set to Ascending to show the oldest log lines first.
func Order(order SortOrder) Option {
return func(logs *Logs) {
logs.Builder.LogsPanel.Options.SortOrder = string(order)
}
}

// Deduplication sets the deduplication strategy.
func Deduplication(dedup DedupStrategy) Option {
return func(logs *Logs) {
logs.Builder.LogsPanel.Options.DedupStrategy = string(dedup)
}
}
171 changes: 171 additions & 0 deletions logs/logs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package logs

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestNewLogsPanelsCanBeCreated(t *testing.T) {
req := require.New(t)

panel := New("Logs panel")

req.False(panel.Builder.IsNew)
req.Equal("Logs panel", panel.Builder.Title)
req.Equal(float32(6), panel.Builder.Span)
req.Equal("Descending", panel.Builder.LogsPanel.Options.SortOrder)
req.True(panel.Builder.LogsPanel.Options.EnableLogDetails)
}

func TestLogsPanelCanHaveLokiTargets(t *testing.T) {
req := require.New(t)

panel := New("", WithLokiTarget("{app=\"loki\"}"))

req.Len(panel.Builder.LogsPanel.Targets, 1)
}

func TestLogsPanelWidthCanBeConfigured(t *testing.T) {
req := require.New(t)

panel := New("", Span(8))

req.Equal(float32(8), panel.Builder.Span)
}

func TestLogsPanelHeightCanBeConfigured(t *testing.T) {
req := require.New(t)

panel := New("", Height("400px"))

req.Equal("400px", *(panel.Builder.Height).(*string))
}

func TestLogsPanelBackgroundCanBeTransparent(t *testing.T) {
req := require.New(t)

panel := New("", Transparent())

req.True(panel.Builder.Transparent)
}

func TestLogsPanelDescriptionCanBeSet(t *testing.T) {
req := require.New(t)

panel := New("", Description("lala"))

req.NotNil(panel.Builder.Description)
req.Equal("lala", *panel.Builder.Description)
}

func TestLogsPanelDataSourceCanBeConfigured(t *testing.T) {
req := require.New(t)

panel := New("", DataSource("loki-default"))

req.Equal("loki-default", *panel.Builder.Datasource)
}

func TestRepeatCanBeConfigured(t *testing.T) {
req := require.New(t)

panel := New("", Repeat("ds"))

req.NotNil(panel.Builder.Repeat)
req.Equal("ds", *panel.Builder.Repeat)
}

func TestTimeCanBeDisplayed(t *testing.T) {
req := require.New(t)

panel := New("", Time())

req.True(panel.Builder.LogsPanel.Options.ShowTime)
}

func TestUniqueLabelsCanBeDisplayed(t *testing.T) {
req := require.New(t)

panel := New("", UniqueLabels())

req.True(panel.Builder.LogsPanel.Options.ShowLabels)
}

func TestCommonLabelsCanBeDisplayed(t *testing.T) {
req := require.New(t)

panel := New("", CommonLabels())

req.True(panel.Builder.LogsPanel.Options.ShowCommonLabels)
}

func TestLinesCanBeWrapped(t *testing.T) {
req := require.New(t)

panel := New("", WrapLines())

req.True(panel.Builder.LogsPanel.Options.WrapLogMessage)
}

func TestJSONCanBePrettyPrinted(t *testing.T) {
req := require.New(t)

panel := New("", PrettifyJSON())

req.True(panel.Builder.LogsPanel.Options.PrettifyLogMessage)
}

func TestLogDetailsCanBeDisabled(t *testing.T) {
req := require.New(t)

panel := New("", HideLogDetails())

req.False(panel.Builder.LogsPanel.Options.EnableLogDetails)
}

func TestSortOrderCanBeSet(t *testing.T) {
testCases := []struct {
order SortOrder
expected string
}{
{order: Asc, expected: "Ascending"},
{order: Desc, expected: "Descending"},
}

for _, testCase := range testCases {
tc := testCase

t.Run(tc.expected, func(t *testing.T) {
req := require.New(t)

panel := New("", Order(tc.order))

req.Equal(tc.expected, panel.Builder.LogsPanel.Options.SortOrder)
})
}
}

func TestDedupStrategyCanBeSet(t *testing.T) {
testCases := []struct {
strategy DedupStrategy
expected string
}{
{strategy: None, expected: "none"},
{strategy: Exact, expected: "exact"},
{strategy: Numbers, expected: "numbers"},
{strategy: Signature, expected: "signature"},
}

for _, testCase := range testCases {
tc := testCase

t.Run(tc.expected, func(t *testing.T) {
req := require.New(t)

panel := New("", Deduplication(tc.strategy))

req.Equal(tc.expected, panel.Builder.LogsPanel.Options.DedupStrategy)
})
}
}
10 changes: 10 additions & 0 deletions row/row.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package row
import (
"github.com/K-Phoen/grabana/graph"
"github.com/K-Phoen/grabana/heatmap"
"github.com/K-Phoen/grabana/logs"
"github.com/K-Phoen/grabana/singlestat"
"github.com/K-Phoen/grabana/table"
"github.com/K-Phoen/grabana/text"
Expand Down Expand Up @@ -53,6 +54,15 @@ func WithTimeSeries(title string, options ...timeseries.Option) Option {
}
}

// WithLogs adds a "logs" panel in the row.
func WithLogs(title string, options ...logs.Option) Option {
return func(row *Row) {
panel := logs.New(title, options...)

row.builder.Add(panel.Builder)
}
}

// WithSingleStat adds a "single stat" panel in the row.
func WithSingleStat(title string, options ...singlestat.Option) Option {
return func(row *Row) {
Expand Down
Loading

0 comments on commit cf26c84

Please sign in to comment.