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 }
@@ -104,13 +85,16 @@ export function withSupplementaryQueries<T extends BaseQuickwitDataSourceConstru
10485 bucketAggs,
10586 filters : query . filters ,
10687 } ;
88+ }
10789
10890 default :
10991 return undefined ;
11092 }
11193 }
11294
113- getLogsVolumeDataProvider ( request : DataQueryRequest < ElasticsearchQuery > ) : Observable < DataQueryResponse > | undefined {
95+ private getLogsVolumeRequest (
96+ request : DataQueryRequest < ElasticsearchQuery >
97+ ) : DataQueryRequest < ElasticsearchQuery > | undefined {
11498 const logsVolumeRequest = cloneDeep ( request ) ;
11599 const targets = logsVolumeRequest . targets
116100 . map ( ( target ) => this . getSupplementaryQuery ( { type : SupplementaryQueryType . LogsVolume } , target ) )
@@ -120,172 +104,7 @@ export function withSupplementaryQueries<T extends BaseQuickwitDataSourceConstru
120104 return undefined ;
121105 }
122106
123- return queryLogsVolume (
124- this ,
125- { ...logsVolumeRequest , targets } ,
126- {
127- range : request . range ,
128- targets : request . targets ,
129- extractLevel : ( dataFrame : any ) => getLogLevelFromKey ( dataFrame || '' ) ,
130- }
131- ) ;
132- }
133- } ;
134- }
135-
136- // Copy/pasted from grafana/data as it is deprecated there.
137- function getLogLevelFromKey ( dataframe : DataFrame ) : LogLevel {
138- const name = dataframe . fields [ 1 ] . config . displayNameFromDS || `` ;
139- const level = ( LogLevel as any ) [ name . toString ( ) . toLowerCase ( ) ] ;
140- if ( level ) {
141- return level ;
142- }
143- return LogLevel . unknown ;
144- }
145-
146- /**
147- * Creates an observable, which makes requests to get logs volume and aggregates results.
148- */
149-
150- export function queryLogsVolume < TQuery extends DataQuery , TOptions extends DataSourceJsonData > (
151- datasource : DataSourceApi < TQuery , TOptions > ,
152- logsVolumeRequest : DataQueryRequest < TQuery > ,
153- options : any
154- ) : Observable < DataQueryResponse > {
155- const timespan = options . range . to . valueOf ( ) - options . range . from . valueOf ( ) ;
156- const intervalInfo = getIntervalInfo ( timespan , 400 ) ;
157-
158- logsVolumeRequest . interval = intervalInfo . interval ;
159- logsVolumeRequest . scopedVars . __interval = { value : intervalInfo . interval , text : intervalInfo . interval } ;
160-
161- if ( intervalInfo . intervalMs !== undefined ) {
162- logsVolumeRequest . intervalMs = intervalInfo . intervalMs ;
163- logsVolumeRequest . scopedVars . __interval_ms = { value : intervalInfo . intervalMs , text : intervalInfo . intervalMs } ;
107+ return { ...logsVolumeRequest , targets } ;
164108 }
165-
166- logsVolumeRequest . hideFromInspector = true ;
167-
168- return new Observable ( ( observer ) => {
169- let logsVolumeData : DataFrame [ ] = [ ] ;
170- observer . next ( {
171- state : LoadingState . Loading ,
172- error : undefined ,
173- data : [ ] ,
174- } ) ;
175-
176- const queryResponse = datasource . query ( logsVolumeRequest ) ;
177- const queryObservable = isObservable ( queryResponse ) ? queryResponse : from ( queryResponse ) ;
178-
179- const subscription = queryObservable . subscribe ( {
180- complete : ( ) => {
181- observer . complete ( ) ;
182- } ,
183- next : ( dataQueryResponse : DataQueryResponse ) => {
184- const { error } = dataQueryResponse ;
185- if ( error !== undefined ) {
186- observer . next ( {
187- state : LoadingState . Error ,
188- error,
189- data : [ ] ,
190- } ) ;
191- observer . error ( error ) ;
192- } else {
193- const framesByRefId = groupBy ( dataQueryResponse . data , 'refId' ) ;
194- logsVolumeData = dataQueryResponse . data . map ( ( dataFrame ) => {
195- let sourceRefId = dataFrame . refId || '' ;
196- if ( sourceRefId . startsWith ( 'log-volume-' ) ) {
197- sourceRefId = sourceRefId . substr ( 'log-volume-' . length ) ;
198- }
199-
200- const logsVolumeCustomMetaData : LogsVolumeCustomMetaData = {
201- logsVolumeType : LogsVolumeType . FullRange ,
202- absoluteRange : { from : options . range . from . valueOf ( ) , to : options . range . to . valueOf ( ) } ,
203- datasourceName : datasource . name ,
204- sourceQuery : options . targets . find ( ( dataQuery : any ) => dataQuery . refId === sourceRefId ) ! ,
205- } ;
206-
207- dataFrame . meta = {
208- ...dataFrame . meta ,
209- custom : {
210- ...dataFrame . meta ?. custom ,
211- ...logsVolumeCustomMetaData ,
212- } ,
213- } ;
214- return updateLogsVolumeConfig ( dataFrame , options . extractLevel , framesByRefId [ dataFrame . refId ] . length === 1 ) ;
215- } ) ;
216-
217- observer . next ( {
218- state : dataQueryResponse . state ,
219- error : undefined ,
220- data : logsVolumeData ,
221- } ) ;
222- }
223- } ,
224- error : ( error : any ) => {
225- observer . next ( {
226- state : LoadingState . Error ,
227- error : error ,
228- data : [ ] ,
229- } ) ;
230- observer . error ( error ) ;
231- } ,
232- } ) ;
233- return ( ) => {
234- subscription ?. unsubscribe ( ) ;
235- } ;
236- } ) ;
237- }
238- const updateLogsVolumeConfig = (
239- dataFrame : DataFrame ,
240- extractLevel : ( dataFrame : DataFrame ) => LogLevel ,
241- oneLevelDetected : boolean
242- ) : DataFrame => {
243- dataFrame . fields = dataFrame . fields . map ( ( field ) => {
244- if ( field . type === FieldType . number ) {
245- field . config = {
246- ...field . config ,
247- ...getLogVolumeFieldConfig ( extractLevel ( dataFrame ) , oneLevelDetected ) ,
248- } ;
249- }
250- return field ;
251- } ) ;
252- return dataFrame ;
253- } ;
254- const LogLevelColor = {
255- [ LogLevel . critical ] : colors [ 7 ] ,
256- [ LogLevel . warning ] : colors [ 1 ] ,
257- [ LogLevel . error ] : colors [ 4 ] ,
258- [ LogLevel . info ] : colors [ 0 ] ,
259- [ LogLevel . debug ] : colors [ 5 ] ,
260- [ LogLevel . trace ] : colors [ 2 ] ,
261- [ LogLevel . unknown ] : '#8e8e8e' // or '#bdc4cd',
262- } ;
263- /**
264- * Returns field configuration used to render logs volume bars
265- */
266- function getLogVolumeFieldConfig ( level : LogLevel , oneLevelDetected : boolean ) {
267- const name = oneLevelDetected && level === LogLevel . unknown ? 'logs' : level ;
268- const color = LogLevelColor [ level ] ;
269- return {
270- displayNameFromDS : name ,
271- color : {
272- mode : FieldColorModeId . Fixed ,
273- fixedColor : color ,
274- } ,
275- custom : {
276- drawStyle : GraphDrawStyle . Bars ,
277- barAlignment : BarAlignment . Center ,
278- lineColor : color ,
279- pointColor : color ,
280- fillColor : color ,
281- lineWidth : 1 ,
282- fillOpacity : 100 ,
283- stacking : {
284- mode : StackingMode . Normal ,
285- group : 'A' ,
286- } ,
287- } ,
288109 } ;
289110}
290-
291-
0 commit comments