11import {
2- DataFrame ,
32 DataQueryRequest ,
4- DataQueryResponse ,
5- DataSourceApi ,
6- DataSourceJsonData ,
73 DataSourceWithSupplementaryQueriesSupport ,
8- FieldColorModeId ,
9- FieldType ,
10- LoadingState ,
11- LogLevel ,
12- LogsVolumeCustomMetaData ,
13- LogsVolumeType ,
144 SupplementaryQueryType ,
155} from '@grafana/data' ;
16- import { BarAlignment , DataQuery , GraphDrawStyle , StackingMode } from "@grafana/schema" ;
17- import { colors } from "@grafana/ui" ;
18- import { getIntervalInfo } from '@/utils/time' ;
19- import { cloneDeep , groupBy } from "lodash" ;
20- import { Observable , isObservable , from } from 'rxjs' ;
6+ import { cloneDeep } from "lodash" ;
217import { BucketAggregation , ElasticsearchQuery } from '@/types' ;
228import { BaseQuickwitDataSourceConstructor } from './base' ;
239
2410export const REF_ID_STARTER_LOG_VOLUME = 'log-volume-' ;
2511
2612export function withSupplementaryQueries < T extends BaseQuickwitDataSourceConstructor > ( Base : T ) {
2713 return class DSWithSupplementaryQueries extends Base implements DataSourceWithSupplementaryQueriesSupport < ElasticsearchQuery > {
14+
2815 /**
29- * Returns an observable that will be used to fetch supplementary data based on the provided
30- * supplementary query type and original request .
16+ * Returns a DataQueryRequest for the supplementary query type.
17+ * Grafana's Explore layer handles the Observable lifecycle .
3118 */
32- getDataProvider (
19+ getSupplementaryRequest (
3320 type : SupplementaryQueryType ,
3421 request : DataQueryRequest < ElasticsearchQuery >
35- ) : Observable < DataQueryResponse > | undefined {
36- if ( ! this . getSupportedSupplementaryQueryTypes ( ) . includes ( type ) ) {
37- return undefined ;
38- }
22+ ) : DataQueryRequest < ElasticsearchQuery > | undefined {
3923 switch ( type ) {
4024 case SupplementaryQueryType . LogsVolume :
41- return this . getLogsVolumeDataProvider ( request ) ;
25+ return this . getLogsVolumeRequest ( request ) ;
4226 default :
4327 return undefined ;
4428 }
@@ -55,18 +39,15 @@ export function withSupplementaryQueries<T extends BaseQuickwitDataSourceConstru
5539 * Returns a supplementary query to be used to fetch supplementary data based on the provided type and original query.
5640 * If provided query is not suitable for provided supplementary query type, undefined should be returned.
5741 */
58- // FIXME: options should be of type SupplementaryQueryOptions but this type is not public.
59- getSupplementaryQuery ( options : any , query : ElasticsearchQuery ) : ElasticsearchQuery | undefined {
42+ getSupplementaryQuery ( options : { type : SupplementaryQueryType } , query : ElasticsearchQuery ) : ElasticsearchQuery | undefined {
6043 if ( ! this . getSupportedSupplementaryQueryTypes ( ) . includes ( options . type ) ) {
6144 return undefined ;
6245 }
6346
64- let isQuerySuitable = false ;
65-
6647 switch ( options . type ) {
67- case SupplementaryQueryType . LogsVolume :
48+ case SupplementaryQueryType . LogsVolume : {
6849 // it has to be a logs-producing range-query
69- isQuerySuitable = ! ! ( query . metrics ?. length === 1 && query . metrics [ 0 ] . type === 'logs' ) ;
50+ const isQuerySuitable = ! ! ( query . metrics ?. length === 1 && query . metrics [ 0 ] . type === 'logs' ) ;
7051 if ( ! isQuerySuitable ) {
7152 return undefined ;
7253 }
@@ -103,13 +84,16 @@ export function withSupplementaryQueries<T extends BaseQuickwitDataSourceConstru
10384 metrics : [ { type : 'count' , id : '1' } ] ,
10485 bucketAggs,
10586 } ;
87+ }
10688
10789 default :
10890 return undefined ;
10991 }
11092 }
11193
112- getLogsVolumeDataProvider ( request : DataQueryRequest < ElasticsearchQuery > ) : Observable < DataQueryResponse > | undefined {
94+ private getLogsVolumeRequest (
95+ request : DataQueryRequest < ElasticsearchQuery >
96+ ) : DataQueryRequest < ElasticsearchQuery > | undefined {
11397 const logsVolumeRequest = cloneDeep ( request ) ;
11498 const targets = logsVolumeRequest . targets
11599 . map ( ( target ) => this . getSupplementaryQuery ( { type : SupplementaryQueryType . LogsVolume } , target ) )
@@ -119,172 +103,7 @@ export function withSupplementaryQueries<T extends BaseQuickwitDataSourceConstru
119103 return undefined ;
120104 }
121105
122- return queryLogsVolume (
123- this ,
124- { ...logsVolumeRequest , targets } ,
125- {
126- range : request . range ,
127- targets : request . targets ,
128- extractLevel : ( dataFrame : any ) => getLogLevelFromKey ( dataFrame || '' ) ,
129- }
130- ) ;
131- }
132- } ;
133- }
134-
135- // Copy/pasted from grafana/data as it is deprecated there.
136- function getLogLevelFromKey ( dataframe : DataFrame ) : LogLevel {
137- const name = dataframe . fields [ 1 ] . config . displayNameFromDS || `` ;
138- const level = ( LogLevel as any ) [ name . toString ( ) . toLowerCase ( ) ] ;
139- if ( level ) {
140- return level ;
141- }
142- return LogLevel . unknown ;
143- }
144-
145- /**
146- * Creates an observable, which makes requests to get logs volume and aggregates results.
147- */
148-
149- export function queryLogsVolume < TQuery extends DataQuery , TOptions extends DataSourceJsonData > (
150- datasource : DataSourceApi < TQuery , TOptions > ,
151- logsVolumeRequest : DataQueryRequest < TQuery > ,
152- options : any
153- ) : Observable < DataQueryResponse > {
154- const timespan = options . range . to . valueOf ( ) - options . range . from . valueOf ( ) ;
155- const intervalInfo = getIntervalInfo ( timespan , 400 ) ;
156-
157- logsVolumeRequest . interval = intervalInfo . interval ;
158- logsVolumeRequest . scopedVars . __interval = { value : intervalInfo . interval , text : intervalInfo . interval } ;
159-
160- if ( intervalInfo . intervalMs !== undefined ) {
161- logsVolumeRequest . intervalMs = intervalInfo . intervalMs ;
162- logsVolumeRequest . scopedVars . __interval_ms = { value : intervalInfo . intervalMs , text : intervalInfo . intervalMs } ;
106+ return { ...logsVolumeRequest , targets } ;
163107 }
164-
165- logsVolumeRequest . hideFromInspector = true ;
166-
167- return new Observable ( ( observer ) => {
168- let logsVolumeData : DataFrame [ ] = [ ] ;
169- observer . next ( {
170- state : LoadingState . Loading ,
171- error : undefined ,
172- data : [ ] ,
173- } ) ;
174-
175- const queryResponse = datasource . query ( logsVolumeRequest ) ;
176- const queryObservable = isObservable ( queryResponse ) ? queryResponse : from ( queryResponse ) ;
177-
178- const subscription = queryObservable . subscribe ( {
179- complete : ( ) => {
180- observer . complete ( ) ;
181- } ,
182- next : ( dataQueryResponse : DataQueryResponse ) => {
183- const { error } = dataQueryResponse ;
184- if ( error !== undefined ) {
185- observer . next ( {
186- state : LoadingState . Error ,
187- error,
188- data : [ ] ,
189- } ) ;
190- observer . error ( error ) ;
191- } else {
192- const framesByRefId = groupBy ( dataQueryResponse . data , 'refId' ) ;
193- logsVolumeData = dataQueryResponse . data . map ( ( dataFrame ) => {
194- let sourceRefId = dataFrame . refId || '' ;
195- if ( sourceRefId . startsWith ( 'log-volume-' ) ) {
196- sourceRefId = sourceRefId . substr ( 'log-volume-' . length ) ;
197- }
198-
199- const logsVolumeCustomMetaData : LogsVolumeCustomMetaData = {
200- logsVolumeType : LogsVolumeType . FullRange ,
201- absoluteRange : { from : options . range . from . valueOf ( ) , to : options . range . to . valueOf ( ) } ,
202- datasourceName : datasource . name ,
203- sourceQuery : options . targets . find ( ( dataQuery : any ) => dataQuery . refId === sourceRefId ) ! ,
204- } ;
205-
206- dataFrame . meta = {
207- ...dataFrame . meta ,
208- custom : {
209- ...dataFrame . meta ?. custom ,
210- ...logsVolumeCustomMetaData ,
211- } ,
212- } ;
213- return updateLogsVolumeConfig ( dataFrame , options . extractLevel , framesByRefId [ dataFrame . refId ] . length === 1 ) ;
214- } ) ;
215-
216- observer . next ( {
217- state : dataQueryResponse . state ,
218- error : undefined ,
219- data : logsVolumeData ,
220- } ) ;
221- }
222- } ,
223- error : ( error : any ) => {
224- observer . next ( {
225- state : LoadingState . Error ,
226- error : error ,
227- data : [ ] ,
228- } ) ;
229- observer . error ( error ) ;
230- } ,
231- } ) ;
232- return ( ) => {
233- subscription ?. unsubscribe ( ) ;
234- } ;
235- } ) ;
236- }
237- const updateLogsVolumeConfig = (
238- dataFrame : DataFrame ,
239- extractLevel : ( dataFrame : DataFrame ) => LogLevel ,
240- oneLevelDetected : boolean
241- ) : DataFrame => {
242- dataFrame . fields = dataFrame . fields . map ( ( field ) => {
243- if ( field . type === FieldType . number ) {
244- field . config = {
245- ...field . config ,
246- ...getLogVolumeFieldConfig ( extractLevel ( dataFrame ) , oneLevelDetected ) ,
247- } ;
248- }
249- return field ;
250- } ) ;
251- return dataFrame ;
252- } ;
253- const LogLevelColor = {
254- [ LogLevel . critical ] : colors [ 7 ] ,
255- [ LogLevel . warning ] : colors [ 1 ] ,
256- [ LogLevel . error ] : colors [ 4 ] ,
257- [ LogLevel . info ] : colors [ 0 ] ,
258- [ LogLevel . debug ] : colors [ 5 ] ,
259- [ LogLevel . trace ] : colors [ 2 ] ,
260- [ LogLevel . unknown ] : '#8e8e8e' // or '#bdc4cd',
261- } ;
262- /**
263- * Returns field configuration used to render logs volume bars
264- */
265- function getLogVolumeFieldConfig ( level : LogLevel , oneLevelDetected : boolean ) {
266- const name = oneLevelDetected && level === LogLevel . unknown ? 'logs' : level ;
267- const color = LogLevelColor [ level ] ;
268- return {
269- displayNameFromDS : name ,
270- color : {
271- mode : FieldColorModeId . Fixed ,
272- fixedColor : color ,
273- } ,
274- custom : {
275- drawStyle : GraphDrawStyle . Bars ,
276- barAlignment : BarAlignment . Center ,
277- lineColor : color ,
278- pointColor : color ,
279- fillColor : color ,
280- lineWidth : 1 ,
281- fillOpacity : 100 ,
282- stacking : {
283- mode : StackingMode . Normal ,
284- group : 'A' ,
285- } ,
286- } ,
287108 } ;
288109}
289-
290-
0 commit comments