Skip to content

Commit

Permalink
feat(observability-lib): builder to create independently grafana reso…
Browse files Browse the repository at this point in the history
…urces
  • Loading branch information
Atrax1 committed Nov 4, 2024
1 parent eed4b09 commit 12a6266
Show file tree
Hide file tree
Showing 17 changed files with 219 additions and 119 deletions.
2 changes: 1 addition & 1 deletion observability-lib/cmd/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ type BuildOptions struct {
AlertsFilters string
}

func BuildDashboardWithType(options *BuildOptions) (*grafana.Dashboard, error) {
func BuildDashboardWithType(options *BuildOptions) (*grafana.Observability, error) {
switch options.TypeDashboard {
case TypeDashboardCoreNode:
return corenode.NewDashboard(&corenode.Props{
Expand Down
2 changes: 1 addition & 1 deletion observability-lib/dashboards/atlas-don/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/smartcontractkit/chainlink-common/observability-lib/grafana"
)

func NewDashboard(props *Props) (*grafana.Dashboard, error) {
func NewDashboard(props *Props) (*grafana.Observability, error) {
if props.Name == "" {
return nil, fmt.Errorf("Name is required")
}
Expand Down
2 changes: 1 addition & 1 deletion observability-lib/dashboards/atlas-don/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func TestNewDashboard(t *testing.T) {
if err != nil {
t.Errorf("Error creating dashboard: %v", err)
}
require.IsType(t, grafana.Dashboard{}, *testDashboard)
require.IsType(t, grafana.Observability{}, *testDashboard)
require.Equal(t, "DON OCR Dashboard", *testDashboard.Dashboard.Title)
json, errJSON := testDashboard.GenerateJSON()
if errJSON != nil {
Expand Down
2 changes: 1 addition & 1 deletion observability-lib/dashboards/capabilities/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Props struct {
}

// NewDashboard creates a Capabilities dashboard
func NewDashboard(props *Props) (*grafana.Dashboard, error) {
func NewDashboard(props *Props) (*grafana.Observability, error) {
if props.Name == "" {
return nil, fmt.Errorf("Name is required")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func TestNewDashboard(t *testing.T) {
if err != nil {
t.Errorf("Error creating dashboard: %v", err)
}
require.IsType(t, grafana.Dashboard{}, *testDashboard)
require.IsType(t, grafana.Observability{}, *testDashboard)
require.Equal(t, "Capabilities Dashboard", *testDashboard.Dashboard.Title)
json, errJSON := testDashboard.GenerateJSON()
if errJSON != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/smartcontractkit/chainlink-common/observability-lib/grafana"
)

func NewDashboard(props *Props) (*grafana.Dashboard, error) {
func NewDashboard(props *Props) (*grafana.Observability, error) {
if props.Name == "" {
return nil, fmt.Errorf("Name is required")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func TestNewDashboard(t *testing.T) {
if err != nil {
t.Errorf("Error creating dashboard: %v", err)
}
require.IsType(t, grafana.Dashboard{}, *testDashboard)
require.IsType(t, grafana.Observability{}, *testDashboard)
require.Equal(t, "Core Node Components Dashboard", *testDashboard.Dashboard.Title)
json, errJSON := testDashboard.GenerateJSON()
if errJSON != nil {
Expand Down
2 changes: 1 addition & 1 deletion observability-lib/dashboards/core-node/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
)

// NewDashboard creates a DON dashboard for the given OCR version
func NewDashboard(props *Props) (*grafana.Dashboard, error) {
func NewDashboard(props *Props) (*grafana.Observability, error) {
if props.Name == "" {
return nil, fmt.Errorf("Name is required")
}
Expand Down
2 changes: 1 addition & 1 deletion observability-lib/dashboards/core-node/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func TestNewDashboard(t *testing.T) {
if err != nil {
t.Errorf("Error creating dashboard: %v", err)
}
require.IsType(t, grafana.Dashboard{}, *testDashboard)
require.IsType(t, grafana.Observability{}, *testDashboard)
require.Equal(t, "Core Node Dashboard", *testDashboard.Dashboard.Title)
json, errJSON := testDashboard.GenerateJSON()
if errJSON != nil {
Expand Down
2 changes: 1 addition & 1 deletion observability-lib/dashboards/k8s-resources/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Props struct {
MetricsDataSource *grafana.DataSource // MetricsDataSource is the datasource for querying metrics
}

func NewDashboard(props *Props) (*grafana.Dashboard, error) {
func NewDashboard(props *Props) (*grafana.Observability, error) {
if props.Name == "" {
return nil, fmt.Errorf("Name is required")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func TestNewDashboard(t *testing.T) {
if err != nil {
t.Errorf("Error creating dashboard: %v", err)
}
require.IsType(t, grafana.Dashboard{}, *testDashboard)
require.IsType(t, grafana.Observability{}, *testDashboard)
require.Equal(t, "K8s resources", *testDashboard.Dashboard.Title)
json, errJSON := testDashboard.GenerateJSON()
if errJSON != nil {
Expand Down
2 changes: 1 addition & 1 deletion observability-lib/dashboards/nop-ocr/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type Props struct {
OCRVersion string // OCRVersion is the version of the OCR (ocr, ocr2, ocr3)
}

func NewDashboard(props *Props) (*grafana.Dashboard, error) {
func NewDashboard(props *Props) (*grafana.Observability, error) {
if props.Name == "" {
return nil, fmt.Errorf("Name is required")
}
Expand Down
2 changes: 1 addition & 1 deletion observability-lib/dashboards/nop-ocr/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func TestNewDashboard(t *testing.T) {
if err != nil {
t.Errorf("Error creating dashboard: %v", err)
}
require.IsType(t, grafana.Dashboard{}, *testDashboard)
require.IsType(t, grafana.Observability{}, *testDashboard)
require.Equal(t, "NOP OCR Dashboard", *testDashboard.Dashboard.Title)
json, errJSON := testDashboard.GenerateJSON()
if errJSON != nil {
Expand Down
82 changes: 46 additions & 36 deletions observability-lib/grafana/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,23 @@ type BuilderOptions struct {
}

func NewBuilder(options *BuilderOptions) *Builder {
if options.TimeZone == "" {
options.TimeZone = common.TimeZoneBrowser
}
builder := &Builder{}

builder := &Builder{
dashboardBuilder: dashboard.NewDashboardBuilder(options.Name).
Tags(options.Tags).
Refresh(options.Refresh).
Time(options.TimeFrom, options.TimeTo).
Timezone(options.TimeZone),
if options.Name != "" {
builder.dashboardBuilder = dashboard.NewDashboardBuilder(options.Name)
if options.Tags != nil {
builder.dashboardBuilder.Tags(options.Tags)
}
if options.Refresh != "" {
builder.dashboardBuilder.Refresh(options.Refresh)
}
if options.TimeFrom != "" && options.TimeTo != "" {
builder.dashboardBuilder.Time(options.TimeFrom, options.TimeTo)
}
if options.TimeZone == "" {
options.TimeZone = common.TimeZoneBrowser
}
builder.dashboardBuilder.Timezone(options.TimeZone)
}

if options.AlertsTags != nil {
Expand Down Expand Up @@ -104,33 +111,39 @@ func (b *Builder) AddNotificationPolicy(notificationPolicies ...*alerting.Notifi
b.notificationPoliciesBuilder = append(b.notificationPoliciesBuilder, notificationPolicies...)
}

func (b *Builder) Build() (*Dashboard, error) {
db, errBuildDashboard := b.dashboardBuilder.Build()
if errBuildDashboard != nil {
return nil, errBuildDashboard
}
func (b *Builder) Build() (*Observability, error) {
observability := Observability{}

var alerts []alerting.Rule
for _, alertBuilder := range b.alertsBuilder {
alert, errBuildAlert := alertBuilder.Build()
if errBuildAlert != nil {
return nil, errBuildAlert
if b.dashboardBuilder != nil {
db, errBuildDashboard := b.dashboardBuilder.Build()
if errBuildDashboard != nil {
return nil, errBuildDashboard
}
observability.Dashboard = &db

// Add common tags to alerts
if b.alertsTags != nil && len(b.alertsTags) > 0 {
tags := maps.Clone(b.alertsTags)
maps.Copy(tags, alert.Labels)
var alerts []alerting.Rule
for _, alertBuilder := range b.alertsBuilder {
alert, errBuildAlert := alertBuilder.Build()
if errBuildAlert != nil {
return nil, errBuildAlert
}

alertBuildWithTags := alertBuilder.Labels(tags)
alertWithTags, errBuildAlertWithTags := alertBuildWithTags.Build()
if errBuildAlertWithTags != nil {
return nil, errBuildAlertWithTags
// Add common tags to alerts
if b.alertsTags != nil && len(b.alertsTags) > 0 {
tags := maps.Clone(b.alertsTags)
maps.Copy(tags, alert.Labels)

alertBuildWithTags := alertBuilder.Labels(tags)
alertWithTags, errBuildAlertWithTags := alertBuildWithTags.Build()
if errBuildAlertWithTags != nil {
return nil, errBuildAlertWithTags
}
alerts = append(alerts, alertWithTags)
} else {
alerts = append(alerts, alert)
}
alerts = append(alerts, alertWithTags)
} else {
alerts = append(alerts, alert)
}
observability.Alerts = alerts
}

var contactPoints []alerting.ContactPoint
Expand All @@ -141,6 +154,7 @@ func (b *Builder) Build() (*Dashboard, error) {
}
contactPoints = append(contactPoints, contactPoint)
}
observability.ContactPoints = contactPoints

var notificationPolicies []alerting.NotificationPolicy
for _, notificationPolicyBuilder := range b.notificationPoliciesBuilder {
Expand All @@ -150,11 +164,7 @@ func (b *Builder) Build() (*Dashboard, error) {
}
notificationPolicies = append(notificationPolicies, notificationPolicy)
}
observability.NotificationPolicies = notificationPolicies

return &Dashboard{
Dashboard: &db,
Alerts: alerts,
ContactPoints: contactPoints,
NotificationPolicies: notificationPolicies,
}, nil
return &observability, nil
}
97 changes: 85 additions & 12 deletions observability-lib/grafana/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package grafana_test
import (
"testing"

"github.com/grafana/grafana-foundation-sdk/go/alerting"
"github.com/stretchr/testify/require"

"github.com/grafana/grafana-foundation-sdk/go/dashboard"
Expand All @@ -21,18 +22,86 @@ func TestNewBuilder(t *testing.T) {
TimeZone: "UTC",
})

db, err := builder.Build()
o, err := builder.Build()
if err != nil {
t.Errorf("Error building dashboard: %v", err)
t.Errorf("Error during build: %v", err)
}

require.NotEmpty(t, o.Dashboard)
require.Empty(t, o.Alerts)
require.Empty(t, o.ContactPoints)
require.Empty(t, o.NotificationPolicies)
})

t.Run("NewBuilder builds a dashboard with alerts", func(t *testing.T) {
builder := grafana.NewBuilder(&grafana.BuilderOptions{
Name: "Dashboard Name",
Tags: []string{"foo", "bar"},
Refresh: "1m",
TimeFrom: "now-1h",
TimeTo: "now",
TimeZone: "UTC",
})
builder.AddAlert(grafana.NewAlertRule(&grafana.AlertOptions{
Title: "Alert Title",
}))

o, err := builder.Build()
if err != nil {
t.Errorf("Error during build: %v", err)
}

require.IsType(t, dashboard.Dashboard{}, *db.Dashboard)
require.NotEmpty(t, o.Dashboard)
require.NotEmpty(t, o.Alerts)
require.Empty(t, o.ContactPoints)
require.Empty(t, o.NotificationPolicies)
})

t.Run("NewBuilder builds a contact point", func(t *testing.T) {
builder := grafana.NewBuilder(&grafana.BuilderOptions{})
builder.AddContactPoint(grafana.NewContactPoint(&grafana.ContactPointOptions{
Name: "slack",
Type: "slack",
}))

o, err := builder.Build()
if err != nil {
t.Errorf("Error during build: %v", err)
}

require.Empty(t, o.Dashboard)
require.Empty(t, o.Alerts)
require.NotEmpty(t, o.ContactPoints)
require.Empty(t, o.NotificationPolicies)
})

t.Run("NewBuilder builds a notification policy", func(t *testing.T) {
builder := grafana.NewBuilder(&grafana.BuilderOptions{})
builder.AddNotificationPolicy(grafana.NewNotificationPolicy(&grafana.NotificationPolicyOptions{
Receiver: "slack",
GroupBy: []string{"grafana_folder", "alertname"},
ObjectMatchers: []alerting.ObjectMatcher{
{"team", "=", "chainlink"},
},
}))

o, err := builder.Build()
if err != nil {
t.Errorf("Error during build: %v", err)
}

require.Empty(t, o.Dashboard)
require.Empty(t, o.Alerts)
require.Empty(t, o.ContactPoints)
require.NotEmpty(t, o.NotificationPolicies)
})
}

func TestBuilder_AddVars(t *testing.T) {
t.Run("AddVars adds variables to the dashboard", func(t *testing.T) {
builder := grafana.NewBuilder(&grafana.BuilderOptions{})
builder := grafana.NewBuilder(&grafana.BuilderOptions{
Name: "Dashboard Name",
})

variable := grafana.NewQueryVariable(&grafana.QueryVariableOptions{
VariableOption: &grafana.VariableOption{
Expand All @@ -44,30 +113,34 @@ func TestBuilder_AddVars(t *testing.T) {
})

builder.AddVars(variable)
db, err := builder.Build()
o, err := builder.Build()
if err != nil {
t.Errorf("Error building dashboard: %v", err)
}
require.IsType(t, dashboard.Dashboard{}, *db.Dashboard)
require.Len(t, o.Dashboard.Templating.List, 1)
})
}

func TestBuilder_AddRow(t *testing.T) {
t.Run("AddRow adds a row to the dashboard", func(t *testing.T) {
builder := grafana.NewBuilder(&grafana.BuilderOptions{})
builder := grafana.NewBuilder(&grafana.BuilderOptions{
Name: "Dashboard Name",
})

builder.AddRow("Row Title")
db, err := builder.Build()
o, err := builder.Build()
if err != nil {
t.Errorf("Error building dashboard: %v", err)
}
require.IsType(t, dashboard.Dashboard{}, *db.Dashboard)
require.IsType(t, dashboard.RowPanel{}, *o.Dashboard.Panels[0].RowPanel)
})
}

func TestBuilder_AddPanel(t *testing.T) {
t.Run("AddPanel adds a panel to the dashboard", func(t *testing.T) {
builder := grafana.NewBuilder(&grafana.BuilderOptions{})
builder := grafana.NewBuilder(&grafana.BuilderOptions{
Name: "Dashboard Name",
})

panel := grafana.NewStatPanel(&grafana.StatPanelOptions{
PanelOptions: &grafana.PanelOptions{
Expand All @@ -76,10 +149,10 @@ func TestBuilder_AddPanel(t *testing.T) {
})

builder.AddPanel(panel)
db, err := builder.Build()
o, err := builder.Build()
if err != nil {
t.Errorf("Error building dashboard: %v", err)
}
require.IsType(t, dashboard.Dashboard{}, *db.Dashboard)
require.IsType(t, dashboard.Panel{}, *o.Dashboard.Panels[0].Panel)
})
}
Loading

0 comments on commit 12a6266

Please sign in to comment.