|
@@ -16,12 +16,12 @@ import {
|
|
|
DataSourceApi,
|
|
DataSourceApi,
|
|
|
DataSourceInstanceSettings,
|
|
DataSourceInstanceSettings,
|
|
|
DataQueryError,
|
|
DataQueryError,
|
|
|
-} from '@grafana/ui/src/types';
|
|
|
|
|
|
|
+ LogRowModel,
|
|
|
|
|
+} from '@grafana/ui';
|
|
|
import { LokiQuery, LokiOptions } from './types';
|
|
import { LokiQuery, LokiOptions } from './types';
|
|
|
import { BackendSrv } from 'app/core/services/backend_srv';
|
|
import { BackendSrv } from 'app/core/services/backend_srv';
|
|
|
import { TemplateSrv } from 'app/features/templating/template_srv';
|
|
import { TemplateSrv } from 'app/features/templating/template_srv';
|
|
|
import { safeStringifyValue } from 'app/core/utils/explore';
|
|
import { safeStringifyValue } from 'app/core/utils/explore';
|
|
|
-import { LogRowModel } from 'app/core/logs_model';
|
|
|
|
|
|
|
|
|
|
export const DEFAULT_MAX_LINES = 1000;
|
|
export const DEFAULT_MAX_LINES = 1000;
|
|
|
|
|
|
|
@@ -41,6 +41,11 @@ function serializeParams(data: any) {
|
|
|
.join('&');
|
|
.join('&');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+interface LokiContextQueryOptions {
|
|
|
|
|
+ direction?: 'BACKWARD' | 'FORWARD';
|
|
|
|
|
+ limit?: number;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
|
|
export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
|
|
|
languageProvider: LanguageProvider;
|
|
languageProvider: LanguageProvider;
|
|
|
maxLines: number;
|
|
maxLines: number;
|
|
@@ -224,7 +229,7 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
|
|
|
return Math.ceil(date.valueOf() * 1e6);
|
|
return Math.ceil(date.valueOf() * 1e6);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- prepareLogRowContextQueryTargets = (row: LogRowModel, limit: number) => {
|
|
|
|
|
|
|
+ prepareLogRowContextQueryTarget = (row: LogRowModel, limit: number, direction: 'BACKWARD' | 'FORWARD') => {
|
|
|
const query = Object.keys(row.labels)
|
|
const query = Object.keys(row.labels)
|
|
|
.map(label => {
|
|
.map(label => {
|
|
|
return `${label}="${row.labels[label]}"`;
|
|
return `${label}="${row.labels[label]}"`;
|
|
@@ -236,69 +241,58 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
|
|
|
const commontTargetOptons = {
|
|
const commontTargetOptons = {
|
|
|
limit,
|
|
limit,
|
|
|
query: `{${query}}`,
|
|
query: `{${query}}`,
|
|
|
|
|
+ direction,
|
|
|
};
|
|
};
|
|
|
- return [
|
|
|
|
|
- // Target for "before" context
|
|
|
|
|
- {
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if (direction === 'BACKWARD') {
|
|
|
|
|
+ return {
|
|
|
...commontTargetOptons,
|
|
...commontTargetOptons,
|
|
|
start: timeEpochNs - contextTimeBuffer,
|
|
start: timeEpochNs - contextTimeBuffer,
|
|
|
end: timeEpochNs,
|
|
end: timeEpochNs,
|
|
|
- direction: 'BACKWARD',
|
|
|
|
|
- },
|
|
|
|
|
- // Target for "after" context
|
|
|
|
|
- {
|
|
|
|
|
|
|
+ direction,
|
|
|
|
|
+ };
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return {
|
|
|
...commontTargetOptons,
|
|
...commontTargetOptons,
|
|
|
start: timeEpochNs, // TODO: We should add 1ns here for the original row not no be included in the result
|
|
start: timeEpochNs, // TODO: We should add 1ns here for the original row not no be included in the result
|
|
|
end: timeEpochNs + contextTimeBuffer,
|
|
end: timeEpochNs + contextTimeBuffer,
|
|
|
- direction: 'FORWARD',
|
|
|
|
|
- },
|
|
|
|
|
- ];
|
|
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- getLogRowContext = (row: LogRowModel, limit?: number) => {
|
|
|
|
|
- // Preparing two targets, for preceeding and following log queries
|
|
|
|
|
- const targets = this.prepareLogRowContextQueryTargets(row, limit || 10);
|
|
|
|
|
-
|
|
|
|
|
- return Promise.all(
|
|
|
|
|
- targets.map(target => {
|
|
|
|
|
- return this._request('/api/prom/query', target).catch(e => {
|
|
|
|
|
- const error: DataQueryError = {
|
|
|
|
|
- message: 'Error during context query. Please check JS console logs.',
|
|
|
|
|
- status: e.status,
|
|
|
|
|
- statusText: e.statusText,
|
|
|
|
|
- };
|
|
|
|
|
- return error;
|
|
|
|
|
- });
|
|
|
|
|
- })
|
|
|
|
|
- ).then((results: any[]) => {
|
|
|
|
|
- const series: Array<Array<SeriesData | DataQueryError>> = [];
|
|
|
|
|
- const emptySeries = {
|
|
|
|
|
- fields: [],
|
|
|
|
|
- rows: [],
|
|
|
|
|
- } as SeriesData;
|
|
|
|
|
-
|
|
|
|
|
- for (let i = 0; i < results.length; i++) {
|
|
|
|
|
- const result = results[i];
|
|
|
|
|
- series[i] = [];
|
|
|
|
|
- if (result.data) {
|
|
|
|
|
- for (const stream of result.data.streams || []) {
|
|
|
|
|
- const seriesData = logStreamToSeriesData(stream);
|
|
|
|
|
- series[i].push(seriesData);
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- series[i].push(result);
|
|
|
|
|
|
|
+ getLogRowContext = async (row: LogRowModel, options?: LokiContextQueryOptions) => {
|
|
|
|
|
+ const target = this.prepareLogRowContextQueryTarget(
|
|
|
|
|
+ row,
|
|
|
|
|
+ (options && options.limit) || 10,
|
|
|
|
|
+ (options && options.direction) || 'BACKWARD'
|
|
|
|
|
+ );
|
|
|
|
|
+ const series: SeriesData[] = [];
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const result = await this._request('/api/prom/query', target);
|
|
|
|
|
+ if (result.data) {
|
|
|
|
|
+ for (const stream of result.data.streams || []) {
|
|
|
|
|
+ const seriesData = logStreamToSeriesData(stream);
|
|
|
|
|
+ series.push(seriesData);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // Following context logs are requested in "forward" direction.
|
|
|
|
|
- // This means, that we need to reverse those to make them sorted
|
|
|
|
|
- // in descending order (by timestamp)
|
|
|
|
|
- if (series[1][0] && (series[1][0] as SeriesData).rows) {
|
|
|
|
|
- (series[1][0] as SeriesData).rows.reverse();
|
|
|
|
|
|
|
+ if (options && options.direction === 'FORWARD') {
|
|
|
|
|
+ if (series[0] && series[0].rows) {
|
|
|
|
|
+ series[0].rows.reverse();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return { data: [series[0][0] || emptySeries, series[1][0] || emptySeries] };
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ return {
|
|
|
|
|
+ data: series,
|
|
|
|
|
+ };
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ const error: DataQueryError = {
|
|
|
|
|
+ message: 'Error during context query. Please check JS console logs.',
|
|
|
|
|
+ status: e.status,
|
|
|
|
|
+ statusText: e.statusText,
|
|
|
|
|
+ };
|
|
|
|
|
+ throw error;
|
|
|
|
|
+ }
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
testDatasource() {
|
|
testDatasource() {
|