From 77400148b196dc0d7f9d22780c426ae652c2cad9 Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Thu, 7 Mar 2024 15:23:06 +0800 Subject: [PATCH] *: fix duplicate panel ids in tidb.json & add a duplicate id checker (#51568) (#51580) close pingcap/tidb#51556 --- Makefile | 6 +++ pkg/metrics/grafana/tidb.json | 10 ++-- tools/dashboard-linter/BUILD.bazel | 14 +++++ tools/dashboard-linter/main.go | 85 ++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 tools/dashboard-linter/BUILD.bazel create mode 100644 tools/dashboard-linter/main.go diff --git a/Makefile b/Makefile index 286a50aba08c4..7e954a1973a66 100644 --- a/Makefile +++ b/Makefile @@ -65,6 +65,12 @@ lint:tools/bin/revive @echo "linting" @tools/bin/revive -formatter friendly -config tools/check/revive.toml $(FILES_TIDB_TESTS) @tools/bin/revive -formatter friendly -config tools/check/revive.toml ./br/pkg/lightning/... + go run tools/dashboard-linter/main.go pkg/metrics/grafana/overview.json + go run tools/dashboard-linter/main.go pkg/metrics/grafana/performance_overview.json + go run tools/dashboard-linter/main.go pkg/metrics/grafana/tidb.json + go run tools/dashboard-linter/main.go pkg/metrics/grafana/tidb_resource_control.json + go run tools/dashboard-linter/main.go pkg/metrics/grafana/tidb_runtime.json + go run tools/dashboard-linter/main.go pkg/metrics/grafana/tidb_summary.json license: bazel $(BAZEL_GLOBAL_CONFIG) run $(BAZEL_CMD_CONFIG) \ diff --git a/pkg/metrics/grafana/tidb.json b/pkg/metrics/grafana/tidb.json index 372e4a23d7777..644510fbdf09e 100644 --- a/pkg/metrics/grafana/tidb.json +++ b/pkg/metrics/grafana/tidb.json @@ -17039,7 +17039,7 @@ "heatmap": {}, "hideZeroBuckets": false, "highlightCards": true, - "id": 308, + "id": 321, "legend": { "show": false }, @@ -20431,7 +20431,7 @@ "x": 0, "y": 20 }, - "id": 309, + "id": 323, "panels": [ { "aliasColors": {}, @@ -20553,7 +20553,7 @@ "y": 105 }, "hiddenSeries": false, - "id": 311, + "id": 324, "legend": { "alignAsTable": false, "avg": false, @@ -20653,7 +20653,7 @@ "y": 113 }, "hiddenSeries": false, - "id": 312, + "id": 325, "legend": { "alignAsTable": false, "avg": false, @@ -20773,7 +20773,7 @@ "x": 0, "y": 21 }, - "id": 315, + "id": 327, "panels": [ { "aliasColors": {}, diff --git a/tools/dashboard-linter/BUILD.bazel b/tools/dashboard-linter/BUILD.bazel new file mode 100644 index 0000000000000..d6d9181cf19a1 --- /dev/null +++ b/tools/dashboard-linter/BUILD.bazel @@ -0,0 +1,14 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") + +go_library( + name = "dashboard-linter_lib", + srcs = ["main.go"], + importpath = "github.com/pingcap/tidb/tools/dashboard-linter", + visibility = ["//visibility:private"], +) + +go_binary( + name = "dashboard-linter", + embed = [":dashboard-linter_lib"], + visibility = ["//visibility:public"], +) diff --git a/tools/dashboard-linter/main.go b/tools/dashboard-linter/main.go new file mode 100644 index 0000000000000..242bf8ec07610 --- /dev/null +++ b/tools/dashboard-linter/main.go @@ -0,0 +1,85 @@ +// Copyright 2024 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "encoding/json" + "fmt" + "os" + "slices" +) + +type basicDashboard struct { + Panels []panel `json:"panels"` +} + +type panel struct { + ID int `json:"id"` + Panels []panel `json:"panels"` +} + +// a small linter to check if there are duplicate panel IDs in a dashboard json file. +// grafana do have one linter https://github.com/grafana/dashboard-linter, but seems +// it does not have rules to check duplicate panel IDs. +func main() { + if len(os.Args) < 2 { + fmt.Println("Usage: dashboard-linter ") + os.Exit(1) + } + fileName := os.Args[1] + content, err := os.ReadFile(fileName) + if err != nil { + panic(err) + } + board := basicDashboard{} + if err = json.Unmarshal(content, &board); err != nil { + panic(err) + } + allIDs := make(map[int]int, 1024) + for _, p := range board.Panels { + allIDs[p.ID]++ + // panel can be nested once(as a row panel) + for _, sub := range p.Panels { + allIDs[sub.ID]++ + } + } + duplicateIDs := make(map[int]int, 8) + usedIDs := make([]int, 0, len(allIDs)) + for id, count := range allIDs { + if count > 1 { + duplicateIDs[id] = count + } + usedIDs = append(usedIDs, id) + } + slices.Sort(usedIDs) + availableRange := make([]string, 0, 100) + if len(usedIDs) > 0 { + nextID := usedIDs[0] + 1 + for i := 1; i < len(usedIDs); i++ { + if usedIDs[i]-nextID > 1 { + availableRange = append(availableRange, fmt.Sprintf("[%d, %d)", nextID, usedIDs[i])) + } else if usedIDs[i]-nextID == 1 { + availableRange = append(availableRange, fmt.Sprintf("%d", nextID)) + } + nextID = usedIDs[i] + 1 + } + availableRange = append(availableRange, fmt.Sprintf("[%d, ∞)", nextID)) + } + if len(duplicateIDs) > 0 { + fmt.Printf("Duplicate panel IDs found(id:count map) in file %s: %v\navailable panel ID range: %v\n", + fileName, duplicateIDs, availableRange) + os.Exit(1) + } +}