mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-12 06:24:10 +01:00
feat: make widget graph configureable
This commit is contained in:
committed by
Vincent Bernat
parent
d152dab89e
commit
6cbdfafd67
@@ -26,6 +26,8 @@ type Configuration struct {
|
||||
DimensionsLimit int `validate:"min=10"`
|
||||
// CacheTTL tells how long to keep the most costly requests in cache.
|
||||
CacheTTL time.Duration `validate:"min=5s"`
|
||||
// HomepageGraphFilter defines the filtering string to use for the homepage graph
|
||||
HomepageGraphFilter string
|
||||
}
|
||||
|
||||
// VisualizeOptionsConfiguration defines options for the "visualize" tab.
|
||||
@@ -55,9 +57,10 @@ func DefaultConfiguration() Configuration {
|
||||
Dimensions: []query.Column{query.NewColumn("SrcAS")},
|
||||
Limit: 10,
|
||||
},
|
||||
HomepageTopWidgets: []string{"src-as", "src-port", "protocol", "src-country", "etype"},
|
||||
DimensionsLimit: 50,
|
||||
CacheTTL: 30 * time.Minute,
|
||||
HomepageTopWidgets: []string{"src-as", "src-port", "protocol", "src-country", "etype"},
|
||||
DimensionsLimit: 50,
|
||||
CacheTTL: 30 * time.Minute,
|
||||
HomepageGraphFilter: "InIfBoundary = 'external'",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -772,6 +772,10 @@ The console itself accepts the following keys:
|
||||
- `homepage-top-widgets` to define the widgets to display on the home page
|
||||
- `dimensions-limit` to set the upper limit of the number of returned dimensions
|
||||
- `cache-ttl` sets the time costly requests are kept in cache
|
||||
- `homepage-graph-filter` sets the filter for the graph on the
|
||||
homepage (default: `InIfBoundary = 'external'`).
|
||||
This is a SQL expression, passed into the clickhouse query directly.
|
||||
It can also be empty, in which case the sum of all flows captured will be displayed.
|
||||
|
||||
Here is an example:
|
||||
|
||||
|
||||
@@ -213,6 +213,11 @@ LIMIT 5
|
||||
}
|
||||
|
||||
func (c *Component) widgetGraphHandlerFunc(gc *gin.Context) {
|
||||
// first step: define which filter to use
|
||||
filter := c.config.HomepageGraphFilter
|
||||
if filter != "" {
|
||||
filter = fmt.Sprintf("AND %s", filter)
|
||||
}
|
||||
ctx := c.t.Context(gc.Request.Context())
|
||||
now := c.d.Clock.Now()
|
||||
query := c.finalizeQuery(fmt.Sprintf(`
|
||||
@@ -222,7 +227,7 @@ SELECT
|
||||
SUM(Bytes*SamplingRate*8/{{ .Interval }})/1000/1000/1000 AS Gbps
|
||||
FROM {{ .Table }}
|
||||
WHERE {{ .Timefilter }}
|
||||
AND InIfBoundary = 'external'
|
||||
%s
|
||||
GROUP BY Time
|
||||
ORDER BY Time WITH FILL
|
||||
FROM {{ .TimefilterStart }}
|
||||
@@ -234,7 +239,8 @@ ORDER BY Time WITH FILL
|
||||
End: now,
|
||||
MainTableRequired: false,
|
||||
Points: 200,
|
||||
})))
|
||||
}),
|
||||
filter))
|
||||
gc.Header("X-SQL-Query", query)
|
||||
|
||||
results := []struct {
|
||||
|
||||
@@ -230,23 +230,13 @@ func TestWidgetTop(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWidgetGraph(t *testing.T) {
|
||||
_, h, mockConn, mockClock := NewMock(t, DefaultConfiguration())
|
||||
|
||||
base := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
|
||||
mockClock.Set(base.Add(24 * time.Hour))
|
||||
expected := []struct {
|
||||
Time time.Time `json:"t"`
|
||||
Gbps float64 `json:"gbps"`
|
||||
testcases := []struct {
|
||||
config Configuration
|
||||
query string
|
||||
}{
|
||||
{base, 25.3},
|
||||
{base.Add(time.Minute), 27.8},
|
||||
{base.Add(2 * time.Minute), 26.4},
|
||||
{base.Add(3 * time.Minute), 29.2},
|
||||
{base.Add(4 * time.Minute), 0},
|
||||
{base.Add(5 * time.Minute), 24.7},
|
||||
}
|
||||
mockConn.EXPECT().
|
||||
Select(gomock.Any(), gomock.Any(), strings.TrimSpace(`
|
||||
{
|
||||
config: DefaultConfiguration(),
|
||||
query: `
|
||||
SELECT
|
||||
toStartOfInterval(TimeReceived + INTERVAL 144 second, INTERVAL 432 second) - INTERVAL 144 second AS Time,
|
||||
SUM(Bytes*SamplingRate*8/432)/1000/1000/1000 AS Gbps
|
||||
@@ -257,23 +247,82 @@ GROUP BY Time
|
||||
ORDER BY Time WITH FILL
|
||||
FROM toDateTime('2009-11-10 23:00:00', 'UTC')
|
||||
TO toDateTime('2009-11-11 23:00:00', 'UTC') + INTERVAL 1 second
|
||||
STEP 432`)).
|
||||
SetArg(1, expected).
|
||||
Return(nil)
|
||||
|
||||
helpers.TestHTTPEndpoints(t, h.LocalAddr(), helpers.HTTPEndpointCases{
|
||||
STEP 432`,
|
||||
},
|
||||
{
|
||||
URL: "/api/v0/console/widget/graph",
|
||||
JSONOutput: gin.H{
|
||||
"data": []gin.H{
|
||||
{"t": "2009-11-10T23:00:00Z", "gbps": 25.3},
|
||||
{"t": "2009-11-10T23:01:00Z", "gbps": 27.8},
|
||||
{"t": "2009-11-10T23:02:00Z", "gbps": 26.4},
|
||||
{"t": "2009-11-10T23:03:00Z", "gbps": 29.2},
|
||||
{"t": "2009-11-10T23:04:00Z", "gbps": 0},
|
||||
{"t": "2009-11-10T23:05:00Z", "gbps": 24.7},
|
||||
config: func() Configuration {
|
||||
c := DefaultConfiguration()
|
||||
c.HomepageGraphFilter = ""
|
||||
return c
|
||||
}(),
|
||||
query: `
|
||||
SELECT
|
||||
toStartOfInterval(TimeReceived + INTERVAL 144 second, INTERVAL 432 second) - INTERVAL 144 second AS Time,
|
||||
SUM(Bytes*SamplingRate*8/432)/1000/1000/1000 AS Gbps
|
||||
FROM flows
|
||||
WHERE TimeReceived BETWEEN toDateTime('2009-11-10 23:00:00', 'UTC') AND toDateTime('2009-11-11 23:00:00', 'UTC')
|
||||
|
||||
GROUP BY Time
|
||||
ORDER BY Time WITH FILL
|
||||
FROM toDateTime('2009-11-10 23:00:00', 'UTC')
|
||||
TO toDateTime('2009-11-11 23:00:00', 'UTC') + INTERVAL 1 second
|
||||
STEP 432`,
|
||||
},
|
||||
{
|
||||
config: func() Configuration {
|
||||
c := DefaultConfiguration()
|
||||
c.HomepageGraphFilter = "OutIfBoundary = 'external'"
|
||||
return c
|
||||
}(),
|
||||
query: `
|
||||
SELECT
|
||||
toStartOfInterval(TimeReceived + INTERVAL 144 second, INTERVAL 432 second) - INTERVAL 144 second AS Time,
|
||||
SUM(Bytes*SamplingRate*8/432)/1000/1000/1000 AS Gbps
|
||||
FROM flows
|
||||
WHERE TimeReceived BETWEEN toDateTime('2009-11-10 23:00:00', 'UTC') AND toDateTime('2009-11-11 23:00:00', 'UTC')
|
||||
AND OutIfBoundary = 'external'
|
||||
GROUP BY Time
|
||||
ORDER BY Time WITH FILL
|
||||
FROM toDateTime('2009-11-10 23:00:00', 'UTC')
|
||||
TO toDateTime('2009-11-11 23:00:00', 'UTC') + INTERVAL 1 second
|
||||
STEP 432`,
|
||||
},
|
||||
}
|
||||
for _, tcase := range testcases {
|
||||
_, h, mockConn, mockClock := NewMock(t, tcase.config)
|
||||
|
||||
base := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
|
||||
mockClock.Set(base.Add(24 * time.Hour))
|
||||
expected := []struct {
|
||||
Time time.Time `json:"t"`
|
||||
Gbps float64 `json:"gbps"`
|
||||
}{
|
||||
{base, 25.3},
|
||||
{base.Add(time.Minute), 27.8},
|
||||
{base.Add(2 * time.Minute), 26.4},
|
||||
{base.Add(3 * time.Minute), 29.2},
|
||||
{base.Add(4 * time.Minute), 0},
|
||||
{base.Add(5 * time.Minute), 24.7},
|
||||
}
|
||||
mockConn.EXPECT().
|
||||
Select(gomock.Any(), gomock.Any(), strings.TrimSpace(tcase.query)).
|
||||
SetArg(1, expected).
|
||||
Return(nil)
|
||||
|
||||
helpers.TestHTTPEndpoints(t, h.LocalAddr(), helpers.HTTPEndpointCases{
|
||||
{
|
||||
URL: "/api/v0/console/widget/graph",
|
||||
JSONOutput: gin.H{
|
||||
"data": []gin.H{
|
||||
{"t": "2009-11-10T23:00:00Z", "gbps": 25.3},
|
||||
{"t": "2009-11-10T23:01:00Z", "gbps": 27.8},
|
||||
{"t": "2009-11-10T23:02:00Z", "gbps": 26.4},
|
||||
{"t": "2009-11-10T23:03:00Z", "gbps": 29.2},
|
||||
{"t": "2009-11-10T23:04:00Z", "gbps": 0},
|
||||
{"t": "2009-11-10T23:05:00Z", "gbps": 24.7},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user