mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 07:39:00 +08:00
fix: include inner panels support and map job,instance correctly (#1718)
* fix: include inner panels support and map job,instance correctly * chore: remove debug and tidy up bit
This commit is contained in:
parent
e558dcae3a
commit
2c7deca2ec
@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -20,6 +21,14 @@ import (
|
|||||||
// This time the global variable is unexported.
|
// This time the global variable is unexported.
|
||||||
var db *sqlx.DB
|
var db *sqlx.DB
|
||||||
|
|
||||||
|
// User for mapping job,instance from grafana
|
||||||
|
var instanceEQRE = regexp.MustCompile("instance(?s)=(?s)\\\"{{.instance}}\\\"")
|
||||||
|
var nodeEQRE = regexp.MustCompile("instance(?s)=(?s)\\\"{{.node}}\\\"")
|
||||||
|
var jobEQRE = regexp.MustCompile("job(?s)=(?s)\\\"{{.job}}\\\"")
|
||||||
|
var instanceRERE = regexp.MustCompile("instance(?s)=~(?s)\\\"{{.instance}}\\\"")
|
||||||
|
var nodeRERE = regexp.MustCompile("instance(?s)=~(?s)\\\"{{.node}}\\\"")
|
||||||
|
var jobRERE = regexp.MustCompile("job(?s)=~(?s)\\\"{{.job}}\\\"")
|
||||||
|
|
||||||
// InitDB sets up setting up the connection pool global variable.
|
// InitDB sets up setting up the connection pool global variable.
|
||||||
func InitDB(dataSourceName string) (*sqlx.DB, error) {
|
func InitDB(dataSourceName string) (*sqlx.DB, error) {
|
||||||
var err error
|
var err error
|
||||||
@ -264,6 +273,78 @@ func SlugifyTitle(title string) string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func widgetFromPanel(panel model.Panels, idx int, variables map[string]model.Variable) *model.Widget {
|
||||||
|
widget := model.Widget{
|
||||||
|
Description: panel.Description,
|
||||||
|
ID: strconv.Itoa(idx),
|
||||||
|
IsStacked: false,
|
||||||
|
NullZeroValues: "zero",
|
||||||
|
Opacity: "1",
|
||||||
|
PanelTypes: "TIME_SERIES", // TODO: Need to figure out how to get this
|
||||||
|
Query: model.Query{
|
||||||
|
ClickHouse: []model.ClickHouseQueryDashboard{
|
||||||
|
{
|
||||||
|
Disabled: false,
|
||||||
|
Legend: "",
|
||||||
|
Name: "A",
|
||||||
|
Query: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MetricsBuilder: model.MetricsBuilder{
|
||||||
|
Formulas: []string{},
|
||||||
|
QueryBuilder: []model.QueryBuilder{
|
||||||
|
{
|
||||||
|
AggregateOperator: 1,
|
||||||
|
Disabled: false,
|
||||||
|
GroupBy: []string{},
|
||||||
|
Legend: "",
|
||||||
|
MetricName: "",
|
||||||
|
Name: "A",
|
||||||
|
ReduceTo: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PromQL: []model.PromQueryDashboard{},
|
||||||
|
QueryType: int(model.PROM),
|
||||||
|
},
|
||||||
|
QueryData: model.QueryDataDashboard{
|
||||||
|
Data: model.Data{
|
||||||
|
QueryData: []interface{}{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Title: panel.Title,
|
||||||
|
YAxisUnit: panel.FieldConfig.Defaults.Unit,
|
||||||
|
QueryType: int(model.PROM), // TODO: Supprot for multiple query types
|
||||||
|
}
|
||||||
|
for _, target := range panel.Targets {
|
||||||
|
if target.Expr != "" {
|
||||||
|
for name := range variables {
|
||||||
|
target.Expr = strings.ReplaceAll(target.Expr, "$"+name, "{{"+"."+name+"}}")
|
||||||
|
target.Expr = strings.ReplaceAll(target.Expr, "$"+"__rate_interval", "5m")
|
||||||
|
}
|
||||||
|
|
||||||
|
// prometheus receiver in collector maps job,instance as service_name,service_instance_id
|
||||||
|
target.Expr = instanceEQRE.ReplaceAllString(target.Expr, "service_instance_id=\"{{.instance}}\"")
|
||||||
|
target.Expr = nodeEQRE.ReplaceAllString(target.Expr, "service_instance_id=\"{{.node}}\"")
|
||||||
|
target.Expr = jobEQRE.ReplaceAllString(target.Expr, "service_name=\"{{.job}}\"")
|
||||||
|
target.Expr = instanceRERE.ReplaceAllString(target.Expr, "service_instance_id=~\"{{.instance}}\"")
|
||||||
|
target.Expr = nodeRERE.ReplaceAllString(target.Expr, "service_instance_id=~\"{{.node}}\"")
|
||||||
|
target.Expr = jobRERE.ReplaceAllString(target.Expr, "service_name=~\"{{.job}}\"")
|
||||||
|
|
||||||
|
widget.Query.PromQL = append(
|
||||||
|
widget.Query.PromQL,
|
||||||
|
model.PromQueryDashboard{
|
||||||
|
Disabled: false,
|
||||||
|
Legend: target.LegendFormat,
|
||||||
|
Name: target.RefID,
|
||||||
|
Query: target.Expr,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &widget
|
||||||
|
}
|
||||||
|
|
||||||
func TransformGrafanaJSONToSignoz(grafanaJSON model.GrafanaJSON) model.DashboardData {
|
func TransformGrafanaJSONToSignoz(grafanaJSON model.GrafanaJSON) model.DashboardData {
|
||||||
var toReturn model.DashboardData
|
var toReturn model.DashboardData
|
||||||
toReturn.Title = grafanaJSON.Title
|
toReturn.Title = grafanaJSON.Title
|
||||||
@ -350,7 +431,31 @@ func TransformGrafanaJSONToSignoz(grafanaJSON model.GrafanaJSON) model.Dashboard
|
|||||||
}
|
}
|
||||||
|
|
||||||
row := 0
|
row := 0
|
||||||
for idx, panel := range grafanaJSON.Panels {
|
idx := 0
|
||||||
|
for _, panel := range grafanaJSON.Panels {
|
||||||
|
if panel.Type == "row" {
|
||||||
|
if panel.Panels != nil && len(panel.Panels) > 0 {
|
||||||
|
for _, innerPanel := range panel.Panels {
|
||||||
|
if idx%3 == 0 {
|
||||||
|
row++
|
||||||
|
}
|
||||||
|
toReturn.Layout = append(
|
||||||
|
toReturn.Layout,
|
||||||
|
model.Layout{
|
||||||
|
X: idx % 3 * 4,
|
||||||
|
Y: row * 3,
|
||||||
|
W: 4,
|
||||||
|
H: 3,
|
||||||
|
I: strconv.Itoa(idx),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
toReturn.Widgets = append(toReturn.Widgets, *widgetFromPanel(innerPanel, idx, toReturn.Variables))
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
if panel.Datasource == nil {
|
if panel.Datasource == nil {
|
||||||
zap.S().Warnf("Skipping panel %d as it has no datasource", idx)
|
zap.S().Warnf("Skipping panel %d as it has no datasource", idx)
|
||||||
continue
|
continue
|
||||||
@ -395,67 +500,8 @@ func TransformGrafanaJSONToSignoz(grafanaJSON model.GrafanaJSON) model.Dashboard
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
widget := model.Widget{
|
toReturn.Widgets = append(toReturn.Widgets, *widgetFromPanel(panel, idx, toReturn.Variables))
|
||||||
Description: panel.Description,
|
idx++
|
||||||
ID: strconv.Itoa(idx),
|
|
||||||
IsStacked: false,
|
|
||||||
NullZeroValues: "zero",
|
|
||||||
Opacity: "1",
|
|
||||||
PanelTypes: "TIME_SERIES", // TODO: Need to figure out how to get this
|
|
||||||
Query: model.Query{
|
|
||||||
ClickHouse: []model.ClickHouseQueryDashboard{
|
|
||||||
{
|
|
||||||
Disabled: false,
|
|
||||||
Legend: "",
|
|
||||||
Name: "A",
|
|
||||||
Query: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MetricsBuilder: model.MetricsBuilder{
|
|
||||||
Formulas: []string{},
|
|
||||||
QueryBuilder: []model.QueryBuilder{
|
|
||||||
{
|
|
||||||
AggregateOperator: 1,
|
|
||||||
Disabled: false,
|
|
||||||
GroupBy: []string{},
|
|
||||||
Legend: "",
|
|
||||||
MetricName: "",
|
|
||||||
Name: "A",
|
|
||||||
ReduceTo: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PromQL: []model.PromQueryDashboard{},
|
|
||||||
QueryType: int(model.PROM),
|
|
||||||
},
|
|
||||||
QueryData: model.QueryDataDashboard{
|
|
||||||
Data: model.Data{
|
|
||||||
QueryData: []interface{}{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Title: panel.Title,
|
|
||||||
YAxisUnit: panel.FieldConfig.Defaults.Unit,
|
|
||||||
QueryType: int(model.PROM), // TODO: Supprot for multiple query types
|
|
||||||
}
|
|
||||||
for _, target := range panel.Targets {
|
|
||||||
if target.Expr != "" {
|
|
||||||
for name := range toReturn.Variables {
|
|
||||||
target.Expr = strings.ReplaceAll(target.Expr, "$"+name, "{{"+"."+name+"}}")
|
|
||||||
target.Expr = strings.ReplaceAll(target.Expr, "$"+"__rate_interval", "5m")
|
|
||||||
}
|
|
||||||
widget.Query.PromQL = append(
|
|
||||||
widget.Query.PromQL,
|
|
||||||
model.PromQueryDashboard{
|
|
||||||
Disabled: false,
|
|
||||||
Legend: target.LegendFormat,
|
|
||||||
Name: target.RefID,
|
|
||||||
Query: target.Expr,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toReturn.Widgets = append(toReturn.Widgets, widget)
|
|
||||||
}
|
}
|
||||||
return toReturn
|
return toReturn
|
||||||
}
|
}
|
||||||
|
@ -5,54 +5,7 @@ type Datasource struct {
|
|||||||
UID string `json:"uid"`
|
UID string `json:"uid"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GrafanaJSON struct {
|
type Panels struct {
|
||||||
Inputs []struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Label string `json:"label"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
PluginID string `json:"pluginId"`
|
|
||||||
PluginName string `json:"pluginName"`
|
|
||||||
} `json:"__inputs"`
|
|
||||||
Requires []struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Version string `json:"version"`
|
|
||||||
} `json:"__requires"`
|
|
||||||
Annotations struct {
|
|
||||||
List []struct {
|
|
||||||
HashKey string `json:"$$hashKey"`
|
|
||||||
BuiltIn int `json:"builtIn"`
|
|
||||||
Datasource interface{} `json:"datasource"`
|
|
||||||
Enable bool `json:"enable"`
|
|
||||||
Hide bool `json:"hide"`
|
|
||||||
IconColor string `json:"iconColor"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Target struct {
|
|
||||||
Limit int `json:"limit"`
|
|
||||||
MatchAny bool `json:"matchAny"`
|
|
||||||
Tags []interface{} `json:"tags"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
} `json:"target"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
} `json:"list"`
|
|
||||||
} `json:"annotations"`
|
|
||||||
Editable bool `json:"editable"`
|
|
||||||
FiscalYearStartMonth int `json:"fiscalYearStartMonth"`
|
|
||||||
GnetID int `json:"gnetId"`
|
|
||||||
GraphTooltip int `json:"graphTooltip"`
|
|
||||||
ID interface{} `json:"id"`
|
|
||||||
Links []struct {
|
|
||||||
Icon string `json:"icon"`
|
|
||||||
Tags []interface{} `json:"tags"`
|
|
||||||
TargetBlank bool `json:"targetBlank"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
URL string `json:"url"`
|
|
||||||
} `json:"links"`
|
|
||||||
LiveNow bool `json:"liveNow"`
|
|
||||||
Panels []struct {
|
|
||||||
Datasource interface{} `json:"datasource"`
|
Datasource interface{} `json:"datasource"`
|
||||||
Description string `json:"description,omitempty"`
|
Description string `json:"description,omitempty"`
|
||||||
FieldConfig struct {
|
FieldConfig struct {
|
||||||
@ -108,8 +61,57 @@ type GrafanaJSON struct {
|
|||||||
HideTimeOverride bool `json:"hideTimeOverride,omitempty"`
|
HideTimeOverride bool `json:"hideTimeOverride,omitempty"`
|
||||||
MaxDataPoints int `json:"maxDataPoints,omitempty"`
|
MaxDataPoints int `json:"maxDataPoints,omitempty"`
|
||||||
Collapsed bool `json:"collapsed,omitempty"`
|
Collapsed bool `json:"collapsed,omitempty"`
|
||||||
Panels []interface{} `json:"panels,omitempty"`
|
Panels []Panels `json:"panels,omitempty"`
|
||||||
} `json:"panels"`
|
}
|
||||||
|
|
||||||
|
type GrafanaJSON struct {
|
||||||
|
Inputs []struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
PluginID string `json:"pluginId"`
|
||||||
|
PluginName string `json:"pluginName"`
|
||||||
|
} `json:"__inputs"`
|
||||||
|
Requires []struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
} `json:"__requires"`
|
||||||
|
Annotations struct {
|
||||||
|
List []struct {
|
||||||
|
HashKey string `json:"$$hashKey"`
|
||||||
|
BuiltIn int `json:"builtIn"`
|
||||||
|
Datasource interface{} `json:"datasource"`
|
||||||
|
Enable bool `json:"enable"`
|
||||||
|
Hide bool `json:"hide"`
|
||||||
|
IconColor string `json:"iconColor"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Target struct {
|
||||||
|
Limit int `json:"limit"`
|
||||||
|
MatchAny bool `json:"matchAny"`
|
||||||
|
Tags []interface{} `json:"tags"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
} `json:"target"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
} `json:"list"`
|
||||||
|
} `json:"annotations"`
|
||||||
|
Editable bool `json:"editable"`
|
||||||
|
FiscalYearStartMonth int `json:"fiscalYearStartMonth"`
|
||||||
|
GnetID int `json:"gnetId"`
|
||||||
|
GraphTooltip int `json:"graphTooltip"`
|
||||||
|
ID interface{} `json:"id"`
|
||||||
|
Links []struct {
|
||||||
|
Icon string `json:"icon"`
|
||||||
|
Tags []interface{} `json:"tags"`
|
||||||
|
TargetBlank bool `json:"targetBlank"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
} `json:"links"`
|
||||||
|
LiveNow bool `json:"liveNow"`
|
||||||
|
Panels []Panels `json:"panels"`
|
||||||
SchemaVersion int `json:"schemaVersion"`
|
SchemaVersion int `json:"schemaVersion"`
|
||||||
Style string `json:"style"`
|
Style string `json:"style"`
|
||||||
Tags []string `json:"tags"`
|
Tags []string `json:"tags"`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user