@grafana/data#DataQueryResponse TypeScript Examples

The following examples show how to use @grafana/data#DataQueryResponse. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: datasource.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
runInstantQuery = (
    target: LokiQuery,
    options: DataQueryRequest<LokiQuery>,
    responseListLength: number
  ): Observable<DataQueryResponse> => {
    const timeNs = this.getTime(options.range.to, true);
    const query = {
      query: parseQuery(target.expr).query,
      time: `${timeNs + (1e9 - (timeNs % 1e9))}`,
      limit: Math.min(options.maxDataPoints || Infinity, this.maxLines),
    };

    return this._request(INSTANT_QUERY_ENDPOINT, query).pipe(
      catchError((err: any) => this.throwUnless(err, err.cancelled, target)),
      filter((response: any) => (response.cancelled ? false : true)),
      map((response: { data: LokiResponse }) => {
        if (response.data.data.resultType === LokiResultType.Stream) {
          throw new Error('Metrics mode does not support logs. Use an aggregation or switch to Logs mode.');
        }

        return {
          data: [lokiResultsToTableModel(response.data.data.result, responseListLength, target.refId, true)],
          key: `${target.refId}_instant`,
        };
      })
    );
  };
Example #2
Source File: datasource.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
private exploreQuery(queries: PromQueryRequest[], activeTargets: PromQuery[], end: number) {
    let runningQueriesCount = queries.length;
    const subQueries = queries.map((query, index) => {
      const target = activeTargets[index];
      let observable: Observable<any> = null;

      if (query.instant) {
        observable = from(this.performInstantQuery(query, end));
      } else {
        observable = from(this.performTimeSeriesQuery(query, query.start, query.end));
      }

      return observable.pipe(
        // Decrease the counter here. We assume that each request returns only single value and then completes
        // (should hold until there is some streaming requests involved).
        tap(() => runningQueriesCount--),
        filter((response: any) => (response.cancelled ? false : true)),
        map((response: any) => {
          const data = this.processResult(response, query, target, queries.length);
          return {
            data,
            key: query.requestId,
            state: runningQueriesCount === 0 ? LoadingState.Done : LoadingState.Loading,
          } as DataQueryResponse;
        })
      );
    });

    return merge(...subQueries);
  }
Example #3
Source File: datasource.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
async query(options: DataQueryRequest<StackdriverQuery>): Promise<DataQueryResponse> {
    const result: DataQueryResponse[] = [];
    const data = await this.getTimeSeries(options);
    if (data.results) {
      Object.values(data.results).forEach((queryRes: any) => {
        if (!queryRes.series) {
          return;
        }
        const unit = this.resolvePanelUnitFromTargets(options.targets);
        queryRes.series.forEach((series: any) => {
          let timeSerie: any = {
            target: series.name,
            datapoints: series.points,
            refId: queryRes.refId,
            meta: queryRes.meta,
          };
          if (unit) {
            timeSerie = { ...timeSerie, unit };
          }
          result.push(timeSerie);
        });
      });
      return { data: result };
    } else {
      return { data: [] };
    }
  }
Example #4
Source File: InputDatasource.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
query(options: DataQueryRequest<InputQuery>): Promise<DataQueryResponse> {
    const results: DataFrame[] = [];
    for (const query of options.targets) {
      if (query.hide) {
        continue;
      }
      let data = this.data;
      if (query.data) {
        data = query.data.map(v => toDataFrame(v));
      }
      for (let i = 0; i < data.length; i++) {
        results.push({
          ...data[i],
          refId: query.refId,
        });
      }
    }
    return Promise.resolve({ data: results });
  }
Example #5
Source File: datasource.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
convertResponseToDataFrames = (result: any): DataQueryResponse => {
    const data: DataFrame[] = [];
    if (!result || !result.data) {
      return { data };
    }
    // Series are either at the root or under a node called 'series'
    const series = result.data.series || result.data;
    if (!_.isArray(series)) {
      throw { message: 'Missing series in result', data: result };
    }

    for (let i = 0; i < series.length; i++) {
      const s = series[i];
      for (let y = 0; y < s.datapoints.length; y++) {
        s.datapoints[y][1] *= 1000;
      }
      const frame = toDataFrame(s);

      // Metrictank metadata
      if (s.meta) {
        frame.meta = {
          custom: {
            request: result.data.meta, // info for the whole request
            info: s.meta, // Array of metadata
          },
        };
      }
      data.push(frame);
    }
    return { data };
  };
