diff --git a/internal/pkg/converter/json.go b/internal/pkg/converter/json.go index 45b1781a..1df89de2 100644 --- a/internal/pkg/converter/json.go +++ b/internal/pkg/converter/json.go @@ -191,6 +191,8 @@ func (converter *JSON) convertDataPanel(panel sdk.Panel) (grabana.DashboardPanel return converter.convertTimeSeries(panel), true case "gauge": return converter.convertGauge(panel), true + case "logs": + return converter.convertLogs(panel), true default: converter.logger.Warn("unhandled panel type: skipped", zap.String("type", panel.Type), zap.String("title", panel.Title)) } diff --git a/internal/pkg/converter/logs.go b/internal/pkg/converter/logs.go new file mode 100644 index 00000000..6c5edc56 --- /dev/null +++ b/internal/pkg/converter/logs.go @@ -0,0 +1,90 @@ +package converter + +import ( + grabana "github.com/K-Phoen/grabana/decoder" + "github.com/K-Phoen/grabana/logs" + "github.com/K-Phoen/sdk" + "go.uber.org/zap" +) + +func (converter *JSON) convertLogs(panel sdk.Panel) grabana.DashboardPanel { + convertedLogs := &grabana.DashboardLogs{ + Title: panel.Title, + Span: panelSpan(panel), + Transparent: panel.Transparent, + Visualization: converter.convertLogsVizualization(panel), + } + + if panel.Description != nil { + convertedLogs.Description = *panel.Description + } + if panel.Height != nil { + convertedLogs.Height = *(panel.Height).(*string) + } + if panel.Datasource != nil { + convertedLogs.Datasource = panel.Datasource.LegacyName + } + if len(panel.Links) != 0 { + convertedLogs.Links = converter.convertPanelLinks(panel.Links) + } + + for _, target := range panel.LogsPanel.Targets { + logsTarget := converter.convertLogsTarget(target) + + convertedLogs.Targets = append(convertedLogs.Targets, logsTarget) + } + + return grabana.DashboardPanel{Logs: convertedLogs} +} + +func (converter *JSON) convertLogsVizualization(panel sdk.Panel) *grabana.LogsVisualization { + return &grabana.LogsVisualization{ + Time: panel.LogsPanel.Options.ShowTime, + UniqueLabels: panel.LogsPanel.Options.ShowLabels, + CommonLabels: panel.LogsPanel.Options.ShowCommonLabels, + WrapLines: panel.LogsPanel.Options.WrapLogMessage, + PrettifyJSON: panel.LogsPanel.Options.PrettifyLogMessage, + HideLogDetails: !panel.LogsPanel.Options.EnableLogDetails, + Order: converter.convertLogsSortOrder(panel.LogsPanel.Options.SortOrder), + Deduplication: converter.convertLogsDedupStrategy(panel.LogsPanel.Options.DedupStrategy), + } +} + +func (converter *JSON) convertLogsDedupStrategy(strategy string) string { + switch strategy { + case string(logs.None): + return "none" + case string(logs.Exact): + return "exact" + case string(logs.Numbers): + return "numbers" + case string(logs.Signature): + return "signature" + default: + converter.logger.Warn("unhandled logs dedup strategy: skipped", zap.String("strategy", strategy)) + return "" + } +} + +func (converter *JSON) convertLogsSortOrder(order string) string { + switch order { + case string(logs.Asc): + return "asc" + case string(logs.Desc): + return "desc" + default: + converter.logger.Warn("unhandled sort order: skipped", zap.String("order", order)) + return "" + } +} + +func (converter *JSON) convertLogsTarget(target sdk.Target) grabana.LogsTarget { + return grabana.LogsTarget{ + Loki: &grabana.LokiTarget{ + Query: target.Expr, + Legend: target.LegendFormat, + Ref: target.RefID, + Hidden: target.Hide, + }, + } +} diff --git a/internal/pkg/converter/logs_test.go b/internal/pkg/converter/logs_test.go new file mode 100644 index 00000000..26ee1cfa --- /dev/null +++ b/internal/pkg/converter/logs_test.go @@ -0,0 +1,84 @@ +package converter + +import ( + "testing" + + "github.com/K-Phoen/sdk" + "github.com/stretchr/testify/require" + "go.uber.org/zap" +) + +func TestConvertLogsPanel(t *testing.T) { + req := require.New(t) + + converter := NewJSON(zap.NewNop()) + height := "200px" + datasource := "prometheus" + + logsPanel := sdk.Panel{ + CommonPanel: sdk.CommonPanel{ + Title: "Logs panel", + Description: strPtr("panel desc"), + Type: "logs", + Transparent: true, + Height: &height, + Datasource: &sdk.DatasourceRef{LegacyName: datasource}, + }, + LogsPanel: &sdk.LogsPanel{ + Targets: []sdk.Target{ + { + Expr: "loki_query", + LegendFormat: "Legend", + RefID: "A", + }, + }, + Options: sdk.LogsOptions{ + DedupStrategy: "none", + WrapLogMessage: true, + ShowTime: true, + ShowLabels: true, + ShowCommonLabels: true, + PrettifyLogMessage: true, + SortOrder: "Descending", + EnableLogDetails: true, + }, + }, + } + + converted, ok := converter.convertDataPanel(logsPanel) + + req.True(ok) + req.True(converted.Logs.Transparent) + req.Equal("Logs panel", converted.Logs.Title) + req.Equal("panel desc", converted.Logs.Description) + req.Equal(height, converted.Logs.Height) + req.Equal(datasource, converted.Logs.Datasource) + req.False(converted.Logs.Visualization.HideLogDetails) + req.True(converted.Logs.Visualization.PrettifyJSON) + req.True(converted.Logs.Visualization.UniqueLabels) + req.True(converted.Logs.Visualization.WrapLines) + req.True(converted.Logs.Visualization.Time) + req.True(converted.Logs.Visualization.CommonLabels) + req.Equal("none", converted.Logs.Visualization.Deduplication) + req.Equal("desc", converted.Logs.Visualization.Order) +} + +func TestConvertLogsLinks(t *testing.T) { + req := require.New(t) + + converter := NewJSON(zap.NewNop()) + sdkPanel := sdk.NewLogs("") + sdkPanel.Links = []sdk.Link{ + {Title: "logs title", URL: strPtr("logs url")}, + } + + converted, ok := converter.convertDataPanel(*sdkPanel) + + req.True(ok) + req.NotNil(converted.Logs) + + panel := converted.Logs + req.Len(panel.Links, 1) + req.Equal("logs title", panel.Links[0].Title) + req.Equal("logs url", panel.Links[0].URL) +}