144 lines
4.7 KiB
Go
Executable file
144 lines
4.7 KiB
Go
Executable file
package main
|
||
|
||
import "log"
|
||
|
||
// validateAndFixTemplate проверяет критичные настройки шаблона и исправляет их если нужно.
|
||
// Вызывается после loadTemplate чтобы гарантировать корректность шаблона независимо от его источника.
|
||
func validateAndFixTemplate(t *DashboardTemplate) {
|
||
fixed := 0
|
||
|
||
// --- vl_interval для панелей с агрегацией ---
|
||
vlIntervalPanels := []string{"rps", "rps_multi", "status_codes", "response_time", "traffic_combined", "traffic_combined_total"}
|
||
for _, key := range vlIntervalPanels {
|
||
p, ok := t.Panels[key]
|
||
if !ok {
|
||
continue
|
||
}
|
||
pm, ok := p.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
if v, _ := pm["vl_interval"].(string); v == "" {
|
||
pm["vl_interval"] = "1m"
|
||
log.Printf("[template-validator] Fixed: panels.%s.vl_interval = \"1m\"", key)
|
||
fixed++
|
||
}
|
||
}
|
||
|
||
// --- spanNulls для status_codes ---
|
||
if p, ok := t.Panels["status_codes"]; ok {
|
||
if pm, ok := p.(map[string]interface{}); ok {
|
||
if fc, ok := pm["fieldConfig"].(map[string]interface{}); ok {
|
||
if defaults, ok := fc["defaults"].(map[string]interface{}); ok {
|
||
if custom, ok := defaults["custom"].(map[string]interface{}); ok {
|
||
if v, _ := custom["spanNulls"].(bool); !v {
|
||
custom["spanNulls"] = true
|
||
log.Printf("[template-validator] Fixed: panels.status_codes.fieldConfig.defaults.custom.spanNulls = true")
|
||
fixed++
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// --- vl_base_query для overview_tenant_per_nodes ---
|
||
checkOverviewVLQuery(t, "overview_tenant_per_nodes",
|
||
"log_type:access TENANT:in(${tenant:csv})",
|
||
"log_type:access AND TENANT:${tenant:lucene}",
|
||
&fixed,
|
||
)
|
||
|
||
// --- vl_base_query для overview_tenant_per_node ---
|
||
checkOverviewVLQuery(t, "overview_tenant_per_node",
|
||
"log_type:access node_name:in(${node_name:csv})",
|
||
"log_type:access AND node_name:${node_name:lucene}",
|
||
&fixed,
|
||
)
|
||
|
||
// --- layout: три столбца ---
|
||
checkLayout(t, &fixed)
|
||
|
||
if fixed > 0 {
|
||
log.Printf("[template-validator] Total fixes applied: %d", fixed)
|
||
} else {
|
||
log.Printf("[template-validator] Template OK, no fixes needed")
|
||
}
|
||
}
|
||
|
||
func checkOverviewVLQuery(t *DashboardTemplate, panelKey, expectedVL, expectedOS string, fixed *int) {
|
||
p, ok := t.Panels[panelKey]
|
||
if !ok {
|
||
return
|
||
}
|
||
pm, ok := p.(map[string]interface{})
|
||
if !ok {
|
||
return
|
||
}
|
||
qc, ok := pm["query_config"].(map[string]interface{})
|
||
if !ok {
|
||
return
|
||
}
|
||
if v, _ := qc["vl_base_query"].(string); v == "" {
|
||
qc["vl_base_query"] = expectedVL
|
||
log.Printf("[template-validator] Fixed: panels.%s.query_config.vl_base_query", panelKey)
|
||
(*fixed)++
|
||
}
|
||
if v, _ := qc["base_query"].(string); v == "log_type:access" {
|
||
qc["base_query"] = expectedOS
|
||
log.Printf("[template-validator] Fixed: panels.%s.query_config.base_query", panelKey)
|
||
(*fixed)++
|
||
}
|
||
}
|
||
|
||
func checkLayout(t *DashboardTemplate, fixed *int) {
|
||
// Проверяем что tenant_panels имеет три столбца по 8
|
||
tenantPanels := t.Layout.TenantPanels
|
||
hasTraffic := false
|
||
wrongWidth := false
|
||
for _, p := range tenantPanels {
|
||
if p.PanelKey == "traffic_combined_total" {
|
||
hasTraffic = true
|
||
}
|
||
if p.Width == 12 {
|
||
wrongWidth = true
|
||
}
|
||
}
|
||
|
||
if !hasTraffic || wrongWidth {
|
||
log.Printf("[template-validator] Fixed: layout.tenant_panels restored to 3-column (8+8+8)")
|
||
t.Layout.TenantPanels = []PanelLayout{
|
||
{PanelKey: "status_codes", TitleFormat: "Status Codes {client}", Width: 8, XOffset: 0},
|
||
{PanelKey: "rps", TitleFormat: "RPS {client}", Width: 8, XOffset: 8,
|
||
Condition: &PanelCondition{Type: "max_domains", Value: 1}},
|
||
{PanelKey: "rps_multi", TitleFormat: "RPS {client}", Width: 8, XOffset: 8,
|
||
Condition: &PanelCondition{Type: "min_domains", Value: 2}},
|
||
{PanelKey: "traffic_combined_total", TitleFormat: "Total Traffic {client}", Width: 8, XOffset: 16,
|
||
Condition: &PanelCondition{Type: "min_domains", Value: 1}},
|
||
}
|
||
(*fixed)++
|
||
}
|
||
|
||
// Проверяем domain_panels
|
||
domainPanels := t.Layout.DomainPanels
|
||
hasDomainTraffic := false
|
||
domainWrongWidth := false
|
||
for _, p := range domainPanels {
|
||
if p.PanelKey == "traffic_combined" {
|
||
hasDomainTraffic = true
|
||
}
|
||
if p.Width == 12 {
|
||
domainWrongWidth = true
|
||
}
|
||
}
|
||
|
||
if !hasDomainTraffic || domainWrongWidth {
|
||
log.Printf("[template-validator] Fixed: layout.domain_panels restored to 3-column (8+8+8)")
|
||
t.Layout.DomainPanels = []PanelLayout{
|
||
{PanelKey: "status_codes", TitleSuffix: "{sid} Status Codes", Width: 8, XOffset: 0},
|
||
{PanelKey: "response_time", TitleSuffix: "{sid} Response Time", Width: 8, XOffset: 8},
|
||
{PanelKey: "traffic_combined", TitleFormat: "{domain} {sid} Traffic", Width: 8, XOffset: 16},
|
||
}
|
||
(*fixed)++
|
||
}
|
||
}
|