mirror of
https://github.com/grafana/grafana.git
synced 2025-01-26 16:27:02 -06:00
testdata: logs scenario (#17182)
Adds logs scenario which is quite basic and not that smart to begin with. This will hopefully ease development of Explore and support for logs in Grafana.
This commit is contained in:
parent
c82df97bb2
commit
3b008d06b4
79
pkg/tsdb/testdata/scenarios.go
vendored
79
pkg/tsdb/testdata/scenarios.go
vendored
@ -2,6 +2,7 @@ package testdata
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
@ -261,6 +262,84 @@ func init() {
|
||||
return queryRes
|
||||
},
|
||||
})
|
||||
|
||||
registerScenario(&Scenario{
|
||||
Id: "logs",
|
||||
Name: "Logs",
|
||||
|
||||
Handler: func(query *tsdb.Query, context *tsdb.TsdbQuery) *tsdb.QueryResult {
|
||||
from := context.TimeRange.GetFromAsMsEpoch()
|
||||
to := context.TimeRange.GetToAsMsEpoch()
|
||||
lines := query.Model.Get("lines").MustInt64(10)
|
||||
includeLevelColumn := query.Model.Get("levelColumn").MustBool(false)
|
||||
|
||||
logLevelGenerator := newRandomStringProvider([]string{
|
||||
"emerg",
|
||||
"alert",
|
||||
"crit",
|
||||
"critical",
|
||||
"warn",
|
||||
"warning",
|
||||
"err",
|
||||
"eror",
|
||||
"error",
|
||||
"info",
|
||||
"notice",
|
||||
"dbug",
|
||||
"debug",
|
||||
"trace",
|
||||
"",
|
||||
})
|
||||
containerIDGenerator := newRandomStringProvider([]string{
|
||||
"f36a9eaa6d34310686f2b851655212023a216de955cbcc764210cefa71179b1a",
|
||||
"5a354a630364f3742c602f315132e16def594fe68b1e4a195b2fce628e24c97a",
|
||||
})
|
||||
hostnameGenerator := newRandomStringProvider([]string{
|
||||
"srv-001",
|
||||
"srv-002",
|
||||
})
|
||||
|
||||
table := tsdb.Table{
|
||||
Columns: []tsdb.TableColumn{
|
||||
{Text: "time"},
|
||||
{Text: "message"},
|
||||
{Text: "container_id"},
|
||||
{Text: "hostname"},
|
||||
},
|
||||
Rows: []tsdb.RowValues{},
|
||||
}
|
||||
|
||||
if includeLevelColumn {
|
||||
table.Columns = append(table.Columns, tsdb.TableColumn{Text: "level"})
|
||||
}
|
||||
|
||||
for i := int64(0); i < lines && to > from; i++ {
|
||||
row := tsdb.RowValues{float64(to)}
|
||||
|
||||
logLevel := logLevelGenerator.Next()
|
||||
timeFormatted := time.Unix(to/1000, 0).Format(time.RFC3339)
|
||||
lvlString := ""
|
||||
if !includeLevelColumn {
|
||||
lvlString = fmt.Sprintf("lvl=%s ", logLevel)
|
||||
}
|
||||
|
||||
row = append(row, fmt.Sprintf("t=%s %smsg=\"Request Completed\" logger=context userId=1 orgId=1 uname=admin method=GET path=/api/datasources/proxy/152/api/prom/label status=502 remote_addr=[::1] time_ms=1 size=0 referer=\"http://localhost:3000/explore?left=%%5B%%22now-6h%%22,%%22now%%22,%%22Prometheus%%202.x%%22,%%7B%%7D,%%7B%%22ui%%22:%%5Btrue,true,true,%%22none%%22%%5D%%7D%%5D\"", timeFormatted, lvlString))
|
||||
row = append(row, containerIDGenerator.Next())
|
||||
row = append(row, hostnameGenerator.Next())
|
||||
|
||||
if includeLevelColumn {
|
||||
row = append(row, logLevel)
|
||||
}
|
||||
|
||||
table.Rows = append(table.Rows, row)
|
||||
to -= query.IntervalMs
|
||||
}
|
||||
|
||||
queryRes := tsdb.NewQueryResult()
|
||||
queryRes.Tables = append(queryRes.Tables, &table)
|
||||
return queryRes
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func getRandomWalk(query *tsdb.Query, tsdbQuery *tsdb.TsdbQuery) *tsdb.QueryResult {
|
||||
|
22
pkg/tsdb/testdata/utils.go
vendored
Normal file
22
pkg/tsdb/testdata/utils.go
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
package testdata
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
type randomStringProvider struct {
|
||||
r *rand.Rand
|
||||
data []string
|
||||
}
|
||||
|
||||
func newRandomStringProvider(data []string) *randomStringProvider {
|
||||
return &randomStringProvider{
|
||||
r: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *randomStringProvider) Next() string {
|
||||
return p.data[p.r.Int31n(int32(len(p.data)))]
|
||||
}
|
@ -32,10 +32,11 @@ export class TestDataDatasource extends DataSourceApi<TestDataQuery> {
|
||||
scenarioId: item.scenarioId,
|
||||
intervalMs: options.intervalMs,
|
||||
maxDataPoints: options.maxDataPoints,
|
||||
datasourceId: this.id,
|
||||
stringInput: item.stringInput,
|
||||
points: item.points,
|
||||
alias: item.alias,
|
||||
datasourceId: this.id,
|
||||
...item,
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -40,8 +40,8 @@
|
||||
<div class="gf-form gf-form">
|
||||
<label class="gf-form-label query-keyword width-7">Type</label>
|
||||
<div class="gf-form-select-wrapper">
|
||||
<select
|
||||
ng-model="ctrl.target.stream.type"
|
||||
<select
|
||||
ng-model="ctrl.target.stream.type"
|
||||
class="gf-form-input"
|
||||
ng-options="type for type in ['signal','logs', 'fetch']"
|
||||
ng-change="ctrl.streamChanged()" />
|
||||
@ -50,45 +50,60 @@
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label query-keyword">Speed (ms)</label>
|
||||
<input type="number"
|
||||
class="gf-form-input width-5"
|
||||
placeholder="value"
|
||||
ng-model="ctrl.target.stream.speed"
|
||||
<input type="number"
|
||||
class="gf-form-input width-5"
|
||||
placeholder="value"
|
||||
ng-model="ctrl.target.stream.speed"
|
||||
min="10"
|
||||
step="10"
|
||||
ng-change="ctrl.streamChanged()" />
|
||||
</div>
|
||||
<div class="gf-form" ng-if="ctrl.target.stream.type === 'signal'">
|
||||
<label class="gf-form-label query-keyword">Spread</label>
|
||||
<input type="number"
|
||||
class="gf-form-input width-5"
|
||||
placeholder="value"
|
||||
ng-model="ctrl.target.stream.spread"
|
||||
<input type="number"
|
||||
class="gf-form-input width-5"
|
||||
placeholder="value"
|
||||
ng-model="ctrl.target.stream.spread"
|
||||
min="0.5"
|
||||
step="0.1"
|
||||
ng-change="ctrl.streamChanged()" />
|
||||
</div>
|
||||
<div class="gf-form" ng-if="ctrl.target.stream.type === 'signal'">
|
||||
<label class="gf-form-label query-keyword">Noise</label>
|
||||
<input type="number"
|
||||
class="gf-form-input width-5"
|
||||
placeholder="value"
|
||||
ng-model="ctrl.target.stream.noise"
|
||||
<input type="number"
|
||||
class="gf-form-input width-5"
|
||||
placeholder="value"
|
||||
ng-model="ctrl.target.stream.noise"
|
||||
min="0"
|
||||
step="0.1"
|
||||
ng-change="ctrl.streamChanged()" />
|
||||
</div>
|
||||
<div class="gf-form gf-form--grow" ng-if="ctrl.target.stream.type === 'fetch'">
|
||||
<label class="gf-form-label query-keyword">URL</label>
|
||||
<input type="string"
|
||||
class="gf-form-input gf-form-label--grow"
|
||||
placeholder="Fetch URL"
|
||||
ng-model="ctrl.target.stream.url"
|
||||
ng-change="ctrl.streamChanged()"
|
||||
<input type="string"
|
||||
class="gf-form-input gf-form-label--grow"
|
||||
placeholder="Fetch URL"
|
||||
ng-model="ctrl.target.stream.url"
|
||||
ng-change="ctrl.streamChanged()"
|
||||
ng-model-onblur />
|
||||
</div>
|
||||
<div class="gf-form gf-form--grow" ng-if="ctrl.target.stream.type !== 'fetch'">
|
||||
<div class="gf-form-label gf-form-label--grow"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-inline" ng-if="ctrl.scenario.id === 'logs'">
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label query-keyword">Lines</label>
|
||||
<input type="number"
|
||||
class="gf-form-input width-5"
|
||||
placeholder="10"
|
||||
ng-model="ctrl.target.lines"
|
||||
ng-change="ctrl.refresh()"
|
||||
ng-model-onblur />
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<gf-form-switch class="gf-form" label="Level" label-class="query-keyword width-5" checked="ctrl.target.levelColumn" switch-class="max-width-6" on-change="ctrl.refresh()"></gf-form-switch>
|
||||
</div>
|
||||
</div>
|
||||
</query-editor-row>
|
||||
|
Loading…
Reference in New Issue
Block a user