forked from moira-alert/moira
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathplot.go
123 lines (98 loc) · 3.03 KB
/
plot.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package plotting
import (
"fmt"
"time"
"github.com/go-graphite/carbonapi/expr/types"
"github.com/wcharczuk/go-chart"
"github.com/moira-alert/moira"
)
// ErrNoPointsToRender is used to prevent unnecessary render calls
type ErrNoPointsToRender struct {
triggerName string
}
// ErrNoPointsToRender implementation with detailed error message
func (err ErrNoPointsToRender) Error() string {
return fmt.Sprintf("no points found to render %s", err.triggerName)
}
// Plot represents plot structure to render
type Plot struct {
theme moira.PlotTheme
location *time.Location
width int
height int
}
// GetPlotTemplate returns plot template
func GetPlotTemplate(theme string, location *time.Location) (*Plot, error) {
plotTheme, err := getPlotTheme(theme)
if err != nil {
return nil, err
}
if location == nil {
return nil, fmt.Errorf("location not specified")
}
return &Plot{
theme: plotTheme,
location: location,
width: 800,
height: 400,
}, nil
}
// GetRenderable returns go-chart to render
func (plot *Plot) GetRenderable(trigger *moira.Trigger, metricsData []*types.MetricData, metricsWhitelist []string) (chart.Chart, error) {
plotSeries := make([]chart.Series, 0)
metricsData = toLimitedMetricsData(metricsData, metricsWhitelist)
limits := resolveLimits(metricsData)
curveSeriesList := getCurveSeriesList(metricsData, plot.theme)
for _, curveSeries := range curveSeriesList {
plotSeries = append(plotSeries, curveSeries)
}
thresholdSeriesList := getThresholdSeriesList(trigger, plot.theme, limits)
plotSeries = append(plotSeries, thresholdSeriesList...)
gridStyle := plot.theme.GetGridStyle()
yAxisValuesFormatter, maxMarkLen := getYAxisValuesFormatter(limits)
yAxisRange := limits.getThresholdAxisRange(trigger.TriggerType)
renderable := chart.Chart{
Title: sanitizeLabelName(trigger.Name, 40),
TitleStyle: plot.theme.GetTitleStyle(),
Width: plot.width,
Height: plot.height,
Canvas: plot.theme.GetCanvasStyle(),
Background: plot.theme.GetBackgroundStyle(maxMarkLen),
XAxis: chart.XAxis{
Style: plot.theme.GetXAxisStyle(),
GridMinorStyle: gridStyle,
GridMajorStyle: gridStyle,
ValueFormatter: getTimeValueFormatter(plot.location, "15:04"),
Range: &chart.ContinuousRange{
Min: float64(limits.from.UnixNano()),
Max: float64(limits.to.UnixNano()),
},
},
YAxis: chart.YAxis{
Style: chart.Style{
Show: false,
},
GridMinorStyle: gridStyle,
GridMajorStyle: gridStyle,
Range: &yAxisRange,
},
YAxisSecondary: chart.YAxis{
ValueFormatter: yAxisValuesFormatter,
Style: plot.theme.GetYAxisStyle(),
GridMinorStyle: gridStyle,
GridMajorStyle: gridStyle,
Range: &chart.ContinuousRange{
Max: limits.highest,
Min: limits.lowest,
},
},
Series: plotSeries,
}
renderable.Elements = []chart.Renderable{
getPlotLegend(&renderable, plot.theme.GetLegendStyle(), plot.width),
}
if len(renderable.Series) == 0 {
return renderable, ErrNoPointsToRender{triggerName: trigger.Name}
}
return renderable, nil
}