Example #6
Source File: datasource.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
async query(options: DataQueryRequest<GraphiteQuery>): Promise<DataQueryResponse> {
    const graphOptions = {
      from: this.translateTime(options.rangeRaw.from, false, options.timezone),
      until: this.translateTime(options.rangeRaw.to, true, options.timezone),
      targets: options.targets,
      format: (options as any).format,
      cacheTimeout: options.cacheTimeout || this.cacheTimeout,
      maxDataPoints: options.maxDataPoints,
    };

    const params = this.buildGraphiteParams(graphOptions, options.scopedVars);
    if (params.length === 0) {
      return Promise.resolve({ data: [] });
    }

    if (this.isMetricTank) {
      params.push('meta=true');
    }

    const httpOptions: any = {
      method: 'POST',
      url: '/render',
      data: params.join('&'),
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
    };

    this.addTracingHeaders(httpOptions, options);

    if (options.panelId) {
      httpOptions.requestId = this.name + '.panelId.' + options.panelId;
    }

    return this.doGraphiteRequest(httpOptions).then(this.convertResponseToDataFrames);
  }
Example #7
Source File: datasource.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
runLegacyQuery = (
    target: LokiQuery,
    options: { range?: TimeRange; maxDataPoints?: number; reverse?: boolean }
  ): Observable<DataQueryResponse> => {
    if (target.liveStreaming) {
      return this.runLiveQuery(target, options);
    }

    const range = options.range
      ? { start: this.getTime(options.range.from, false), end: this.getTime(options.range.to, true) }
      : {};
    const query: LokiLegacyQueryRequest = {
      ...DEFAULT_QUERY_PARAMS,
      ...parseQuery(target.expr),
      ...range,
      limit: Math.min(options.maxDataPoints || Infinity, this.maxLines),
      refId: target.refId,
    };

    return this._request(LEGACY_QUERY_ENDPOINT, query).pipe(
      catchError((err: any) => this.throwUnless(err, err.cancelled, target)),
      filter((response: any) => !response.cancelled),
      map((response: { data: LokiLegacyStreamResponse }) => ({
        data: lokiLegacyStreamsToDataframes(
          response.data,
          query,
          this.maxLines,
          this.instanceSettings.jsonData,
          options.reverse
        ),
        key: `${target.refId}_log`,
      }))
    );
  };
Example #8
Source File: datasource.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
processQueryResult(queries: any, res: any): DataQueryResponse {
    const data: TestData[] = [];
    let error: DataQueryError | undefined = undefined;

    for (const query of queries) {
      const results = res.data.results[query.refId];

      for (const t of results.tables || []) {
        const table = t as TableData;
        table.refId = query.refId;
        table.name = query.alias;
        data.push(table);
      }

      for (const series of results.series || []) {
        data.push({ target: series.name, datapoints: series.points, refId: query.refId, tags: series.tags });
      }

      if (results.error) {
        error = {
          message: results.error,
        };
      }
    }

    return { data, error };
  }
Example #9
Source File: runStreams.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
export function runStream(target: TestDataQuery, req: DataQueryRequest<TestDataQuery>): Observable<DataQueryResponse> {
  const query = defaults(target.stream, defaultQuery);
  if ('signal' === query.type) {
    return runSignalStream(target, query, req);
  }
  if ('logs' === query.type) {
    return runLogsStream(target, query, req);
  }
  if ('fetch' === query.type) {
    return runFetchStream(target, query, req);
  }
  throw new Error(`Unknown Stream Type: ${query.type}`);
}
Example #10
Source File: metrics_panel_ctrl.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
handleQueryResult(result: DataQueryResponse) {
    this.loading = false;

    if (this.dashboard.snapshot) {
      this.panel.snapshotData = result.data;
    }

    if (!result || !result.data) {
      console.log('Data source query result invalid, missing data field:', result);
      result = { data: [] };
    }

    try {
      this.events.emit(PanelEvents.dataReceived, result.data);
    } catch (err) {
      this.processDataError(err);
    }
  }
