diff --git a/packages/grafana-ui/src/components/Logs/LogDetails.tsx b/packages/grafana-ui/src/components/Logs/LogDetails.tsx index 56632c54746..95856b9fb1c 100644 --- a/packages/grafana-ui/src/components/Logs/LogDetails.tsx +++ b/packages/grafana-ui/src/components/Logs/LogDetails.tsx @@ -106,6 +106,10 @@ class UnThemedLogDetails extends PureComponent { ); }); + /** + * Returns all fields for log row which consists of fields we parse from the message itself and any derived fields + * setup in data source config. + */ getAllFields = memoizeOne((row: LogRowModel) => { const fields = this.parseMessage(row.entry); const derivedFields = this.getDerivedFields(row); @@ -121,18 +125,10 @@ class UnThemedLogDetails extends PureComponent { } return acc; }, {} as { [key: string]: FieldDef }); + const allFields = Object.values(fieldsMap); - allFields.sort((fieldA, fieldB) => { - if (fieldA.links?.length && !fieldB.links?.length) { - return -1; - } + allFields.sort(sortFieldsLinkFirst); - if (!fieldA.links?.length && fieldB.links?.length) { - return 1; - } - - return fieldA.key > fieldB.key ? 1 : fieldA.key < fieldB.key ? -1 : 0; - }); return allFields; }); @@ -233,5 +229,15 @@ class UnThemedLogDetails extends PureComponent { } } +function sortFieldsLinkFirst(fieldA: FieldDef, fieldB: FieldDef) { + if (fieldA.links?.length && !fieldB.links?.length) { + return -1; + } + if (!fieldA.links?.length && fieldB.links?.length) { + return 1; + } + return fieldA.key > fieldB.key ? 1 : fieldA.key < fieldB.key ? -1 : 0; +} + export const LogDetails = withTheme(UnThemedLogDetails); LogDetails.displayName = 'LogDetails'; diff --git a/public/app/features/explore/utils/links.ts b/public/app/features/explore/utils/links.ts index 5be70302455..fd1a9e17918 100644 --- a/public/app/features/explore/utils/links.ts +++ b/public/app/features/explore/utils/links.ts @@ -5,7 +5,7 @@ import { serializeStateToUrlParam } from '../../../core/utils/explore'; import { getDataSourceSrv } from '@grafana/runtime'; /** - * Get links from the filed of a dataframe that was given to as and in addition check if there is associated + * Get links from the field of a dataframe and in addition check if there is associated * metadata with datasource in which case we will add onClick to open the link in new split window. This assumes * that we just supply datasource name and field value and Explore split window will know how to render that * appropriately. This is for example used for transition from log with traceId to trace datasource to show that diff --git a/public/app/plugins/datasource/loki/result_transformer.test.ts b/public/app/plugins/datasource/loki/result_transformer.test.ts index daf6b268606..14c4199aa99 100644 --- a/public/app/plugins/datasource/loki/result_transformer.test.ts +++ b/public/app/plugins/datasource/loki/result_transformer.test.ts @@ -131,6 +131,11 @@ describe('enhanceDataFrame', () => { name: 'trace2', datasourceUid: 'uid', }, + { + matcherRegex: 'trace2=(\\w+)', + name: 'trace2', + datasourceUid: 'uid2', + }, ], }); expect(df.fields.length).toBe(3); @@ -142,9 +147,14 @@ describe('enhanceDataFrame', () => { }); expect(fc.getFieldByName('trace2').values.toArray()).toEqual([null, null, 'foo']); + expect(fc.getFieldByName('trace2').config.links.length).toBe(2); expect(fc.getFieldByName('trace2').config.links[0]).toEqual({ title: '', meta: { datasourceUid: 'uid' }, }); + expect(fc.getFieldByName('trace2').config.links[1]).toEqual({ + title: '', + meta: { datasourceUid: 'uid2' }, + }); }); }); diff --git a/public/app/plugins/datasource/loki/result_transformer.ts b/public/app/plugins/datasource/loki/result_transformer.ts index e610f53bea7..c986ac4c065 100644 --- a/public/app/plugins/datasource/loki/result_transformer.ts +++ b/public/app/plugins/datasource/loki/result_transformer.ts @@ -10,7 +10,6 @@ import { ArrayVector, MutableDataFrame, findUniqueLabels, - FieldConfig, DataFrameView, DataLink, Field, @@ -332,14 +331,15 @@ export const enhanceDataFrame = (dataFrame: DataFrame, config: LokiOptions | nul if (!derivedFields.length) { return; } - const newFields = derivedFields.map(fieldFromDerivedFieldConfig); - const newFieldsMap = _.keyBy(newFields, 'name'); + const derivedFieldsGrouped = _.groupBy(derivedFields, 'name'); + + const newFields = Object.values(derivedFieldsGrouped).map(fieldFromDerivedFieldConfig); const view = new DataFrameView(dataFrame); view.forEach((row: { line: string }) => { - for (const field of derivedFields) { - const logMatch = row.line.match(field.matcherRegex); - newFieldsMap[field.name].values.add(logMatch && logMatch[1]); + for (const field of newFields) { + const logMatch = row.line.match(derivedFieldsGrouped[field.name][0].matcherRegex); + field.values.add(logMatch && logMatch[1]); } }); @@ -349,28 +349,30 @@ export const enhanceDataFrame = (dataFrame: DataFrame, config: LokiOptions | nul /** * Transform derivedField config into dataframe field with config that contains link. */ -function fieldFromDerivedFieldConfig(derivedFieldConfig: DerivedFieldConfig): Field { - const config: FieldConfig = {}; - if (derivedFieldConfig.url || derivedFieldConfig.datasourceUid) { - const link: Partial = { - // 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, - }; +function fieldFromDerivedFieldConfig(derivedFieldConfigs: DerivedFieldConfig[]): Field { + const dataLinks = derivedFieldConfigs.reduce((acc, derivedFieldConfig) => { + if (derivedFieldConfig.url || derivedFieldConfig.datasourceUid) { + acc.push({ + // 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. + meta: derivedFieldConfig.datasourceUid + ? { + datasourceUid: derivedFieldConfig.datasourceUid, + } + : undefined, + }); } + return acc; + }, [] as DataLink[]); - config.links = [link as DataLink]; - } return { - name: derivedFieldConfig.name, + name: derivedFieldConfigs[0].name, type: FieldType.string, - config, + config: { + links: dataLinks, + }, // We are adding values later on values: new ArrayVector([]), }; diff --git a/scripts/ci-frontend-metrics.sh b/scripts/ci-frontend-metrics.sh index 7167da0978f..da20c528517 100755 --- a/scripts/ci-frontend-metrics.sh +++ b/scripts/ci-frontend-metrics.sh @@ -4,7 +4,7 @@ echo -e "Collecting code stats (typescript errors & more)" -ERROR_COUNT_LIMIT=728 +ERROR_COUNT_LIMIT=726 DIRECTIVES_LIMIT=172 CONTROLLERS_LIMIT=139