diff --git a/.betterer.results b/.betterer.results index 9c7d33abd00..eb523e906fe 100644 --- a/.betterer.results +++ b/.betterer.results @@ -3475,8 +3475,7 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "0"] ], "public/app/features/explore/TraceView/components/model/link-patterns.test.ts:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"], - [0, 0, 0, "Unexpected any. Specify a different type.", "1"] + [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], "public/app/features/explore/TraceView/components/model/link-patterns.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], @@ -3490,8 +3489,7 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "8"], [0, 0, 0, "Do not use any type assertions.", "9"], [0, 0, 0, "Unexpected any. Specify a different type.", "10"], - [0, 0, 0, "Do not use any type assertions.", "11"], - [0, 0, 0, "Unexpected any. Specify a different type.", "12"] + [0, 0, 0, "Do not use any type assertions.", "11"] ], "public/app/features/explore/TraceView/components/model/transform-trace-data.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] diff --git a/public/app/features/explore/TraceView/components/model/link-patterns.test.ts b/public/app/features/explore/TraceView/components/model/link-patterns.test.ts index d31063ffc7c..8ddcd4516f0 100644 --- a/public/app/features/explore/TraceView/components/model/link-patterns.test.ts +++ b/public/app/features/explore/TraceView/components/model/link-patterns.test.ts @@ -12,17 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Trace, TraceLink, TraceSpan } from '../types'; +import { Trace } from '../types'; import { processTemplate, createTestFunction, - getParameterInArray, - getParameterInAncestor, processLinkPattern, ProcessedLinkPattern, - computeLinks, - createGetLinks, computeTraceLink, } from './link-patterns'; @@ -153,179 +149,6 @@ describe('createTestFunction()', () => { }); }); -describe('getParameterInArray()', () => { - const data = [ - { key: 'mykey', value: 'ok' }, - { key: 'otherkey', value: 'v' }, - ]; - - it('returns an entry that is present', () => { - expect(getParameterInArray('mykey', data)).toBe(data[0]); - expect(getParameterInArray('otherkey', data)).toBe(data[1]); - }); - - it('returns undefined when the entry cannot be found', () => { - expect(getParameterInArray('myotherkey', data)).toBeUndefined(); - }); - - it('returns undefined when there is no array', () => { - expect(getParameterInArray('otherkey')).toBeUndefined(); - expect(getParameterInArray('otherkey', null)).toBeUndefined(); - }); -}); - -describe('getParameterInAncestor()', () => { - const spans = [ - { - depth: 0, - process: { - tags: [ - { key: 'a', value: 'a7' }, - { key: 'b', value: 'b7' }, - { key: 'c', value: 'c7' }, - { key: 'd', value: 'd7' }, - { key: 'e', value: 'e7' }, - { key: 'f', value: 'f7' }, - { key: 'g', value: 'g7' }, - { key: 'h', value: 'h7' }, - ], - }, - tags: [ - { key: 'a', value: 'a6' }, - { key: 'b', value: 'b6' }, - { key: 'c', value: 'c6' }, - { key: 'd', value: 'd6' }, - { key: 'e', value: 'e6' }, - { key: 'f', value: 'f6' }, - { key: 'g', value: 'g6' }, - ], - }, - { - depth: 1, - process: { - tags: [ - { key: 'a', value: 'a5' }, - { key: 'b', value: 'b5' }, - { key: 'c', value: 'c5' }, - { key: 'd', value: 'd5' }, - { key: 'e', value: 'e5' }, - { key: 'f', value: 'f5' }, - ], - }, - tags: [ - { key: 'a', value: 'a4' }, - { key: 'b', value: 'b4' }, - { key: 'c', value: 'c4' }, - { key: 'd', value: 'd4' }, - { key: 'e', value: 'e4' }, - ], - }, - { - depth: 1, - process: { - tags: [ - { key: 'a', value: 'a3' }, - { key: 'b', value: 'b3' }, - { key: 'c', value: 'c3' }, - { key: 'd', value: 'd3' }, - ], - }, - tags: [ - { key: 'a', value: 'a2' }, - { key: 'b', value: 'b2' }, - { key: 'c', value: 'c2' }, - ], - }, - { - depth: 2, - process: { - tags: [ - { key: 'a', value: 'a1' }, - { key: 'b', value: 'b1' }, - ], - }, - tags: [{ key: 'a', value: 'a0' }], - }, - ] as TraceSpan[]; - - spans[1].references = [ - { - spanID: 's1', - traceID: 't2', - refType: 'CHILD_OF', - span: spans[0], - }, - ]; - spans[2].references = [ - { - spanID: 's1', - traceID: 't2', - refType: 'CHILD_OF', - span: spans[0], - }, - ]; - spans[3].references = [ - { - spanID: 's1', - traceID: 't2', - refType: 'CHILD_OF', - span: spans[2], - }, - ]; - - it('uses current span tags', () => { - expect(getParameterInAncestor('a', spans[3])).toEqual({ key: 'a', value: 'a0' }); - expect(getParameterInAncestor('a', spans[2])).toEqual({ key: 'a', value: 'a2' }); - expect(getParameterInAncestor('a', spans[1])).toEqual({ key: 'a', value: 'a4' }); - expect(getParameterInAncestor('a', spans[0])).toEqual({ key: 'a', value: 'a6' }); - }); - - it('uses current span process tags', () => { - expect(getParameterInAncestor('b', spans[3])).toEqual({ key: 'b', value: 'b1' }); - expect(getParameterInAncestor('d', spans[2])).toEqual({ key: 'd', value: 'd3' }); - expect(getParameterInAncestor('f', spans[1])).toEqual({ key: 'f', value: 'f5' }); - expect(getParameterInAncestor('h', spans[0])).toEqual({ key: 'h', value: 'h7' }); - }); - - it('uses parent span tags', () => { - expect(getParameterInAncestor('c', spans[3])).toEqual({ key: 'c', value: 'c2' }); - expect(getParameterInAncestor('e', spans[2])).toEqual({ key: 'e', value: 'e6' }); - expect(getParameterInAncestor('f', spans[2])).toEqual({ key: 'f', value: 'f6' }); - expect(getParameterInAncestor('g', spans[2])).toEqual({ key: 'g', value: 'g6' }); - expect(getParameterInAncestor('g', spans[1])).toEqual({ key: 'g', value: 'g6' }); - }); - - it('uses parent span process tags', () => { - expect(getParameterInAncestor('d', spans[3])).toEqual({ key: 'd', value: 'd3' }); - expect(getParameterInAncestor('h', spans[2])).toEqual({ key: 'h', value: 'h7' }); - expect(getParameterInAncestor('h', spans[1])).toEqual({ key: 'h', value: 'h7' }); - }); - - it('uses grand-parent span tags', () => { - expect(getParameterInAncestor('e', spans[3])).toEqual({ key: 'e', value: 'e6' }); - expect(getParameterInAncestor('f', spans[3])).toEqual({ key: 'f', value: 'f6' }); - expect(getParameterInAncestor('g', spans[3])).toEqual({ key: 'g', value: 'g6' }); - }); - - it('uses grand-parent process tags', () => { - expect(getParameterInAncestor('h', spans[3])).toEqual({ key: 'h', value: 'h7' }); - }); - - it('returns undefined when the entry cannot be found', () => { - expect(getParameterInAncestor('i', spans[3])).toBeUndefined(); - }); - - it('does not break if some tags are not defined', () => { - const spansWithUndefinedTags = [ - { - depth: 0, - process: {}, - }, - ] as TraceSpan[]; - expect(getParameterInAncestor('a', spansWithUndefinedTags[0])).toBeUndefined(); - }); -}); - describe('computeTraceLink()', () => { const linkPatterns = [ { @@ -359,95 +182,3 @@ describe('computeTraceLink()', () => { ]); }); }); - -describe('computeLinks()', () => { - const linkPatterns = [ - { - type: 'tags', - key: 'myKey', - url: 'http://example.com/?myKey=#{myKey}', - text: 'first link (#{myKey})', - }, - { - key: 'myOtherKey', - url: 'http://example.com/?myKey=#{myOtherKey}&myKey=#{myKey}', - text: 'second link (#{myOtherKey})', - }, - ].map(processLinkPattern) as ProcessedLinkPattern[]; - - const spans = [ - { depth: 0, process: {}, tags: [{ key: 'myKey', value: 'valueOfMyKey' }] }, - { depth: 1, process: {}, logs: [{ fields: [{ key: 'myOtherKey', value: 'valueOfMy+Other+Key' }] }] }, - ] as unknown as TraceSpan[]; - spans[1].references = [ - { - spanID: 's1', - traceID: 't2', - refType: 'CHILD_OF', - span: spans[0], - }, - ]; - - it('correctly computes links', () => { - expect(computeLinks(linkPatterns, spans[0], spans[0].tags, 0)).toEqual([ - { - url: 'http://example.com/?myKey=valueOfMyKey', - text: 'first link (valueOfMyKey)', - }, - ]); - expect(computeLinks(linkPatterns, spans[1], spans[1].logs[0].fields, 0)).toEqual([ - { - url: 'http://example.com/?myKey=valueOfMy%2BOther%2BKey&myKey=valueOfMyKey', - text: 'second link (valueOfMy+Other+Key)', - }, - ]); - }); -}); - -describe('getLinks()', () => { - const linkPatterns = [ - { - key: 'mySpecialKey', - url: 'http://example.com/?mySpecialKey=#{mySpecialKey}', - text: 'special key link (#{mySpecialKey})', - }, - ].map(processLinkPattern) as ProcessedLinkPattern[]; - const template = jest.spyOn(linkPatterns[0]!.url, 'template'); - - const span = { depth: 0, process: {}, tags: [{ key: 'mySpecialKey', value: 'valueOfMyKey' }] } as TraceSpan; - - let cache: WeakMap; - - beforeEach(() => { - cache = new WeakMap(); - template.mockClear(); - }); - - it('does not access the cache if there is no link pattern', () => { - cache.get = jest.fn(); - const getLinks = createGetLinks([], cache); - expect(getLinks(span, span.tags, 0)).toEqual([]); - expect(cache.get).not.toHaveBeenCalled(); - }); - - it('returns the result from the cache', () => { - const result: TraceLink[] = []; - cache.set(span.tags[0], result); - const getLinks = createGetLinks(linkPatterns, cache); - expect(getLinks(span, span.tags, 0)).toBe(result); - expect(template).not.toHaveBeenCalled(); - }); - - it('adds the result to the cache', () => { - const getLinks = createGetLinks(linkPatterns, cache); - const result = getLinks(span, span.tags, 0); - expect(template).toHaveBeenCalledTimes(1); - expect(result).toEqual([ - { - url: 'http://example.com/?mySpecialKey=valueOfMyKey', - text: 'special key link (valueOfMyKey)', - }, - ]); - expect(cache.get(span.tags[0])).toBe(result); - }); -}); diff --git a/public/app/features/explore/TraceView/components/model/link-patterns.tsx b/public/app/features/explore/TraceView/components/model/link-patterns.tsx index 930fc541056..cf52965244d 100644 --- a/public/app/features/explore/TraceView/components/model/link-patterns.tsx +++ b/public/app/features/explore/TraceView/components/model/link-patterns.tsx @@ -15,11 +15,9 @@ import { uniq as _uniq } from 'lodash'; import memoize from 'lru-memoize'; -import { TraceSpan, TraceLink, TraceKeyValuePair, Trace, TNil } from '../types'; +import { Trace } from '../types'; import { getConfigValue } from '../utils/config/get-config'; -import { getParent } from './span'; - const parameterRegExp = /#\{([^{}]*)\}/g; type ProcessedTemplate = { @@ -119,25 +117,6 @@ export function processLinkPattern(pattern: any): ProcessedLinkPattern | null { } } -export function getParameterInArray(name: string, array?: TraceKeyValuePair[] | TNil) { - if (array) { - return array.find((entry) => entry.key === name); - } - return undefined; -} - -export function getParameterInAncestor(name: string, span: TraceSpan) { - let currentSpan: TraceSpan | TNil = span; - while (currentSpan) { - const result = getParameterInArray(name, currentSpan.tags) || getParameterInArray(name, currentSpan.process.tags); - if (result) { - return result; - } - currentSpan = getParent(currentSpan); - } - return undefined; -} - function callTemplate(template: ProcessedTemplate, data: any) { return template.template(data); } @@ -173,70 +152,6 @@ export function computeTraceLink(linkPatterns: ProcessedLinkPattern[], trace: Tr return result; } -export function computeLinks( - linkPatterns: ProcessedLinkPattern[], - span: TraceSpan, - items: TraceKeyValuePair[], - itemIndex: number -) { - const item = items[itemIndex]; - let type = 'logs'; - const processTags = span.process.tags === items; - if (processTags) { - type = 'process'; - } - const spanTags = span.tags === items; - if (spanTags) { - type = 'tags'; - } - const result: Array<{ url: string; text: string }> = []; - linkPatterns.forEach((pattern) => { - if (pattern.type(type) && pattern.key(item.key) && pattern.value(item.value)) { - const parameterValues: Record = {}; - const allParameters = pattern.parameters.every((parameter) => { - let entry = getParameterInArray(parameter, items); - if (!entry && !processTags) { - // do not look in ancestors for process tags because the same object may appear in different places in the hierarchy - // and the cache in getLinks uses that object as a key - entry = getParameterInAncestor(parameter, span); - } - if (entry) { - parameterValues[parameter] = entry.value; - return true; - } - // eslint-disable-next-line no-console - console.warn( - `Skipping link pattern, missing parameter ${parameter} for key ${item.key} in ${type}.`, - pattern.object - ); - return false; - }); - if (allParameters) { - result.push({ - url: callTemplate(pattern.url, parameterValues), - text: callTemplate(pattern.text, parameterValues), - }); - } - } - }); - return result; -} - -export function createGetLinks(linkPatterns: ProcessedLinkPattern[], cache: WeakMap) { - return (span: TraceSpan, items: TraceKeyValuePair[], itemIndex: number) => { - if (linkPatterns.length === 0) { - return []; - } - const item = items[itemIndex]; - let result = cache.get(item); - if (!result) { - result = computeLinks(linkPatterns, span, items, itemIndex); - cache.set(item, result); - } - return result; - }; -} - const processedLinks = (getConfigValue('linkPatterns') || []) .map(processLinkPattern) .filter((link: ProcessedLinkPattern | null): link is ProcessedLinkPattern => Boolean(link)); @@ -248,5 +163,3 @@ export const getTraceLinks: (trace: Trace | undefined) => TLinksRV = memoize(10) } return computeTraceLink(processedLinks, trace); }); - -export default createGetLinks(processedLinks, new WeakMap()); diff --git a/public/app/features/explore/TraceView/components/model/span.tsx b/public/app/features/explore/TraceView/components/model/span.tsx deleted file mode 100644 index 07764898a24..00000000000 --- a/public/app/features/explore/TraceView/components/model/span.tsx +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2017 The Jaeger Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import { TraceSpan } from '../types'; - -/** - * Searches the span.references to find 'CHILD_OF' reference type or returns null. - * @param {TraceSpan} span The span whose parent is to be returned. - * @returns {TraceSpan|null} The parent span if there is one, null otherwise. - */ -export function getParent(span: TraceSpan) { - const parentRef = span.references ? span.references.find((ref) => ref.refType === 'CHILD_OF') : null; - return parentRef ? parentRef.span : null; -}