Example #11
Source File: datasource.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
query(options: DataQueryRequest<PromQuery>): Observable<DataQueryResponse> {
    const start = this.getPrometheusTime(options.range.from, false);
    const end = this.getPrometheusTime(options.range.to, true);
    const { queries, activeTargets } = this.prepareTargets(options, start, end);

    // No valid targets, return the empty result to save a round trip.
    if (!queries || !queries.length) {
      return of({
        data: [],
        state: LoadingState.Done,
      });
    }

    if (options.app === CoreApp.Explore) {
      return this.exploreQuery(queries, activeTargets, end);
    }

    return this.panelsQuery(queries, activeTargets, end, options.requestId);
  }
Example #12
Source File: datasource.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
/**
   * Runs live queries which in this case means creating a websocket and listening on it for new logs.
   * This returns a bit different dataFrame than runQueries as it returns single dataframe even if there are multiple
   * Loki streams, sets only common labels on dataframe.labels and has additional dataframe.fields.labels for unique
   * labels per row.
   */
  runLiveQuery = (target: LokiQuery, options: { maxDataPoints?: number }): Observable<DataQueryResponse> => {
    const liveTarget = this.createLiveTarget(target, options);

    return from(this.getVersion()).pipe(
      mergeMap(version =>
        iif(
          () => version === 'v1',
          defer(() => this.streams.getStream(liveTarget)),
          defer(() => {
            const legacyTarget = this.createLegacyLiveTarget(target, options);
            return this.streams.getLegacyStream(legacyTarget);
          })
        )
      ),
      map(data => ({
        data,
        key: `loki-${liveTarget.refId}`,
        state: LoadingState.Streaming,
      }))
    );
  };
Example #13
Source File: datasource_srv.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
query(request: DataQueryRequest): Promise<DataQueryResponse> {
    if (this.queryResolver) {
      return this.queryResolver;
    }
    return new Promise(resolver => {
      setTimeout(() => {
        resolver(this.result);
      });
    });
  }
Example #14
Source File: runRequest.test.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
reset() {
    this.wasStarted = false;
    this.isUnsubbed = false;

    this.results = [];
    this.request = {
      range: {
        from: this.fromStartTime,
        to: this.toStartTime,
        raw: { from: '1h', to: 'now' },
      },
      targets: [
        {
          refId: 'A',
        },
      ],
    } as DataQueryRequest;

    this.ds = {
      query: (request: DataQueryRequest) => {
        return new Observable<DataQueryResponse>(subscriber => {
          this.subscriber = subscriber;
          this.wasStarted = true;

          if (this.error) {
            throw this.error;
          }

          return () => {
            this.isUnsubbed = true;
          };
        });
      },
    } as DataSourceApi;
  }
Example #15
Source File: MixedDataSource.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
query(request: DataQueryRequest<DataQuery>): Observable<DataQueryResponse> {
    // Remove any invalid queries
    const queries = request.targets.filter(t => {
      return t.datasource !== MIXED_DATASOURCE_NAME;
    });

    if (!queries.length) {
      return of({ data: [] } as DataQueryResponse); // nothing
    }

    // Build groups of queries to run in parallel
    const sets: { [key: string]: DataQuery[] } = groupBy(queries, 'datasource');
    const mixed: BatchedQueries[] = [];
    for (const key in sets) {
      const targets = sets[key];
      const dsName = targets[0].datasource;
      mixed.push({
        datasource: getDataSourceSrv().get(dsName),
        targets,
      });
    }
    return this.batchQueries(mixed, request);
  }
