2022-05-11 02:29:04 -05:00
|
|
|
import { groupBy } from 'lodash';
|
|
|
|
|
2023-04-20 09:59:18 -05:00
|
|
|
import { FieldType, DataFrame, DataLink, Field } from '@grafana/data';
|
2022-05-11 02:29:04 -05:00
|
|
|
import { getDataSourceSrv } from '@grafana/runtime';
|
|
|
|
|
|
|
|
import { DerivedFieldConfig } from './types';
|
|
|
|
|
|
|
|
export function getDerivedFields(dataFrame: DataFrame, derivedFieldConfigs: DerivedFieldConfig[]): Field[] {
|
|
|
|
if (!derivedFieldConfigs.length) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
const derivedFieldsGrouped = groupBy(derivedFieldConfigs, 'name');
|
|
|
|
|
|
|
|
const newFields = Object.values(derivedFieldsGrouped).map(fieldFromDerivedFieldConfig);
|
|
|
|
|
|
|
|
// line-field is the first string-field
|
|
|
|
// NOTE: we should create some common log-frame-extra-string-field code somewhere
|
|
|
|
const lineField = dataFrame.fields.find((f) => f.type === FieldType.string);
|
|
|
|
|
|
|
|
if (lineField === undefined) {
|
|
|
|
// if this is happening, something went wrong, let's raise an error
|
|
|
|
throw new Error('invalid logs-dataframe, string-field missing');
|
|
|
|
}
|
|
|
|
|
2023-04-20 09:59:18 -05:00
|
|
|
lineField.values.forEach((line) => {
|
2022-05-11 02:29:04 -05:00
|
|
|
for (const field of newFields) {
|
|
|
|
const logMatch = line.match(derivedFieldsGrouped[field.name][0].matcherRegex);
|
2023-04-21 00:03:38 -05:00
|
|
|
field.values.push(logMatch && logMatch[1]);
|
2022-05-11 02:29:04 -05:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return newFields;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Transform derivedField config into dataframe field with config that contains link.
|
|
|
|
*/
|
2023-04-20 09:59:18 -05:00
|
|
|
function fieldFromDerivedFieldConfig(derivedFieldConfigs: DerivedFieldConfig[]): Field {
|
2022-05-11 02:29:04 -05:00
|
|
|
const dataSourceSrv = getDataSourceSrv();
|
|
|
|
|
2023-02-09 03:03:13 -06:00
|
|
|
const dataLinks = derivedFieldConfigs.reduce<DataLink[]>((acc, derivedFieldConfig) => {
|
2022-05-11 02:29:04 -05:00
|
|
|
// Having field.datasourceUid means it is an internal link.
|
|
|
|
if (derivedFieldConfig.datasourceUid) {
|
|
|
|
const dsSettings = dataSourceSrv.getInstanceSettings(derivedFieldConfig.datasourceUid);
|
|
|
|
|
|
|
|
acc.push({
|
|
|
|
// Will be filled out later
|
|
|
|
title: derivedFieldConfig.urlDisplayLabel || '',
|
|
|
|
url: '',
|
|
|
|
// This is hardcoded for Jaeger or Zipkin not way right now to specify datasource specific query object
|
|
|
|
internal: {
|
2023-04-20 04:52:12 -05:00
|
|
|
query: { query: derivedFieldConfig.url, queryType: dsSettings?.type === 'tempo' ? 'traceql' : undefined },
|
2022-05-11 02:29:04 -05:00
|
|
|
datasourceUid: derivedFieldConfig.datasourceUid,
|
|
|
|
datasourceName: dsSettings?.name ?? 'Data source not found',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
} else if (derivedFieldConfig.url) {
|
|
|
|
acc.push({
|
|
|
|
// We do not know what title to give here so we count on presentation layer to create a title from metadata.
|
|
|
|
title: derivedFieldConfig.urlDisplayLabel || '',
|
|
|
|
// This is hardcoded for Jaeger or Zipkin not way right now to specify datasource specific query object
|
|
|
|
url: derivedFieldConfig.url,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return acc;
|
2023-02-09 03:03:13 -06:00
|
|
|
}, []);
|
2022-05-11 02:29:04 -05:00
|
|
|
|
|
|
|
return {
|
|
|
|
name: derivedFieldConfigs[0].name,
|
|
|
|
type: FieldType.string,
|
|
|
|
config: {
|
|
|
|
links: dataLinks,
|
|
|
|
},
|
|
|
|
// We are adding values later on
|
2023-04-20 09:59:18 -05:00
|
|
|
values: [],
|
2022-05-11 02:29:04 -05:00
|
|
|
};
|
|
|
|
}
|