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:
Marcus Efraimsson 2019-05-21 09:21:59 +02:00 committed by GitHub
parent c82df97bb2
commit 3b008d06b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 137 additions and 20 deletions

View File

@ -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
View 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)))]
}

View File

@ -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,
};
});

View File

@ -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>