Example #16
Source File: MixedDataSource.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
batchQueries(mixed: BatchedQueries[], request: DataQueryRequest<DataQuery>): Observable<DataQueryResponse> {
    const runningQueries = mixed.filter(this.isQueryable).map((query, i) =>
      from(query.datasource).pipe(
        mergeMap((api: DataSourceApi) => {
          const dsRequest = cloneDeep(request);
          dsRequest.requestId = `mixed-${i}-${dsRequest.requestId || ''}`;
          dsRequest.targets = query.targets;

          return from(api.query(dsRequest)).pipe(
            map(response => {
              return {
                ...response,
                data: response.data || [],
                state: LoadingState.Loading,
                key: `mixed-${i}-${response.key || ''}`,
              } as DataQueryResponse;
            })
          );
        })
      )
    );

    return forkJoin(runningQueries).pipe(map(this.markAsDone), mergeAll());
  }
Example #17
Source File: DataSourceWithBackend.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
/**
   * This makes the arrow library loading async.
   */
  async toDataQueryResponse(rsp: any): Promise<DataQueryResponse> {
    const { resultsToDataFrames } = await import(
      /* webpackChunkName: "apache-arrow-util" */ '@grafana/data/src/dataframe/ArrowDataFrame'
    );
    return { data: resultsToDataFrames(rsp) };
  }
Example #18
Source File: MixedDataSource.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
private markAsDone(responses: DataQueryResponse[]): DataQueryResponse[] {
    const { length } = responses;

    if (length === 0) {
      return responses;
    }

    responses[length - 1].state = LoadingState.Done;
    return responses;
  }
Example #19
Source File: datasource.ts    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
query(options: DataQueryRequest<TestDataQuery>): Observable<DataQueryResponse> {
    const queries: any[] = [];
    const streams: Array<Observable<DataQueryResponse>> = [];

    // Start streams and prepare queries
    for (const target of options.targets) {
      if (target.hide) {
        continue;
      }
      if (target.scenarioId === 'streaming_client') {
        streams.push(runStream(target, options));
      } else {
        queries.push({
          ...target,
          intervalMs: options.intervalMs,
          maxDataPoints: options.maxDataPoints,
          datasourceId: this.id,
          alias: templateSrv.replace(target.alias || ''),
        });
      }
    }

    if (queries.length) {
      const req: Promise<DataQueryResponse> = getBackendSrv()
        .datasourceRequest({
          method: 'POST',
          url: '/api/tsdb/query',
          data: {
            from: options.range.from.valueOf().toString(),
            to: options.range.to.valueOf().toString(),
            queries: queries,
          },
          // This sets up a cancel token
          requestId: options.requestId,
        })
        .then((res: any) => this.processQueryResult(queries, res));

      streams.push(from(req));
    }

    return merge(...streams);
  }
