loki: implement schema for loki query (#62114)

* loki: implement schema for loki query

* removed forgotten code

* better types

* adjust cue-maturity-level

Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>

* sync docs to schema change

* removed forgotten go code

* updated schema docs

Co-authored-by: J Stickler <julie.stickler@grafana.com>

* updated schema docs

Co-authored-by: J Stickler <julie.stickler@grafana.com>

* update schema docs

Co-authored-by: J Stickler <julie.stickler@grafana.com>

* update schema docs

Co-authored-by: J Stickler <julie.stickler@grafana.com>

* updated schema docs

Co-authored-by: J Stickler <julie.stickler@grafana.com>

* updated schema docs

* add documentation to the resolution field

* move direction-field to schema

* loki: cue: moved deprecated fields to the bottom

---------

Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>
Co-authored-by: J Stickler <julie.stickler@grafana.com>
This commit is contained in:
Gábor Farkas 2023-02-02 17:18:30 +01:00 committed by GitHub
parent 753c84f825
commit 48a374f50b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 367 additions and 92 deletions

View File

@ -0,0 +1,47 @@
---
keywords:
- grafana
- schema
title: LokiDataQuery kind
---
> Both documentation generation and kinds schemas are in active development and subject to change without prior notice.
## LokiDataQuery
#### Maturity: experimental
#### Version: 0.0
It extends [DataQuery](#dataquery).
| Property | Type | Required | Description |
|----------------|---------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `expr` | string | **Yes** | The LogQL query. |
| `refId` | string | **Yes** | *(Inherited from [DataQuery](#dataquery))*<br/>A - Z |
| `datasource` | | No | *(Inherited from [DataQuery](#dataquery))*<br/>For mixed data sources the selected datasource is on the query level.<br/>For non mixed scenarios this is undefined.<br/>TODO find a better way to do this ^ that's friendly to schema<br/>TODO this shouldn't be unknown but DataSourceRef &#124; null |
| `editorMode` | string | No | Possible values are: `code`, `builder`. |
| `hide` | boolean | No | *(Inherited from [DataQuery](#dataquery))*<br/>true if query is disabled (ie should not be returned to the dashboard) |
| `instant` | boolean | No | @deprecated, now use queryType. |
| `key` | string | No | *(Inherited from [DataQuery](#dataquery))*<br/>Unique, guid like, string used in explore mode |
| `legendFormat` | string | No | Used to override the name of the series. |
| `maxLines` | integer | No | Used to limit the number of log rows returned. |
| `queryType` | string | No | *(Inherited from [DataQuery](#dataquery))*<br/>Specify the query flavor<br/>TODO make this required and give it a default |
| `range` | boolean | No | @deprecated, now use queryType. |
| `resolution` | integer | No | Used to scale the interval value. |
### DataQuery
These are the common properties available to all queries in all datasources.
Specific implementations will *extend* this interface, adding the required
properties for the given context.
| Property | Type | Required | Description |
|--------------|---------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `refId` | string | **Yes** | A - Z |
| `datasource` | | No | For mixed data sources the selected datasource is on the query level.<br/>For non mixed scenarios this is undefined.<br/>TODO find a better way to do this ^ that's friendly to schema<br/>TODO this shouldn't be unknown but DataSourceRef &#124; null |
| `hide` | boolean | No | true if query is disabled (ie should not be returned to the dashboard) |
| `key` | string | No | Unique, guid like, string used in explore mode |
| `queryType` | string | No | Specify the query flavor<br/>TODO make this required and give it a default |

View File

@ -908,7 +908,9 @@
},
"lokidataquery": {
"category": "composable",
"codeowners": [],
"codeowners": [
"grafana/observability-logs"
],
"currentVersion": [
0,
0
@ -916,13 +918,13 @@
"grafanaMaturityCount": 0,
"lineageIsGroup": false,
"links": {
"docs": "n/a",
"go": "n/a",
"schema": "n/a",
"ts": "n/a"
"docs": "https://grafana.com/docs/grafana/next/developers/kinds/composable/lokidataquery/schema-reference",
"go": "https://github.com/grafana/grafana/tree/main/pkg/tsdb/loki/kinds/dataquery/types_dataquery_gen.go",
"schema": "https://github.com/grafana/grafana/tree/main/public/app/plugins/datasource/loki/dataquery.cue",
"ts": "https://github.com/grafana/grafana/tree/main/public/app/plugins/datasource/loki/dataquery.gen.ts"
},
"machineName": "lokidataquery",
"maturity": "planned",
"maturity": "experimental",
"name": "LokiDataQuery",
"pluralMachineName": "lokidataquerys",
"pluralName": "LokiDataQuerys",
@ -1981,6 +1983,7 @@
"gaugepanelcfg",
"histogrampanelcfg",
"librarypanel",
"lokidataquery",
"newspanelcfg",
"nodegraphpanelcfg",
"phlaredataquery",
@ -1993,7 +1996,7 @@
"textpanelcfg",
"xychartpanelcfg"
],
"count": 19
"count": 20
},
"mature": {
"name": "mature",
@ -2045,7 +2048,6 @@
"jaegerdatasourcecfg",
"livepanelcfg",
"logspanelcfg",
"lokidataquery",
"lokidatasourcecfg",
"microsoftsqlserverdataquery",
"microsoftsqlserverdatasourcecfg",
@ -2070,7 +2072,7 @@
"zipkindataquery",
"zipkindatasourcecfg"
],
"count": 53
"count": 52
},
"stable": {
"name": "stable",

View File

@ -0,0 +1,105 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
//
// Generated by:
// public/app/plugins/gen.go
// Using jennies:
// PluginGoTypesJenny
//
// Run 'make gen-cue' from repository root to regenerate.
package dataquery
// Defines values for EditorMode.
const (
EditorModeBuilder EditorMode = "builder"
EditorModeCode EditorMode = "code"
)
// Defines values for LokiQueryDirection.
const (
LokiQueryDirectionBackward LokiQueryDirection = "backward"
LokiQueryDirectionForward LokiQueryDirection = "forward"
)
// Defines values for LokiQueryType.
const (
LokiQueryTypeInstant LokiQueryType = "instant"
LokiQueryTypeRange LokiQueryType = "range"
LokiQueryTypeStream LokiQueryType = "stream"
)
// Defines values for QueryEditorMode.
const (
QueryEditorModeBuilder QueryEditorMode = "builder"
QueryEditorModeCode QueryEditorMode = "code"
)
// Defines values for SupportingQueryType.
const (
SupportingQueryTypeDataSample SupportingQueryType = "dataSample"
SupportingQueryTypeLogsSample SupportingQueryType = "logsSample"
SupportingQueryTypeLogsVolume SupportingQueryType = "logsVolume"
)
// LokiDataQuery defines model for LokiDataQuery.
type LokiDataQuery struct {
// For mixed data sources the selected datasource is on the query level.
// For non mixed scenarios this is undefined.
// TODO find a better way to do this ^ that's friendly to schema
// TODO this shouldn't be unknown but DataSourceRef | null
Datasource *interface{} `json:"datasource,omitempty"`
EditorMode *EditorMode `json:"editorMode,omitempty"`
// The LogQL query.
Expr string `json:"expr"`
// true if query is disabled (ie should not be returned to the dashboard)
Hide *bool `json:"hide,omitempty"`
// @deprecated, now use queryType.
Instant *bool `json:"instant,omitempty"`
// Unique, guid like, string used in explore mode
Key *string `json:"key,omitempty"`
// Used to override the name of the series.
LegendFormat *string `json:"legendFormat,omitempty"`
// Used to limit the number of log rows returned.
MaxLines *int64 `json:"maxLines,omitempty"`
// Specify the query flavor
// TODO make this required and give it a default
QueryType *string `json:"queryType,omitempty"`
// @deprecated, now use queryType.
Range *bool `json:"range,omitempty"`
// A - Z
RefId string `json:"refId"`
// Used to scale the interval value.
Resolution *int64 `json:"resolution,omitempty"`
}
// EditorMode defines model for LokiDataQuery.EditorMode.
type EditorMode string
// LokiQueryDirection defines model for LokiQueryDirection.
type LokiQueryDirection string
// LokiQueryType defines model for LokiQueryType.
type LokiQueryType string
// QueryEditorMode defines model for QueryEditorMode.
type QueryEditorMode string
// SupportingQueryType defines model for SupportingQueryType.
type SupportingQueryType string

View File

@ -19,6 +19,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/tsdb/loki/kinds/dataquery"
)
var logger = log.New("tsdb.loki")
@ -57,15 +58,9 @@ type datasourceInfo struct {
}
type QueryJSONModel struct {
QueryType string `json:"queryType"`
Expr string `json:"expr"`
Direction string `json:"direction"`
LegendFormat string `json:"legendFormat"`
Interval string `json:"interval"`
IntervalMS int `json:"intervalMS"`
Resolution int64 `json:"resolution"`
MaxLines int `json:"maxLines"`
SupportingQueryType string `json:"supportingQueryType"`
dataquery.LokiDataQuery
Direction *string `json:"direction,omitempty"`
SupportingQueryType *string `json:"supportingQueryType"`
}
func parseQueryModel(raw json.RawMessage) (*QueryJSONModel, error) {

View File

@ -53,48 +53,57 @@ func interpolateVariables(expr string, interval time.Duration, timeRange time.Du
return expr
}
func parseQueryType(jsonValue string) (QueryType, error) {
switch jsonValue {
case "instant":
return QueryTypeInstant, nil
case "range":
return QueryTypeRange, nil
case "":
func parseQueryType(jsonPointerValue *string) (QueryType, error) {
if jsonPointerValue == nil {
// there are older queries stored in alerting that did not have queryType,
// those were range-queries
return QueryTypeRange, nil
default:
return QueryTypeRange, fmt.Errorf("invalid queryType: %s", jsonValue)
} else {
jsonValue := *jsonPointerValue
switch jsonValue {
case "instant":
return QueryTypeInstant, nil
case "range":
return QueryTypeRange, nil
default:
return QueryTypeRange, fmt.Errorf("invalid queryType: %s", jsonValue)
}
}
}
func parseDirection(jsonValue string) (Direction, error) {
switch jsonValue {
case "backward":
return DirectionBackward, nil
case "forward":
return DirectionForward, nil
case "":
func parseDirection(jsonPointerValue *string) (Direction, error) {
if jsonPointerValue == nil {
// there are older queries stored in alerting that did not have queryDirection,
// we default to "backward"
return DirectionBackward, nil
default:
return DirectionBackward, fmt.Errorf("invalid queryDirection: %s", jsonValue)
} else {
jsonValue := *jsonPointerValue
switch jsonValue {
case "backward":
return DirectionBackward, nil
case "forward":
return DirectionForward, nil
default:
return DirectionBackward, fmt.Errorf("invalid queryDirection: %s", jsonValue)
}
}
}
func parseSupportingQueryType(jsonValue string) (SupportingQueryType, error) {
switch jsonValue {
case "logsVolume":
return SupportingQueryLogsVolume, nil
case "logsSample":
return SupportingQueryLogsSample, nil
case "dataSample":
return SupportingQueryDataSample, nil
case "":
func parseSupportingQueryType(jsonPointerValue *string) (SupportingQueryType, error) {
if jsonPointerValue == nil {
return SupportingQueryNone, nil
default:
return SupportingQueryNone, fmt.Errorf("invalid supportingQueryType: %s", jsonValue)
} else {
jsonValue := *jsonPointerValue
switch jsonValue {
case "logsVolume":
return SupportingQueryLogsVolume, nil
case "logsSample":
return SupportingQueryLogsSample, nil
case "dataSample":
return SupportingQueryDataSample, nil
default:
return SupportingQueryNone, fmt.Errorf("invalid supportingQueryType: %s", jsonValue)
}
}
}
@ -110,8 +119,8 @@ func parseQuery(queryContext *backend.QueryDataRequest) ([]*lokiQuery, error) {
end := query.TimeRange.To
var resolution int64 = 1
if model.Resolution >= 1 && model.Resolution <= 5 || model.Resolution == 10 {
resolution = model.Resolution
if model.Resolution != nil && (*model.Resolution >= 1 && *model.Resolution <= 5 || *model.Resolution == 10) {
resolution = *model.Resolution
}
interval := query.Interval
@ -131,6 +140,16 @@ func parseQuery(queryContext *backend.QueryDataRequest) ([]*lokiQuery, error) {
return nil, err
}
var maxLines int64
if model.MaxLines != nil {
maxLines = *model.MaxLines
}
var legendFormat string
if model.LegendFormat != nil {
legendFormat = *model.LegendFormat
}
supportingQueryType, err := parseSupportingQueryType(model.SupportingQueryType)
if err != nil {
return nil, err
@ -141,8 +160,8 @@ func parseQuery(queryContext *backend.QueryDataRequest) ([]*lokiQuery, error) {
QueryType: queryType,
Direction: direction,
Step: step,
MaxLines: model.MaxLines,
LegendFormat: model.LegendFormat,
MaxLines: int(maxLines),
LegendFormat: legendFormat,
Start: start,
End: end,
RefID: query.RefID,

View File

@ -1,27 +1,30 @@
package loki
import "time"
import (
"time"
type QueryType string
type SupportingQueryType string
"github.com/grafana/grafana/pkg/tsdb/loki/kinds/dataquery"
)
type QueryType = dataquery.LokiQueryType
type SupportingQueryType = dataquery.SupportingQueryType
type Direction = dataquery.LokiQueryDirection
const (
QueryTypeRange QueryType = "range"
QueryTypeInstant QueryType = "instant"
QueryTypeRange = dataquery.LokiQueryTypeRange
QueryTypeInstant = dataquery.LokiQueryTypeInstant
)
const (
SupportingQueryLogsVolume SupportingQueryType = "logsVolume"
SupportingQueryLogsSample SupportingQueryType = "logsSample"
SupportingQueryDataSample SupportingQueryType = "dataSample"
SupportingQueryLogsVolume = dataquery.SupportingQueryTypeLogsVolume
SupportingQueryLogsSample = dataquery.SupportingQueryTypeLogsSample
SupportingQueryDataSample = dataquery.SupportingQueryTypeDataSample
SupportingQueryNone SupportingQueryType = "none"
)
type Direction string
const (
DirectionBackward Direction = "backward"
DirectionForward Direction = "forward"
DirectionBackward = dataquery.LokiQueryDirectionBackward
DirectionForward = dataquery.LokiQueryDirectionForward
)
type lokiQuery struct {

View File

@ -0,0 +1,61 @@
// Copyright 2023 Grafana Labs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package grafanaplugin
import (
"github.com/grafana/grafana/packages/grafana-schema/src/common"
"github.com/grafana/grafana/pkg/plugins/pfs"
)
// This file (with its sibling .cue files) implements pfs.GrafanaPlugin
pfs.GrafanaPlugin
composableKinds: DataQuery: {
maturity: "experimental"
lineage: {
seqs: [
{
schemas: [
{
common.DataQuery
// The LogQL query.
expr: string
// Used to override the name of the series.
legendFormat?: string
// Used to limit the number of log rows returned.
maxLines?: int64
// Used to scale the interval value.
resolution?: int64
editorMode?: #QueryEditorMode
// @deprecated, now use queryType.
range?: bool
// @deprecated, now use queryType.
instant?: bool
#QueryEditorMode: "code" | "builder" @cuetsy(kind="enum")
#LokiQueryType: "range" | "instant" | "stream" @cuetsy(kind="enum")
#SupportingQueryType: "logsVolume" | "logsSample" | "dataSample" @cuetsy(kind="enum")
#LokiQueryDirection: "forward" | "backward" @cuetsy(kind="enum")
},
]
},
]
}
}

View File

@ -0,0 +1,63 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
//
// Generated by:
// public/app/plugins/gen.go
// Using jennies:
// TSTypesJenny
// PluginTSTypesJenny
//
// Run 'make gen-cue' from repository root to regenerate.
import * as common from '@grafana/schema';
export const DataQueryModelVersion = Object.freeze([0, 0]);
export enum QueryEditorMode {
Builder = 'builder',
Code = 'code',
}
export enum LokiQueryType {
Instant = 'instant',
Range = 'range',
Stream = 'stream',
}
export enum SupportingQueryType {
DataSample = 'dataSample',
LogsSample = 'logsSample',
LogsVolume = 'logsVolume',
}
export enum LokiQueryDirection {
Backward = 'backward',
Forward = 'forward',
}
export interface Loki extends common.DataQuery {
editorMode?: QueryEditorMode;
/**
* The LogQL query.
*/
expr: string;
/**
* @deprecated, now use queryType.
*/
instant?: boolean;
/**
* Used to override the name of the series.
*/
legendFormat?: string;
/**
* Used to limit the number of log rows returned.
*/
maxLines?: number;
/**
* @deprecated, now use queryType.
*/
range?: boolean;
/**
* Used to scale the interval value.
*/
resolution?: number;
}

View File

@ -1,6 +1,8 @@
import { DataQuery, DataSourceJsonData, QueryResultMeta, ScopedVars } from '@grafana/data';
import { QueryEditorMode } from '../prometheus/querybuilder/shared/types';
import { Loki as LokiQueryFromSchema, LokiQueryType, SupportingQueryType, LokiQueryDirection } from './dataquery.gen';
export { LokiQueryDirection, LokiQueryType, SupportingQueryType };
export interface LokiInstantQueryRequest {
query: string;
@ -24,31 +26,15 @@ export enum LokiResultType {
Matrix = 'matrix',
}
export enum LokiQueryType {
Range = 'range',
Instant = 'instant',
Stream = 'stream',
}
export enum LokiQueryDirection {
Backward = 'backward',
Forward = 'forward',
}
export interface LokiQuery extends DataQuery {
queryType?: LokiQueryType;
expr: string;
export interface LokiQuery extends LokiQueryFromSchema {
direction?: LokiQueryDirection;
legendFormat?: string;
maxLines?: number;
resolution?: number;
/** Used only to identify supporting queries, e.g. logs volume, logs sample and data sample */
supportingQueryType?: SupportingQueryType;
/* @deprecated now use queryType */
range?: boolean;
/* @deprecated now use queryType */
instant?: boolean;
editorMode?: QueryEditorMode;
// CUE autogenerates `queryType` as `?string`, as that's how it is defined
// in the parent-interface (in DataQuery).
// the temporary fix (until this gets improved in the codegen), is to
// override it here
queryType?: LokiQueryType;
}
export interface LokiOptions extends DataSourceJsonData {
@ -161,12 +147,6 @@ export interface QueryStats {
entries: number;
}
export enum SupportingQueryType {
LogsVolume = 'logsVolume',
LogsSample = 'logsSample',
DataSample = 'dataSample',
}
export interface ContextFilter {
enabled: boolean;
label: string;