|
|
|
|
@ -12,6 +12,8 @@ import { |
|
|
|
|
findUniqueLabels, |
|
|
|
|
FieldConfig, |
|
|
|
|
DataFrameView, |
|
|
|
|
DataLink, |
|
|
|
|
Field, |
|
|
|
|
} from '@grafana/data'; |
|
|
|
|
|
|
|
|
|
import templateSrv from 'app/features/templating/template_srv'; |
|
|
|
|
@ -28,6 +30,7 @@ import { |
|
|
|
|
LokiTailResponse, |
|
|
|
|
LokiQuery, |
|
|
|
|
LokiOptions, |
|
|
|
|
DerivedFieldConfig, |
|
|
|
|
} from './types'; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
@ -289,44 +292,50 @@ export const enhanceDataFrame = (dataFrame: DataFrame, config: LokiOptions | nul |
|
|
|
|
if (!derivedFields.length) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const fields = derivedFields.reduce((acc, field) => { |
|
|
|
|
const config: FieldConfig = {}; |
|
|
|
|
if (field.url || field.datasourceUid) { |
|
|
|
|
config.links = [ |
|
|
|
|
{ |
|
|
|
|
url: field.url, |
|
|
|
|
title: '', |
|
|
|
|
meta: field.datasourceUid |
|
|
|
|
? { |
|
|
|
|
datasourceUid: field.datasourceUid, |
|
|
|
|
} |
|
|
|
|
: undefined, |
|
|
|
|
}, |
|
|
|
|
]; |
|
|
|
|
} |
|
|
|
|
const dataFrameField = { |
|
|
|
|
name: field.name, |
|
|
|
|
type: FieldType.string, |
|
|
|
|
config, |
|
|
|
|
values: new ArrayVector<string>([]), |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
acc[field.name] = dataFrameField; |
|
|
|
|
return acc; |
|
|
|
|
}, {} as Record<string, any>); |
|
|
|
|
const newFields = derivedFields.map(fieldFromDerivedFieldConfig); |
|
|
|
|
const newFieldsMap = _.keyBy(newFields, 'name'); |
|
|
|
|
|
|
|
|
|
const view = new DataFrameView(dataFrame); |
|
|
|
|
view.forEach((row: { line: string }) => { |
|
|
|
|
for (const field of derivedFields) { |
|
|
|
|
const logMatch = row.line.match(field.matcherRegex); |
|
|
|
|
fields[field.name].values.add(logMatch && logMatch[1]); |
|
|
|
|
newFieldsMap[field.name].values.add(logMatch && logMatch[1]); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
dataFrame.fields = [...dataFrame.fields, ...Object.values(fields)]; |
|
|
|
|
dataFrame.fields = [...dataFrame.fields, ...newFields]; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Transform derivedField config into dataframe field with config that contains link. |
|
|
|
|
*/ |
|
|
|
|
function fieldFromDerivedFieldConfig(derivedFieldConfig: DerivedFieldConfig): Field<any, ArrayVector> { |
|
|
|
|
const config: FieldConfig = {}; |
|
|
|
|
if (derivedFieldConfig.url || derivedFieldConfig.datasourceUid) { |
|
|
|
|
const link: Partial<DataLink> = { |
|
|
|
|
// We do not know what title to give here so we count on presentation layer to create a title from metadata.
|
|
|
|
|
title: '', |
|
|
|
|
url: derivedFieldConfig.url, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Having field.datasourceUid means it is an internal link.
|
|
|
|
|
if (derivedFieldConfig.datasourceUid) { |
|
|
|
|
link.meta = { |
|
|
|
|
datasourceUid: derivedFieldConfig.datasourceUid, |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
config.links = [link as DataLink]; |
|
|
|
|
} |
|
|
|
|
return { |
|
|
|
|
name: derivedFieldConfig.name, |
|
|
|
|
type: FieldType.string, |
|
|
|
|
config, |
|
|
|
|
// We are adding values later on
|
|
|
|
|
values: new ArrayVector<string>([]), |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export function rangeQueryResponseToTimeSeries( |
|
|
|
|
response: LokiResponse, |
|
|
|
|
query: LokiRangeQueryRequest, |
|
|
|
|
|