Example #20
Source File: datasource_srv.ts    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
queryResolver: Promise<DataQueryResponse>;
Example #21
Source File: runStreams.ts    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
export function runSignalStream(
  target: TestDataQuery,
  query: StreamingQuery,
  req: DataQueryRequest<TestDataQuery>
): Observable<DataQueryResponse> {
  return new Observable<DataQueryResponse>(subscriber => {
    const streamId = `signal-${req.panelId}-${target.refId}`;
    const maxDataPoints = req.maxDataPoints || 1000;

    const data = new CircularDataFrame({
      append: 'tail',
      capacity: maxDataPoints,
    });
    data.refId = target.refId;
    data.name = target.alias || 'Signal ' + target.refId;
    data.addField({ name: 'time', type: FieldType.time });
    data.addField({ name: 'value', type: FieldType.number });

    const { spread, speed, bands, noise } = query;

    for (let i = 0; i < bands; i++) {
      const suffix = bands > 1 ? ` ${i + 1}` : '';
      data.addField({ name: 'Min' + suffix, type: FieldType.number });
      data.addField({ name: 'Max' + suffix, type: FieldType.number });
    }

    let value = Math.random() * 100;
    let timeoutId: any = null;

    const addNextRow = (time: number) => {
      value += (Math.random() - 0.5) * spread;

      let idx = 0;
      data.fields[idx++].values.add(time);
      data.fields[idx++].values.add(value);

      let min = value;
      let max = value;

      for (let i = 0; i < bands; i++) {
        min = min - Math.random() * noise;
        max = max + Math.random() * noise;

        data.fields[idx++].values.add(min);
        data.fields[idx++].values.add(max);
      }
    };

    // Fill the buffer on init
    if (true) {
      let time = Date.now() - maxDataPoints * speed;
      for (let i = 0; i < maxDataPoints; i++) {
        addNextRow(time);
        time += speed;
      }
    }

    const pushNextEvent = () => {
      addNextRow(Date.now());
      subscriber.next({
        data: [data],
        key: streamId,
      });

      timeoutId = setTimeout(pushNextEvent, speed);
    };

    // Send first event in 5ms
    setTimeout(pushNextEvent, 5);

    return () => {
      console.log('unsubscribing to stream ' + streamId);
      clearTimeout(timeoutId);
    };
  });
}
Example #22
Source File: runStreams.ts    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
export function runLogsStream(
  target: TestDataQuery,
  query: StreamingQuery,
  req: DataQueryRequest<TestDataQuery>
): Observable<DataQueryResponse> {
  return new Observable<DataQueryResponse>(subscriber => {
    const streamId = `logs-${req.panelId}-${target.refId}`;
    const maxDataPoints = req.maxDataPoints || 1000;

    const data = new CircularDataFrame({
      append: 'tail',
      capacity: maxDataPoints,
    });
    data.refId = target.refId;
    data.name = target.alias || 'Logs ' + target.refId;
    data.addField({ name: 'time', type: FieldType.time });
    data.addField({ name: 'line', type: FieldType.string });

    const { speed } = query;

    let timeoutId: any = null;

    const pushNextEvent = () => {
      data.values.time.add(Date.now());
      data.values.line.add(getRandomLine());

      subscriber.next({
        data: [data],
        key: streamId,
      });

      timeoutId = setTimeout(pushNextEvent, speed);
    };

    // Send first event in 5ms
    setTimeout(pushNextEvent, 5);

    return () => {
      console.log('unsubscribing to stream ' + streamId);
      clearTimeout(timeoutId);
    };
  });
}
Example #23
Source File: runStreams.ts    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
export function runFetchStream(
  target: TestDataQuery,
  query: StreamingQuery,
  req: DataQueryRequest<TestDataQuery>
): Observable<DataQueryResponse> {
  return new Observable<DataQueryResponse>(subscriber => {
    const streamId = `fetch-${req.panelId}-${target.refId}`;
    const maxDataPoints = req.maxDataPoints || 1000;

    let data = new CircularDataFrame({
      append: 'tail',
      capacity: maxDataPoints,
    });
    data.refId = target.refId;
    data.name = target.alias || 'Fetch ' + target.refId;

    let reader: ReadableStreamReader<Uint8Array>;
    const csv = new CSVReader({
      callback: {
        onHeader: (fields: Field[]) => {
          // Clear any existing fields
          if (data.fields.length) {
            data = new CircularDataFrame({
              append: 'tail',
              capacity: maxDataPoints,
            });
            data.refId = target.refId;
            data.name = 'Fetch ' + target.refId;
          }
          for (const field of fields) {
            data.addField(field);
          }
        },
        onRow: (row: any[]) => {
          data.add(row);
        },
      },
    });

    const processChunk = (value: ReadableStreamReadResult<Uint8Array>): any => {
      if (value.value) {
        const text = new TextDecoder().decode(value.value);
        csv.readCSV(text);
      }

      subscriber.next({
        data: [data],
        key: streamId,
        state: value.done ? LoadingState.Done : LoadingState.Streaming,
      });

      if (value.done) {
        console.log('Finished stream');
        subscriber.complete(); // necessary?
        return;
      }

      return reader.read().then(processChunk);
    };

    fetch(new Request(query.url)).then(response => {
      reader = response.body.getReader();
      reader.read().then(processChunk);
    });

    return () => {
      // Cancel fetch?
      console.log('unsubscribing to stream ' + streamId);
    };
  });
}
Example #24
Source File: datasource_srv.ts    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
constructor(name?: string, result?: DataQueryResponse, meta?: any) {
    super({ name: name ? name : 'MockDataSourceApi' } as DataSourceInstanceSettings);
    if (result) {
      this.result = result;
    }

    this.meta = meta || ({} as DataSourcePluginMeta);
  }
