diff --git a/.betterer.results b/.betterer.results index 37fb0e90b15..4482c94acc5 100644 --- a/.betterer.results +++ b/.betterer.results @@ -3498,12 +3498,6 @@ exports[`better eslint`] = { "public/app/plugins/datasource/influxdb/response_parser.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], - "public/app/plugins/datasource/jaeger/_importedDependencies/model/transform-trace-data.tsx:5381": [ - [0, 0, 0, "Do not use any type assertions.", "0"] - ], - "public/app/plugins/datasource/jaeger/_importedDependencies/types/index.tsx:5381": [ - [0, 0, 0, "Do not re-export imported variable (\`./trace\`)", "0"] - ], "public/app/plugins/datasource/jaeger/datasource.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], diff --git a/public/app/plugins/datasource/jaeger/_importedDependencies/README.md b/public/app/plugins/datasource/jaeger/_importedDependencies/README.md deleted file mode 100644 index 6a32e35129c..00000000000 --- a/public/app/plugins/datasource/jaeger/_importedDependencies/README.md +++ /dev/null @@ -1,3 +0,0 @@ -This directory contains dependencies that we duplicated from Grafana core while working on the decoupling of Jaeger from such core. -The long-term goal is to move these files away from here by replacing them with packages. -As such, they are only temporary and meant to be used internally to this package, please avoid using them for example as dependencies (imports) in other data source plugins. diff --git a/public/app/plugins/datasource/jaeger/_importedDependencies/model/trace-viewer.ts b/public/app/plugins/datasource/jaeger/_importedDependencies/model/trace-viewer.ts deleted file mode 100644 index d3978acc247..00000000000 --- a/public/app/plugins/datasource/jaeger/_importedDependencies/model/trace-viewer.ts +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2020 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 { memoize } from 'lodash'; - -import { TraceSpan } from '../types'; - -function _getTraceNameImpl(spans: TraceSpan[]) { - // Use a span with no references to another span in given array - // prefering the span with the fewest references - // using start time as a tie breaker - let candidateSpan: TraceSpan | undefined; - const allIDs: Set = new Set(spans.map(({ spanID }) => spanID)); - - for (let i = 0; i < spans.length; i++) { - const hasInternalRef = - spans[i].references && - spans[i].references.some(({ traceID, spanID }) => traceID === spans[i].traceID && allIDs.has(spanID)); - if (hasInternalRef) { - continue; - } - - if (!candidateSpan) { - candidateSpan = spans[i]; - continue; - } - - const thisRefLength = (spans[i].references && spans[i].references.length) || 0; - const candidateRefLength = (candidateSpan.references && candidateSpan.references.length) || 0; - - if ( - thisRefLength < candidateRefLength || - (thisRefLength === candidateRefLength && spans[i].startTime < candidateSpan.startTime) - ) { - candidateSpan = spans[i]; - } - } - return candidateSpan ? `${candidateSpan.process.serviceName}: ${candidateSpan.operationName}` : ''; -} - -export const getTraceName = memoize(_getTraceNameImpl, (spans: TraceSpan[]) => { - if (!spans.length) { - return 0; - } - return spans[0].traceID; -}); diff --git a/public/app/plugins/datasource/jaeger/_importedDependencies/model/transform-trace-data.tsx b/public/app/plugins/datasource/jaeger/_importedDependencies/model/transform-trace-data.tsx deleted file mode 100644 index f095fe3d8c1..00000000000 --- a/public/app/plugins/datasource/jaeger/_importedDependencies/model/transform-trace-data.tsx +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// 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 { isEqual as _isEqual } from 'lodash'; - -import { TraceKeyValuePair } from '@grafana/data'; - -import { getTraceSpanIdsAsTree } from '../selectors/trace'; -import { TraceSpan, Trace, TraceResponse, TraceProcess } from '../types'; -import TreeNode from '../utils/TreeNode'; -import { getConfigValue } from '../utils/config/get-config'; - -import { getTraceName } from './trace-viewer'; - -function deduplicateTags(tags: TraceKeyValuePair[]) { - const warningsHash: Map = new Map(); - const dedupedTags: TraceKeyValuePair[] = tags.reduce((uniqueTags, tag) => { - if (!uniqueTags.some((t) => t.key === tag.key && t.value === tag.value)) { - uniqueTags.push(tag); - } else { - warningsHash.set(`${tag.key}:${tag.value}`, `Duplicate tag "${tag.key}:${tag.value}"`); - } - return uniqueTags; - }, []); - const warnings = Array.from(warningsHash.values()); - return { dedupedTags, warnings }; -} - -function orderTags(tags: TraceKeyValuePair[], topPrefixes?: string[]) { - const orderedTags: TraceKeyValuePair[] = tags?.slice() ?? []; - const tp = (topPrefixes || []).map((p: string) => p.toLowerCase()); - - orderedTags.sort((a, b) => { - const aKey = a.key.toLowerCase(); - const bKey = b.key.toLowerCase(); - - for (let i = 0; i < tp.length; i++) { - const p = tp[i]; - if (aKey.startsWith(p) && !bKey.startsWith(p)) { - return -1; - } - if (!aKey.startsWith(p) && bKey.startsWith(p)) { - return 1; - } - } - - if (aKey > bKey) { - return 1; - } - if (aKey < bKey) { - return -1; - } - return 0; - }); - - return orderedTags; -} - -/** - * NOTE: Mutates `data` - Transform the HTTP response data into the form the app - * generally requires. - */ -export default function transformTraceData(data: TraceResponse | undefined): Trace | null { - if (!data?.traceID) { - return null; - } - const traceID = data.traceID.toLowerCase(); - - let traceEndTime = 0; - let traceStartTime = Number.MAX_SAFE_INTEGER; - const spanIdCounts = new Map(); - const spanMap = new Map(); - // filter out spans with empty start times - // eslint-disable-next-line no-param-reassign - data.spans = data.spans.filter((span) => Boolean(span.startTime)); - - // Sort process tags - data.processes = Object.entries(data.processes).reduce>((processes, [id, process]) => { - processes[id] = { - ...process, - tags: orderTags(process.tags), - }; - return processes; - }, {}); - - const max = data.spans.length; - for (let i = 0; i < max; i++) { - const span: TraceSpan = data.spans[i] as TraceSpan; - const { startTime, duration, processID } = span; - - let spanID = span.spanID; - // check for start / end time for the trace - if (startTime < traceStartTime) { - traceStartTime = startTime; - } - if (startTime + duration > traceEndTime) { - traceEndTime = startTime + duration; - } - // make sure span IDs are unique - const idCount = spanIdCounts.get(spanID); - if (idCount != null) { - // eslint-disable-next-line no-console - console.warn(`Dupe spanID, ${idCount + 1} x ${spanID}`, span, spanMap.get(spanID)); - if (_isEqual(span, spanMap.get(spanID))) { - // eslint-disable-next-line no-console - console.warn('\t two spans with same ID have `isEqual(...) === true`'); - } - spanIdCounts.set(spanID, idCount + 1); - spanID = `${spanID}_${idCount}`; - span.spanID = spanID; - } else { - spanIdCounts.set(spanID, 1); - } - span.process = data.processes[processID]; - spanMap.set(spanID, span); - } - // tree is necessary to sort the spans, so children follow parents, and - // siblings are sorted by start time - const tree = getTraceSpanIdsAsTree(data, spanMap); - const spans: TraceSpan[] = []; - const svcCounts: Record = {}; - - tree.walk((spanID: string, node: TreeNode, depth = 0) => { - if (spanID === '__root__') { - return; - } - if (typeof spanID !== 'string') { - return; - } - const span = spanMap.get(spanID); - if (!span) { - return; - } - const { serviceName } = span.process; - svcCounts[serviceName] = (svcCounts[serviceName] || 0) + 1; - span.relativeStartTime = span.startTime - traceStartTime; - span.depth = depth - 1; - span.hasChildren = node.children.length > 0; - span.childSpanCount = node.children.length; - span.warnings = span.warnings || []; - span.tags = span.tags || []; - span.references = span.references || []; - - span.childSpanIds = node.children - .slice() - .sort((a, b) => { - const spanA = spanMap.get(a.value)!; - const spanB = spanMap.get(b.value)!; - return spanB.startTime + spanB.duration - (spanA.startTime + spanA.duration); - }) - .map((each) => each.value); - - const tagsInfo = deduplicateTags(span.tags); - span.tags = orderTags(tagsInfo.dedupedTags, getConfigValue('topTagPrefixes')); - span.warnings = span.warnings.concat(tagsInfo.warnings); - span.references.forEach((ref, index) => { - const refSpan = spanMap.get(ref.spanID); - if (refSpan) { - // eslint-disable-next-line no-param-reassign - ref.span = refSpan; - if (index > 0) { - // Don't take into account the parent, just other references. - refSpan.subsidiarilyReferencedBy = refSpan.subsidiarilyReferencedBy || []; - refSpan.subsidiarilyReferencedBy.push({ - spanID, - traceID, - span, - refType: ref.refType, - }); - } - } - }); - spans.push(span); - }); - const traceName = getTraceName(spans); - const services = Object.keys(svcCounts).map((name) => ({ name, numberOfSpans: svcCounts[name] })); - return { - services, - spans, - traceID, - traceName, - // can't use spread operator for intersection types - // repl: https://goo.gl/4Z23MJ - // issue: https://github.com/facebook/flow/issues/1511 - processes: data.processes, - duration: traceEndTime - traceStartTime, - startTime: traceStartTime, - endTime: traceEndTime, - }; -} diff --git a/public/app/plugins/datasource/jaeger/_importedDependencies/selectors/trace.ts b/public/app/plugins/datasource/jaeger/_importedDependencies/selectors/trace.ts deleted file mode 100644 index 9fb695b3321..00000000000 --- a/public/app/plugins/datasource/jaeger/_importedDependencies/selectors/trace.ts +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// 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 { TraceResponse, TraceSpanData } from '../types/trace'; -import TreeNode from '../utils/TreeNode'; - -const TREE_ROOT_ID = '__root__'; - -/** - * Build a tree of { value: spanID, children } items derived from the - * `span.references` information. The tree represents the grouping of parent / - * child relationships. The root-most node is nominal in that - * `.value === TREE_ROOT_ID`. This is done because a root span (the main trace - * span) is not always included with the trace data. Thus, there can be - * multiple top-level spans, and the root node acts as their common parent. - * - * The children are sorted by `span.startTime` after the tree is built. - * - * @param {Trace} trace The trace to build the tree of spanIDs. - * @return {TreeNode} A tree of spanIDs derived from the relationships - * between spans in the trace. - */ -export function getTraceSpanIdsAsTree(trace: TraceResponse, spanMap: Map | null = null) { - const nodesById = new Map(trace.spans.map((span: TraceSpanData) => [span.spanID, new TreeNode(span.spanID)])); - const spansById = spanMap ?? new Map(trace.spans.map((span: TraceSpanData) => [span.spanID, span])); - const root = new TreeNode(TREE_ROOT_ID); - trace.spans.forEach((span: TraceSpanData) => { - const node = nodesById.get(span.spanID)!; - if (Array.isArray(span.references) && span.references.length) { - const { refType, spanID: parentID } = span.references[0]; - if (refType === 'CHILD_OF' || refType === 'FOLLOWS_FROM') { - const parent = nodesById.get(parentID) || root; - parent.children?.push(node); - } else { - throw new Error(`Unrecognized ref type: ${refType}`); - } - } else { - root.children.push(node); - } - }); - const comparator = (nodeA: TreeNode, nodeB: TreeNode) => { - const a: TraceSpanData | undefined = nodeA?.value ? spansById.get(nodeA.value.toString()) : undefined; - const b: TraceSpanData | undefined = nodeB?.value ? spansById.get(nodeB.value.toString()) : undefined; - return +(a?.startTime! > b?.startTime!) || +(a?.startTime === b?.startTime) - 1; - }; - trace.spans.forEach((span: TraceSpanData) => { - const node = nodesById.get(span.spanID); - if (node!.children.length > 1) { - node?.children.sort(comparator); - } - }); - root.children.sort(comparator); - return root; -} diff --git a/public/app/plugins/datasource/jaeger/_importedDependencies/types/index.tsx b/public/app/plugins/datasource/jaeger/_importedDependencies/types/index.tsx deleted file mode 100644 index f777aee8566..00000000000 --- a/public/app/plugins/datasource/jaeger/_importedDependencies/types/index.tsx +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// 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. - -export type { TraceSpan, TraceResponse, Trace, TraceProcess, TraceLink, CriticalPathSection } from './trace'; diff --git a/public/app/plugins/datasource/jaeger/_importedDependencies/types/trace.ts b/public/app/plugins/datasource/jaeger/_importedDependencies/types/trace.ts deleted file mode 100644 index 0c38b7ba584..00000000000 --- a/public/app/plugins/datasource/jaeger/_importedDependencies/types/trace.ts +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// 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 { TraceKeyValuePair, TraceLog } from '@grafana/data'; - -/** - * All timestamps are in microseconds - */ - -export type TraceLink = { - url: string; - text: string; -}; - -export type TraceProcess = { - serviceName: string; - tags: TraceKeyValuePair[]; -}; - -export type TraceSpanReference = { - refType: 'CHILD_OF' | 'FOLLOWS_FROM'; - // eslint-disable-next-line no-use-before-define - span?: TraceSpan | null | undefined; - spanID: string; - traceID: string; - tags?: TraceKeyValuePair[]; -}; - -export type TraceSpanData = { - spanID: string; - traceID: string; - processID: string; - operationName: string; - // Times are in microseconds - startTime: number; - duration: number; - logs: TraceLog[]; - tags?: TraceKeyValuePair[]; - kind?: string; - statusCode?: number; - statusMessage?: string; - instrumentationLibraryName?: string; - instrumentationLibraryVersion?: string; - traceState?: string; - references?: TraceSpanReference[]; - warnings?: string[] | null; - stackTraces?: string[]; - flags: number; - errorIconColor?: string; - dataFrameRowIndex?: number; - childSpanIds?: string[]; -}; - -export type TraceSpan = TraceSpanData & { - depth: number; - hasChildren: boolean; - childSpanCount: number; - process: TraceProcess; - relativeStartTime: number; - tags: NonNullable; - references: NonNullable; - warnings: NonNullable; - childSpanIds: NonNullable; - subsidiarilyReferencedBy: TraceSpanReference[]; -}; - -export type TraceData = { - processes: Record; - traceID: string; - warnings?: string[] | null; -}; - -export type TraceResponse = TraceData & { - spans: TraceSpanData[]; -}; - -export type Trace = TraceData & { - duration: number; - endTime: number; - spans: TraceSpan[]; - startTime: number; - traceName: string; - services: Array<{ name: string; numberOfSpans: number }>; -}; - -// It is a section of span that lies on critical path -export type CriticalPathSection = { - spanId: string; - section_start: number; - section_end: number; -}; diff --git a/public/app/plugins/datasource/jaeger/_importedDependencies/utils/TreeNode.ts b/public/app/plugins/datasource/jaeger/_importedDependencies/utils/TreeNode.ts deleted file mode 100644 index f6b123f2d50..00000000000 --- a/public/app/plugins/datasource/jaeger/_importedDependencies/utils/TreeNode.ts +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// 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 - -export default class TreeNode { - value: TValue; - children: Array>; - - static iterFunction( - fn: ((value: TValue, node: TreeNode, depth: number) => TreeNode | null) | Function, - depth = 0 - ) { - return (node: TreeNode) => fn(node.value, node, depth); - } - - static searchFunction(search: Function | TreeNode) { - if (typeof search === 'function') { - return search; - } - - return (value: TValue, node: TreeNode) => (search instanceof TreeNode ? node === search : value === search); - } - - constructor(value: TValue, children: Array> = []) { - this.value = value; - this.children = children; - } - - get depth(): number { - return this.children.reduce((depth, child) => Math.max(child.depth + 1, depth), 1); - } - - get size() { - let i = 0; - this.walk(() => i++); - return i; - } - - addChild(child: TreeNode | TValue) { - this.children.push(child instanceof TreeNode ? child : new TreeNode(child)); - return this; - } - - find(search: Function | TreeNode): TreeNode | null { - const searchFn = TreeNode.iterFunction(TreeNode.searchFunction(search)); - if (searchFn(this)) { - return this; - } - for (let i = 0; i < this.children.length; i++) { - const result = this.children[i].find(search); - if (result) { - return result; - } - } - return null; - } - - getPath(search: Function | TreeNode) { - const searchFn = TreeNode.iterFunction(TreeNode.searchFunction(search)); - - const findPath = ( - currentNode: TreeNode, - currentPath: Array> - ): Array> | null => { - // skip if we already found the result - const attempt = currentPath.concat([currentNode]); - // base case: return the array when there is a match - if (searchFn(currentNode)) { - return attempt; - } - for (let i = 0; i < currentNode.children.length; i++) { - const child = currentNode.children[i]; - const match = findPath(child, attempt); - if (match) { - return match; - } - } - return null; - }; - - return findPath(this, []); - } - - walk(fn: (spanID: TValue, node: TreeNode, depth: number) => void, startDepth = 0) { - type StackEntry = { - node: TreeNode; - depth: number; - }; - const nodeStack: StackEntry[] = []; - let actualDepth = startDepth; - nodeStack.push({ node: this, depth: actualDepth }); - while (nodeStack.length) { - const entry: StackEntry = nodeStack[nodeStack.length - 1]; - nodeStack.pop(); - const { node, depth } = entry; - fn(node.value, node, depth); - actualDepth = depth + 1; - let i = node.children.length - 1; - while (i >= 0) { - nodeStack.push({ node: node.children[i], depth: actualDepth }); - i--; - } - } - } - - paths(fn: (pathIds: TValue[]) => void) { - type StackEntry = { - node: TreeNode; - childIndex: number; - }; - const stack: StackEntry[] = []; - stack.push({ node: this, childIndex: 0 }); - const paths: TValue[] = []; - while (stack.length) { - const { node, childIndex } = stack[stack.length - 1]; - if (node.children.length >= childIndex + 1) { - stack[stack.length - 1].childIndex++; - stack.push({ node: node.children[childIndex], childIndex: 0 }); - } else { - if (node.children.length === 0) { - const path = stack.map((item) => item.node.value); - fn(path); - } - stack.pop(); - } - } - return paths; - } -} diff --git a/public/app/plugins/datasource/jaeger/_importedDependencies/utils/config/default-config.ts b/public/app/plugins/datasource/jaeger/_importedDependencies/utils/config/default-config.ts deleted file mode 100644 index 1e8215a230d..00000000000 --- a/public/app/plugins/datasource/jaeger/_importedDependencies/utils/config/default-config.ts +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// 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. - -const FALLBACK_DAG_MAX_NUM_SERVICES = 100; - -export default Object.defineProperty( - { - archiveEnabled: false, - dependencies: { - dagMaxNumServices: FALLBACK_DAG_MAX_NUM_SERVICES, - menuEnabled: true, - }, - linkPatterns: [], - search: { - maxLookback: { - label: '2 Days', - value: '2d', - }, - maxLimit: 1500, - }, - tracking: { - gaID: null, - trackErrors: true, - }, - }, - // fields that should be individually merged vs wholesale replaced - '__mergeFields', - { value: ['dependencies', 'search', 'tracking'] } -); diff --git a/public/app/plugins/datasource/jaeger/_importedDependencies/utils/config/get-config.tsx b/public/app/plugins/datasource/jaeger/_importedDependencies/utils/config/get-config.tsx deleted file mode 100644 index 0a1ec89870c..00000000000 --- a/public/app/plugins/datasource/jaeger/_importedDependencies/utils/config/get-config.tsx +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2017 Uber Technologies, Inc. -// -// 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 { get as _get } from 'lodash'; - -import defaultConfig from './default-config'; - -/** - * Merge the embedded config from the query service (if present) with the - * default config from `../../constants/default-config`. - */ -export default function getConfig() { - return defaultConfig; -} - -export function getConfigValue(path: string) { - return _get(getConfig(), path); -} diff --git a/public/app/plugins/datasource/jaeger/components/SearchForm.tsx b/public/app/plugins/datasource/jaeger/components/SearchForm.tsx index c5840a60bab..a81c64d72a0 100644 --- a/public/app/plugins/datasource/jaeger/components/SearchForm.tsx +++ b/public/app/plugins/datasource/jaeger/components/SearchForm.tsx @@ -8,7 +8,6 @@ import { fuzzyMatch, InlineField, InlineFieldRow, Input, Select } from '@grafana import { JaegerDatasource } from '../datasource'; import { JaegerQuery } from '../types'; -import { transformToLogfmt } from '../util'; const durationPlaceholder = 'e.g. 1.2s, 100ms, 500us'; @@ -150,7 +149,7 @@ export function SearchForm({ datasource, query, onChange }: Props) { onChange({ diff --git a/public/app/plugins/datasource/jaeger/datasource.test.ts b/public/app/plugins/datasource/jaeger/datasource.test.ts index 5c0961d4ac7..2beeeb09eb8 100644 --- a/public/app/plugins/datasource/jaeger/datasource.test.ts +++ b/public/app/plugins/datasource/jaeger/datasource.test.ts @@ -136,16 +136,6 @@ describe('node graph functionality', () => { }); }); -describe('time range', () => { - it('should calculate correct time range', async () => { - const ds = new JaegerDatasource(defaultSettings); - const timeRange = ds.getTimeRange(); - const now = Date.now(); - expect(timeRange.end).toBeCloseTo(now * 1000, -4); - expect(timeRange.start).toBeCloseTo((now - 6 * 3600 * 1000) * 1000, -4); - }); -}); - function setupQueryMock(type: 'trace' | 'search') { return jest.spyOn(DataSourceWithBackend.prototype, 'query').mockImplementation(() => { if (type === 'search') { diff --git a/public/app/plugins/datasource/jaeger/datasource.ts b/public/app/plugins/datasource/jaeger/datasource.ts index 11c6a8a3f3b..ea4eb2c4d43 100644 --- a/public/app/plugins/datasource/jaeger/datasource.ts +++ b/public/app/plugins/datasource/jaeger/datasource.ts @@ -6,10 +6,7 @@ import { DataQueryResponse, DataSourceInstanceSettings, DataSourceJsonData, - dateMath, - DateTime, FieldType, - getDefaultTimeRange, MutableDataFrame, ScopedVars, toDataFrame, @@ -45,10 +42,6 @@ export class JaegerDatasource extends DataSourceWithBackend): Observable { // At this moment we expect only one target. In case we somehow change the UI to be able to show multiple // traces at one we need to change this. @@ -122,25 +115,11 @@ export class JaegerDatasource extends DataSourceWithBackend { - it('should transform Jaeger dependencies API response', () => { - const data = { - data: [ - { - parent: 'serviceA', - child: 'serviceB', - callCount: 1, - }, - { - parent: 'serviceA', - child: 'serviceC', - callCount: 2, - }, - { - parent: 'serviceB', - child: 'serviceC', - callCount: 3, - }, - ], - total: 0, - limit: 0, - offset: 0, - }; - - const res = mapJaegerDependenciesResponse({ data }); - expect(res).toMatchObject({ - data: [ - { - fields: [ - { - config: {}, - name: 'id', - type: 'string', - values: ['serviceA', 'serviceB', 'serviceC'], - }, - { - config: {}, - name: 'title', - type: 'string', - values: ['serviceA', 'serviceB', 'serviceC'], - }, - ], - meta: { preferredVisualisationType: 'nodeGraph' }, - }, - { - fields: [ - { - config: {}, - name: 'id', - type: 'string', - values: ['serviceA--serviceB', 'serviceA--serviceC', 'serviceB--serviceC'], - }, - { - config: {}, - name: 'target', - type: 'string', - values: ['serviceB', 'serviceC', 'serviceC'], - }, - { - config: {}, - name: 'source', - type: 'string', - values: ['serviceA', 'serviceA', 'serviceB'], - }, - { - config: { displayName: 'Call count' }, - name: 'mainstat', - type: 'string', - values: [1, 2, 3], - }, - ], - meta: { preferredVisualisationType: 'nodeGraph' }, - }, - ], - }); - }); - - it('should transform Jaeger API error', () => { - const data = { - total: 0, - limit: 0, - offset: 0, - errors: [ - { - code: 400, - msg: 'unable to parse param \'endTs\': strconv.ParseInt: parsing "foo": invalid syntax', - }, - ], - }; - - const res = mapJaegerDependenciesResponse({ data }); - - expect(res).toEqual({ - data: [], - errors: [ - { - message: 'unable to parse param \'endTs\': strconv.ParseInt: parsing "foo": invalid syntax', - status: 400, - }, - ], - }); - }); -}); diff --git a/public/app/plugins/datasource/jaeger/dependencyGraphTransform.ts b/public/app/plugins/datasource/jaeger/dependencyGraphTransform.ts deleted file mode 100644 index 0e8fe6dce46..00000000000 --- a/public/app/plugins/datasource/jaeger/dependencyGraphTransform.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { - DataFrame, - DataQueryResponse, - FieldType, - MutableDataFrame, - NodeGraphDataFrameFieldNames as Fields, -} from '@grafana/data'; - -import { JaegerServiceDependency } from './types'; - -interface Node { - [Fields.id]: string; - [Fields.title]: string; -} - -interface Edge { - [Fields.id]: string; - [Fields.target]: string; - [Fields.source]: string; - [Fields.mainStat]: number; -} - -/** - * Error schema used by the Jaeger dependencies API. - */ -interface JaegerDependenciesResponseError { - code: number; - msg: string; -} - -interface JaegerDependenciesResponse { - data?: { - errors?: JaegerDependenciesResponseError[]; - data?: JaegerServiceDependency[]; - }; -} - -/** - * Transforms a Jaeger dependencies API response to a Grafana {@link DataQueryResponse}. - * @param response Raw response data from the API proxy. - */ -export function mapJaegerDependenciesResponse(response: JaegerDependenciesResponse): DataQueryResponse { - const errors = response?.data?.errors; - if (errors) { - return { - data: [], - errors: errors.map((e: JaegerDependenciesResponseError) => ({ message: e.msg, status: e.code })), - }; - } - const dependencies = response?.data?.data; - if (dependencies) { - return { - data: convertDependenciesToGraph(dependencies), - }; - } - - return { data: [] }; -} - -/** - * Converts a list of Jaeger service dependencies to a Grafana {@link DataFrame} array suitable for the node graph panel. - * @param dependencies List of Jaeger service dependencies as returned by the Jaeger dependencies API. - */ -function convertDependenciesToGraph(dependencies: JaegerServiceDependency[]): DataFrame[] { - const servicesByName = new Map(); - const edges: Edge[] = []; - - for (const dependency of dependencies) { - addServiceNode(dependency.parent, servicesByName); - addServiceNode(dependency.child, servicesByName); - - edges.push({ - [Fields.id]: dependency.parent + '--' + dependency.child, - [Fields.target]: dependency.child, - [Fields.source]: dependency.parent, - [Fields.mainStat]: dependency.callCount, - }); - } - - const nodesFrame = new MutableDataFrame({ - fields: [ - { name: Fields.id, type: FieldType.string }, - { name: Fields.title, type: FieldType.string }, - ], - meta: { - preferredVisualisationType: 'nodeGraph', - }, - }); - - const edgesFrame = new MutableDataFrame({ - fields: [ - { name: Fields.id, type: FieldType.string }, - { name: Fields.target, type: FieldType.string }, - { name: Fields.source, type: FieldType.string }, - { name: Fields.mainStat, type: FieldType.string, config: { displayName: 'Call count' } }, - ], - meta: { - preferredVisualisationType: 'nodeGraph', - }, - }); - - for (const node of servicesByName.values()) { - nodesFrame.add(node); - } - - for (const edge of edges) { - edgesFrame.add(edge); - } - - return [nodesFrame, edgesFrame]; -} - -/** - * Convenience function to register a service node in the dependency graph. - * @param service Name of the service to register. - * @param servicesByName Map of service nodes keyed name. - */ -function addServiceNode(service: string, servicesByName: Map) { - if (!servicesByName.has(service)) { - servicesByName.set(service, { - [Fields.id]: service, - [Fields.title]: service, - }); - } -} diff --git a/public/app/plugins/datasource/jaeger/responseTransform.ts b/public/app/plugins/datasource/jaeger/responseTransform.ts index 35446e221b8..cd56f08e61f 100644 --- a/public/app/plugins/datasource/jaeger/responseTransform.ts +++ b/public/app/plugins/datasource/jaeger/responseTransform.ts @@ -1,13 +1,5 @@ -import { - DataFrame, - DataSourceInstanceSettings, - FieldType, - MutableDataFrame, - TraceLog, - TraceSpanRow, -} from '@grafana/data'; +import { DataFrame, FieldType, MutableDataFrame, TraceLog, TraceSpanRow } from '@grafana/data'; -import transformTraceData from './_importedDependencies/model/transform-trace-data'; import { JaegerResponse, Span, TraceProcess, TraceResponse } from './types'; export function createTraceFrame(data: TraceResponse): DataFrame { @@ -68,62 +60,6 @@ function toSpanRow(span: Span, processes: Record): TraceSp }; } -export function createTableFrame(data: TraceResponse[], instanceSettings: DataSourceInstanceSettings): DataFrame { - const frame = new MutableDataFrame({ - fields: [ - { - name: 'traceID', - type: FieldType.string, - config: { - unit: 'string', - displayNameFromDS: 'Trace ID', - links: [ - { - title: 'Trace: ${__value.raw}', - url: '', - internal: { - datasourceUid: instanceSettings.uid, - datasourceName: instanceSettings.name, - query: { - query: '${__value.raw}', - }, - }, - }, - ], - }, - }, - { name: 'traceName', type: FieldType.string, config: { displayNameFromDS: 'Trace name' } }, - { name: 'startTime', type: FieldType.time, config: { displayNameFromDS: 'Start time' } }, - { name: 'duration', type: FieldType.number, config: { displayNameFromDS: 'Duration', unit: 'µs' } }, - ], - meta: { - preferredVisualisationType: 'table', - }, - }); - // Show the most recent traces - const traceData = data.map(transformToTraceData).sort((a, b) => b?.startTime! - a?.startTime!); - - for (const trace of traceData) { - frame.add(trace); - } - - return frame; -} - -function transformToTraceData(data: TraceResponse) { - const traceData = transformTraceData(data); - if (!traceData) { - return; - } - - return { - traceID: traceData.traceID, - startTime: traceData.startTime / 1000, - duration: traceData.duration, - traceName: traceData.traceName, - }; -} - export function transformToJaeger(data: MutableDataFrame): JaegerResponse { let traceResponse: TraceResponse = { traceID: '', diff --git a/public/app/plugins/datasource/jaeger/types.ts b/public/app/plugins/datasource/jaeger/types.ts index 7173be50a1f..0ddf78bc2b4 100644 --- a/public/app/plugins/datasource/jaeger/types.ts +++ b/public/app/plugins/datasource/jaeger/types.ts @@ -1,9 +1,5 @@ -import { DataQuery, TraceKeyValuePair, TraceLog } from '@grafana/data'; - -export type TraceLink = { - url: string; - text: string; -}; +import { TraceKeyValuePair, TraceLog } from '@grafana/data'; +import { DataQuery } from '@grafana/schema'; export type TraceProcess = { serviceName: string; diff --git a/public/app/plugins/datasource/jaeger/util.ts b/public/app/plugins/datasource/jaeger/util.ts deleted file mode 100644 index f025ed9df55..00000000000 --- a/public/app/plugins/datasource/jaeger/util.ts +++ /dev/null @@ -1,26 +0,0 @@ -import logfmt from 'logfmt'; - -export function convertTagsLogfmt(tags: string | undefined) { - if (!tags) { - return ''; - } - const data = logfmt.parse(tags); - Object.keys(data).forEach((key) => { - const value = data[key]; - if (typeof value !== 'string') { - data[key] = String(value); - } - }); - return JSON.stringify(data); -} - -export function transformToLogfmt(tags: string | undefined) { - if (!tags) { - return ''; - } - try { - return logfmt.stringify(JSON.parse(tags)); - } catch { - return tags; - } -}