/usr/share/grafana/public/app/plugins/datasource/loki
import { groupBy } from 'lodash'; import { FieldType, DataFrame, DataLink, Field } from '@grafana/data'; 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'); } const labelFields = dataFrame.fields.find((f) => f.type === FieldType.other && f.name === 'labels'); for (let i = 0; i < lineField.values.length; i++) { for (const field of newFields) { // `matcherRegex` can be either a RegExp that is used to extract the value from the log line, or it can be a label key to derive the field from the labels if (derivedFieldsGrouped[field.name][0].matcherType === 'label' && labelFields) { const label = labelFields.values[i]; if (label) { // Find the key that matches the regex pattern in `matcherRegex` const intersectingKey = Object.keys(label).find((key) => { const regex = new RegExp(derivedFieldsGrouped[field.name][0].matcherRegex); return regex.test(key); }); if (intersectingKey) { field.values.push(label[intersectingKey]); continue; } } field.values.push(null); } else if ( derivedFieldsGrouped[field.name][0].matcherType === 'regex' || derivedFieldsGrouped[field.name][0].matcherType === undefined ) { // `matcherRegex` will actually be used as a RegExp here const line = lineField.values[i]; const logMatch = line.match(derivedFieldsGrouped[field.name][0].matcherRegex); if (logMatch && logMatch[1]) { field.values.push(logMatch[1]); continue; } field.values.push(null); } else { field.values.push(null); } } } return newFields; } /** * Transform derivedField config into dataframe field with config that contains link. */ function fieldFromDerivedFieldConfig(derivedFieldConfigs: DerivedFieldConfig[]): Field { const dataSourceSrv = getDataSourceSrv(); const dataLinks = derivedFieldConfigs.reduce<DataLink[]>((acc, derivedFieldConfig) => { // Having field.datasourceUid means it is an internal link. if (derivedFieldConfig.datasourceUid) { const dsSettings = dataSourceSrv.getInstanceSettings(derivedFieldConfig.datasourceUid); const queryType = (type: string | undefined): string | undefined => { switch (type) { case 'tempo': return 'traceql'; case 'grafana-x-ray-datasource': return 'getTrace'; default: return undefined; } }; 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: { query: { query: derivedFieldConfig.url, queryType: queryType(dsSettings?.type) }, datasourceUid: derivedFieldConfig.datasourceUid, datasourceName: dsSettings?.name ?? 'Data source not found', }, targetBlank: derivedFieldConfig.targetBlank, }); } 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, targetBlank: derivedFieldConfig.targetBlank, }); } return acc; }, []); return { name: derivedFieldConfigs[0].name, type: FieldType.string, config: { links: dataLinks, }, // We are adding values later on values: [], }; }
.
Edit
..
Edit
CHANGELOG.md
Edit
LanguageProvider.test.ts
Edit
LanguageProvider.ts
Edit
LiveStreams.test.ts
Edit
LiveStreams.ts
Edit
LogContextProvider.test.ts
Edit
LogContextProvider.ts
Edit
LokiVariableSupport.test.ts
Edit
LokiVariableSupport.ts
Edit
README.md
Edit
backendResultTransformer.test.ts
Edit
backendResultTransformer.ts
Edit
components
Edit
configuration
Edit
dataquery.cue
Edit
dataquery.gen.ts
Edit
datasource.test.ts
Edit
datasource.ts
Edit
dist
Edit
docs
Edit
getDerivedFields.test.ts
Edit
getDerivedFields.ts
Edit
img
Edit
jest-setup.js
Edit
jest.config.js
Edit
languageUtils.test.ts
Edit
languageUtils.ts
Edit
language_utils.test.ts
Edit
lineParser.test.ts
Edit
lineParser.ts
Edit
liveStreamsResultTransformer.test.ts
Edit
liveStreamsResultTransformer.ts
Edit
logsTimeSplitting.test.ts
Edit
logsTimeSplitting.ts
Edit
makeTableFrames.test.ts
Edit
makeTableFrames.ts
Edit
mergeResponses.test.ts
Edit
mergeResponses.ts
Edit
metricTimeSplitting.test.ts
Edit
metricTimeSplitting.ts
Edit
migrations
Edit
mocks
Edit
modifyQuery.test.ts
Edit
modifyQuery.ts
Edit
module.test.ts
Edit
module.ts
Edit
package.json
Edit
plugin.json
Edit
project.json
Edit
queryHints.test.ts
Edit
queryHints.ts
Edit
querySplitting.test.ts
Edit
querySplitting.ts
Edit
queryUtils.test.ts
Edit
queryUtils.ts
Edit
querybuilder
Edit
responseUtils.test.ts
Edit
responseUtils.ts
Edit
shardQuerySplitting.test.ts
Edit
shardQuerySplitting.ts
Edit
sortDataFrame.test.ts
Edit
sortDataFrame.ts
Edit
streaming.test.ts
Edit
streaming.ts
Edit
syntax.test.ts
Edit
syntax.ts
Edit
tracking.test.ts
Edit
tracking.ts
Edit
tsconfig.json
Edit
types.ts
Edit
webpack.config.ts
Edit