Example #25
Source File: datasource_srv.ts    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
result: DataQueryResponse = { data: [] };
Example #26
Source File: datasource.ts    From grafana-kdb-datasource-ws with Apache License 2.0 5 votes vote down vote up
query(options: DataQueryRequest<MyQuery>): Promise<DataQueryResponse> {
    var prefilterResultCount = options.targets.length;

    if (prefilterResultCount == 0) {
      return new Promise((resolve) => {
        resolve({ data: [] });
      });
    }

    var allRefIDs = [];
    var blankRefIDs = [];
    var validRequestList = [];
    var errorList = [];

    for (var i = 0; i < prefilterResultCount; i++) {
      //Inject variables into target
      this.injectVariables(options.targets[i], options.scopedVars, options.range);

      // for some reason randomWalk is defaulted
      if (options.targets[i].queryType == 'randomWalk') {
        options.targets[i].queryType = 'selectQuery';
      }
      allRefIDs.push(options.targets[i].refId);
      options.targets[i].range = options.range;
      if (
        (!options.targets[i].table && options.targets[i].queryType === 'selectQuery') ||
        (options.targets[i].queryType === 'functionQuery' && options.targets[i].kdbFunction === '') ||
        options.targets[i].hide === true
      ) {
        blankRefIDs.push(options.targets[i].refId);
      } else if (!options.targets[i].queryError) {
        blankRefIDs.push(options.targets[i].refId);
      } else if (options.targets[i].queryError.error.indexOf(true) !== -1) {
        errorList.push({
          refId: options.targets[i].refId,
          errorMessage: options.targets[i].queryError.message[options.targets[i].queryError.error.indexOf(true)],
        });
      } else validRequestList.push(options.targets[i]);
    }

    var nrBlankRequests = blankRefIDs.length;
    var requestList = validRequestList.map((target) => {
      return this.buildKdbRequest(target);
    });

    var nrRequests: number = requestList.length;
    if (!this.ws || this.ws.readyState > 1)
      return this.connectWS().then((connectStatus) => {
        if (connectStatus === true && nrRequests > 0)
          return this.sendQueries(nrRequests, requestList, nrBlankRequests, blankRefIDs, errorList).then(
            (series: any) => {
              return this.buildDataFrames(series);
            }
          );
        else if (connectStatus === true && nrRequests === 0)
          return this.emptyQueries(nrBlankRequests, blankRefIDs, errorList).then(() => {
            return { data: [] };
          });
        else
          return this.connectFail(prefilterResultCount, allRefIDs).then(() => {
            return { data: [] };
          });
      });
    else {
      return this.webSocketWait().then(() => {
        if (nrRequests > 0)
          return this.sendQueries(nrRequests, requestList, nrBlankRequests, blankRefIDs, errorList).then(
            (series: any) => {
              return this.buildDataFrames(series);
            }
          );
        else
          return this.emptyQueries(nrBlankRequests, blankRefIDs, errorList).then(() => {
            return { data: [] };
          });
      });
    }
  }
Example #27
Source File: datasource.ts    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
/**
   * Attempts to send a query to /loki/api/v1/query_range but falls back to the legacy endpoint if necessary.
   */
  runRangeQueryWithFallback = (
    target: LokiQuery,
    options: RangeQueryOptions,
    responseListLength = 1
  ): Observable<DataQueryResponse> => {
    // target.maxLines value already preprocessed
    // available cases:
    // 1) empty input -> mapped to NaN, falls back to dataSource.maxLines limit
    // 2) input with at least 1 character and that is either incorrect (value in the input field is not a number) or negative
    //    - mapped to 0, falls back to the limit of 0 lines
    // 3) default case - correct input, mapped to the value from the input field

    let linesLimit = 0;
    if (target.maxLines === undefined) {
      // no target.maxLines, using options.maxDataPoints
      linesLimit = Math.min(options.maxDataPoints || Infinity, this.maxLines);
    } else {
      // using target.maxLines
      if (isNaN(target.maxLines)) {
        linesLimit = this.maxLines;
      } else {
        linesLimit = target.maxLines;
      }
    }

    const queryOptions = { ...options, maxDataPoints: linesLimit };
    if (target.liveStreaming) {
      return this.runLiveQuery(target, queryOptions);
    }
    const query = this.createRangeQuery(target, queryOptions);
    return this._request(RANGE_QUERY_ENDPOINT, query).pipe(
      catchError((err: any) => this.throwUnless(err, err.cancelled || err.status === 404, target)),
      filter((response: any) => (response.cancelled ? false : true)),
      switchMap((response: { data: LokiResponse; status: number }) =>
        iif<DataQueryResponse, DataQueryResponse>(
          () => response.status === 404,
          defer(() => this.runLegacyQuery(target, queryOptions)),
          defer(() =>
            processRangeQueryResponse(
              response.data,
              target,
              query,
              responseListLength,
              linesLimit,
              this.instanceSettings.jsonData,
              options.reverse
            )
          )
        )
      )
    );
  };
Example #28
Source File: datasource.ts    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
testDatasource() {
    // Consider only last 10 minutes otherwise request takes too long
    const startMs = Date.now() - 10 * 60 * 1000;
    const start = `${startMs}000000`; // API expects nanoseconds
    return this._request('/loki/api/v1/label', { start })
      .pipe(
        catchError((err: any) => {
          if (err.status === 404) {
            return of(err);
          }

          throw err;
        }),
        switchMap((response: { data: { values: string[] }; status: number }) =>
          iif<DataQueryResponse, any>(
            () => response.status === 404,
            defer(() => this._request('/api/prom/label', { start })),
            defer(() => of(response))
          )
        ),
        map(res => {
          const values: any[] = res?.data?.data || res?.data?.values || [];
          const testResult =
            values.length > 0
              ? { status: 'success', message: 'Data source connected and labels found.' }
              : {
                  status: 'error',
                  message:
                    'Data source connected, but no labels received. Verify that Loki and Promtail is configured properly.',
                };
          return testResult;
        }),
        catchError((err: any) => {
          let message = 'Loki: ';
          if (err.statusText) {
            message += err.statusText;
          } else {
            message += 'Cannot connect to Loki';
          }

          if (err.status) {
            message += `. ${err.status}`;
          }

          if (err.data && err.data.message) {
            message += `. ${err.data.message}`;
          } else if (err.data) {
            message += `. ${err.data}`;
          }
          return of({ status: 'error', message: message });
        })
      )
      .toPromise();
  }
Example #29
Source File: datasource.ts    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
query(options: DataQueryRequest<LokiQuery>): Observable<DataQueryResponse> {
    const subQueries: Array<Observable<DataQueryResponse>> = [];
    const filteredTargets = options.targets
      .filter(target => target.expr && !target.hide)
      .map(target => ({
        ...target,
        expr: this.templateSrv.replace(target.expr, options.scopedVars, this.interpolateQueryExpr),
      }));

    if (options.exploreMode === ExploreMode.Metrics) {
      filteredTargets.forEach(target =>
        subQueries.push(
          this.runInstantQuery(target, options, filteredTargets.length),
          this.runRangeQueryWithFallback(target, options, filteredTargets.length)
        )
      );
    } else {
      filteredTargets.forEach(target =>
        subQueries.push(
          this.runRangeQueryWithFallback(target, options, filteredTargets.length).pipe(
            map(dataQueryResponse => {
              if (options.exploreMode === ExploreMode.Logs && dataQueryResponse.data.find(d => isTimeSeries(d))) {
                throw new Error(
                  'Logs mode does not support queries that return time series data. Please perform a logs query or switch to Metrics mode.'
                );
              } else {
                return dataQueryResponse;
              }
            })
          )
        )
      );
    }

    // No valid targets, return the empty result to save a round trip.
    if (isEmpty(subQueries)) {
      return of({
        data: [],
        state: LoadingState.Done,
      });
    }

    return merge(...subQueries);
  }