mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Correlations: Enable traceView formatted links (#67160)
* Enable correlations links for traceView formatted fields * Add other links to the span UI * Show both “legacy” and dataframe links * bandaid test * Remove special path logic, stringify all non strings before applying regex * Fix test * Do not create new instance of factory for every call, change header to correlations * Get links from more than one field * Remove categories * Fix google cloud link tests * Add test for multiple internal links * Remove changes to datasources provisioning * Added sorting, changed log link title
This commit is contained in:
parent
f478504bc9
commit
0db397b8be
@ -12,7 +12,9 @@ export const getTransformationVars = (
|
|||||||
let transformVal: { [key: string]: string | boolean | null | undefined } = {};
|
let transformVal: { [key: string]: string | boolean | null | undefined } = {};
|
||||||
if (transformation.type === SupportedTransformationType.Regex && transformation.expression) {
|
if (transformation.type === SupportedTransformationType.Regex && transformation.expression) {
|
||||||
const regexp = new RegExp(transformation.expression, 'gi');
|
const regexp = new RegExp(transformation.expression, 'gi');
|
||||||
const matches = fieldValue.matchAll(regexp);
|
const stringFieldVal = typeof fieldValue === 'string' ? fieldValue : safeStringifyValue(fieldValue);
|
||||||
|
|
||||||
|
const matches = stringFieldVal.matchAll(regexp);
|
||||||
for (const match of matches) {
|
for (const match of matches) {
|
||||||
if (match.groups) {
|
if (match.groups) {
|
||||||
transformVal = match.groups;
|
transformVal = match.groups;
|
||||||
|
@ -17,8 +17,7 @@ import userEvent from '@testing-library/user-event';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { NONE, DURATION, TAG } from '../settings/SpanBarSettings';
|
import { NONE, DURATION, TAG } from '../settings/SpanBarSettings';
|
||||||
import { TraceSpan } from '../types';
|
import { SpanLinkDef, TraceSpan } from '../types';
|
||||||
import { SpanLinks } from '../types/links';
|
|
||||||
|
|
||||||
import SpanBarRow, { SpanBarRowProps } from './SpanBarRow';
|
import SpanBarRow, { SpanBarRowProps } from './SpanBarRow';
|
||||||
|
|
||||||
@ -111,11 +110,7 @@ describe('<SpanBarRow>', () => {
|
|||||||
<SpanBarRow
|
<SpanBarRow
|
||||||
{...(props as unknown as SpanBarRowProps)}
|
{...(props as unknown as SpanBarRowProps)}
|
||||||
span={span}
|
span={span}
|
||||||
createSpanLink={() =>
|
createSpanLink={() => [{ href: 'href' }, { href: 'href' }] as SpanLinkDef[]}
|
||||||
({
|
|
||||||
traceLinks: [{ href: 'href' }, { href: 'href' }],
|
|
||||||
} as SpanLinks)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
expect(screen.getAllByTestId('SpanLinksMenu')).toHaveLength(1);
|
expect(screen.getAllByTestId('SpanLinksMenu')).toHaveLength(1);
|
||||||
@ -142,11 +137,7 @@ describe('<SpanBarRow>', () => {
|
|||||||
<SpanBarRow
|
<SpanBarRow
|
||||||
{...(props as unknown as SpanBarRowProps)}
|
{...(props as unknown as SpanBarRowProps)}
|
||||||
span={span}
|
span={span}
|
||||||
createSpanLink={() =>
|
createSpanLink={() => [{ content: 'This span is referenced by another span', href: 'href' }] as SpanLinkDef[]}
|
||||||
({
|
|
||||||
traceLinks: [{ content: 'This span is referenced by another span', href: 'href' }],
|
|
||||||
} as SpanLinks)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
expect(screen.getByRole('link', { name: 'This span is referenced by another span' })).toBeInTheDocument();
|
expect(screen.getByRole('link', { name: 'This span is referenced by another span' })).toBeInTheDocument();
|
||||||
@ -181,11 +172,7 @@ describe('<SpanBarRow>', () => {
|
|||||||
<SpanBarRow
|
<SpanBarRow
|
||||||
{...(props as unknown as SpanBarRowProps)}
|
{...(props as unknown as SpanBarRowProps)}
|
||||||
span={span}
|
span={span}
|
||||||
createSpanLink={() =>
|
createSpanLink={() => [{ href: 'href' }, { href: 'href' }] as SpanLinkDef[]}
|
||||||
({
|
|
||||||
traceLinks: [{ href: 'href' }, { href: 'href' }],
|
|
||||||
} as SpanLinks)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
expect(screen.getAllByTestId('SpanLinksMenu')).toHaveLength(1);
|
expect(screen.getAllByTestId('SpanLinksMenu')).toHaveLength(1);
|
||||||
|
@ -22,7 +22,6 @@ import { Icon, stylesFactory, withTheme2 } from '@grafana/ui';
|
|||||||
import { autoColor } from '../Theme';
|
import { autoColor } from '../Theme';
|
||||||
import { DURATION, NONE, TAG } from '../settings/SpanBarSettings';
|
import { DURATION, NONE, TAG } from '../settings/SpanBarSettings';
|
||||||
import { SpanBarOptions, SpanLinkFunc, TraceSpan, TNil } from '../types';
|
import { SpanBarOptions, SpanLinkFunc, TraceSpan, TNil } from '../types';
|
||||||
import { SpanLinks } from '../types/links';
|
|
||||||
|
|
||||||
import SpanBar from './SpanBar';
|
import SpanBar from './SpanBar';
|
||||||
import { SpanLinksMenu } from './SpanLinks';
|
import { SpanLinksMenu } from './SpanLinks';
|
||||||
@ -404,14 +403,6 @@ export class UnthemedSpanBarRow extends React.PureComponent<SpanBarRowProps> {
|
|||||||
hintClassName = styles.labelRight;
|
hintClassName = styles.labelRight;
|
||||||
}
|
}
|
||||||
|
|
||||||
const countLinks = (links?: SpanLinks): number => {
|
|
||||||
if (!links) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Object.values(links).reduce((count, arr) => count + arr.length, 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TimelineRow
|
<TimelineRow
|
||||||
className={cx(
|
className={cx(
|
||||||
@ -490,32 +481,31 @@ export class UnthemedSpanBarRow extends React.PureComponent<SpanBarRowProps> {
|
|||||||
{createSpanLink &&
|
{createSpanLink &&
|
||||||
(() => {
|
(() => {
|
||||||
const links = createSpanLink(span);
|
const links = createSpanLink(span);
|
||||||
const count = countLinks(links);
|
const count = links?.length || 0;
|
||||||
if (links && count === 1) {
|
if (links && count === 1) {
|
||||||
const link = links.logLinks?.[0] ?? links.metricLinks?.[0] ?? links.traceLinks?.[0] ?? undefined;
|
if (!links[0]) {
|
||||||
if (!link) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
href={link.href}
|
href={links[0].href}
|
||||||
// Needs to have target otherwise preventDefault would not work due to angularRouter.
|
// Needs to have target otherwise preventDefault would not work due to angularRouter.
|
||||||
target={'_blank'}
|
target={'_blank'}
|
||||||
style={{ marginRight: '5px' }}
|
style={{ marginRight: '5px' }}
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
onClick={
|
onClick={
|
||||||
link.onClick
|
links[0].onClick
|
||||||
? (event) => {
|
? (event) => {
|
||||||
if (!(event.ctrlKey || event.metaKey || event.shiftKey) && link.onClick) {
|
if (!(event.ctrlKey || event.metaKey || event.shiftKey) && links[0].onClick) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
link.onClick(event);
|
links[0].onClick(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{link.content}
|
{links[0].content}
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
} else if (links && count > 1) {
|
} else if (links && count > 1) {
|
||||||
|
@ -24,6 +24,7 @@ import { autoColor } from '../../Theme';
|
|||||||
import { Divider } from '../../common/Divider';
|
import { Divider } from '../../common/Divider';
|
||||||
import LabeledList from '../../common/LabeledList';
|
import LabeledList from '../../common/LabeledList';
|
||||||
import { SpanLinkFunc, TNil } from '../../types';
|
import { SpanLinkFunc, TNil } from '../../types';
|
||||||
|
import { SpanLinkType } from '../../types/links';
|
||||||
import { TraceKeyValuePair, TraceLink, TraceLog, TraceSpan, TraceSpanReference } from '../../types/trace';
|
import { TraceKeyValuePair, TraceLink, TraceLog, TraceSpan, TraceSpanReference } from '../../types/trace';
|
||||||
import { uAlignIcon, ubM0, ubMb1, ubMy1, ubTxRightAlign } from '../../uberUtilityStyles';
|
import { uAlignIcon, ubM0, ubMb1, ubMy1, ubTxRightAlign } from '../../uberUtilityStyles';
|
||||||
import { TopOfViewRefType } from '../VirtualizedTraceView';
|
import { TopOfViewRefType } from '../VirtualizedTraceView';
|
||||||
@ -197,14 +198,15 @@ export default function SpanDetail(props: SpanDetailProps) {
|
|||||||
let logLinkButton: JSX.Element | undefined = undefined;
|
let logLinkButton: JSX.Element | undefined = undefined;
|
||||||
if (createSpanLink) {
|
if (createSpanLink) {
|
||||||
const links = createSpanLink(span);
|
const links = createSpanLink(span);
|
||||||
if (links?.logLinks) {
|
const logLinks = links?.filter((link) => link.type === SpanLinkType.Logs);
|
||||||
|
if (links && logLinks && logLinks.length > 0) {
|
||||||
logLinkButton = (
|
logLinkButton = (
|
||||||
<DataLinkButton
|
<DataLinkButton
|
||||||
link={{
|
link={{
|
||||||
...links.logLinks[0],
|
...logLinks[0],
|
||||||
title: 'Logs for this span',
|
title: 'Logs for this span',
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
origin: links.logLinks[0].field,
|
origin: logLinks[0].field,
|
||||||
onClick: (event: React.MouseEvent) => {
|
onClick: (event: React.MouseEvent) => {
|
||||||
reportInteraction('grafana_traces_trace_view_span_link_clicked', {
|
reportInteraction('grafana_traces_trace_view_span_link_clicked', {
|
||||||
datasourceType: datasourceType,
|
datasourceType: datasourceType,
|
||||||
@ -212,7 +214,7 @@ export default function SpanDetail(props: SpanDetailProps) {
|
|||||||
type: 'log',
|
type: 'log',
|
||||||
location: 'spanDetails',
|
location: 'spanDetails',
|
||||||
});
|
});
|
||||||
links?.logLinks?.[0].onClick?.(event);
|
logLinks?.[0].onClick?.(event);
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
buttonProps={{ icon: 'gf-logs' }}
|
buttonProps={{ icon: 'gf-logs' }}
|
||||||
|
@ -2,106 +2,48 @@ import { css } from '@emotion/css';
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
import { config, reportInteraction } from '@grafana/runtime';
|
import { config, reportInteraction } from '@grafana/runtime';
|
||||||
import { useStyles2, MenuGroup, MenuItem, Icon, ContextMenu } from '@grafana/ui';
|
import { useStyles2, MenuItem, Icon, ContextMenu } from '@grafana/ui';
|
||||||
|
|
||||||
import { SpanLinks } from '../types/links';
|
import { SpanLinkDef } from '../types/links';
|
||||||
|
|
||||||
interface SpanLinksProps {
|
interface SpanLinksProps {
|
||||||
links: SpanLinks;
|
links: SpanLinkDef[];
|
||||||
datasourceType: string;
|
datasourceType: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderMenuItems = (
|
const renderMenuItems = (
|
||||||
links: SpanLinks,
|
links: SpanLinkDef[],
|
||||||
styles: ReturnType<typeof getStyles>,
|
styles: ReturnType<typeof getStyles>,
|
||||||
closeMenu: () => void,
|
closeMenu: () => void,
|
||||||
datasourceType: string
|
datasourceType: string
|
||||||
) => {
|
) => {
|
||||||
return (
|
links.sort(function (linkA, linkB) {
|
||||||
<>
|
return (linkA.title || 'link').toLowerCase().localeCompare((linkB.title || 'link').toLowerCase());
|
||||||
{!!links.logLinks?.length ? (
|
});
|
||||||
<MenuGroup label="Logs">
|
|
||||||
{links.logLinks.map((link, i) => (
|
return links.map((link, i) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={i}
|
key={i}
|
||||||
label="Logs for this span"
|
label={link.title || 'Link'}
|
||||||
onClick={
|
onClick={
|
||||||
link.onClick
|
link.onClick
|
||||||
? (event) => {
|
? (event) => {
|
||||||
reportInteraction('grafana_traces_trace_view_span_link_clicked', {
|
reportInteraction(`grafana_traces_trace_view_span_link_clicked`, {
|
||||||
datasourceType: datasourceType,
|
datasourceType: datasourceType,
|
||||||
grafana_version: config.buildInfo.version,
|
grafana_version: config.buildInfo.version,
|
||||||
type: 'log',
|
type: link.type,
|
||||||
location: 'menu',
|
location: 'menu',
|
||||||
});
|
});
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
link.onClick!(event);
|
link.onClick!(event);
|
||||||
closeMenu();
|
closeMenu();
|
||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
url={link.href}
|
url={link.href}
|
||||||
className={styles.menuItem}
|
className={styles.menuItem}
|
||||||
/>
|
/>
|
||||||
))}
|
));
|
||||||
</MenuGroup>
|
|
||||||
) : null}
|
|
||||||
{!!links.metricLinks?.length ? (
|
|
||||||
<MenuGroup label="Metrics">
|
|
||||||
{links.metricLinks.map((link, i) => (
|
|
||||||
<MenuItem
|
|
||||||
key={i}
|
|
||||||
label={link.title ?? 'Metrics for this span'}
|
|
||||||
onClick={
|
|
||||||
link.onClick
|
|
||||||
? (event) => {
|
|
||||||
reportInteraction('grafana_traces_trace_view_span_link_clicked', {
|
|
||||||
datasourceType: datasourceType,
|
|
||||||
grafana_version: config.buildInfo.version,
|
|
||||||
type: 'metric',
|
|
||||||
location: 'menu',
|
|
||||||
});
|
|
||||||
event?.preventDefault();
|
|
||||||
link.onClick!(event);
|
|
||||||
closeMenu();
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
url={link.href}
|
|
||||||
className={styles.menuItem}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</MenuGroup>
|
|
||||||
) : null}
|
|
||||||
{!!links.traceLinks?.length ? (
|
|
||||||
<MenuGroup label="Traces">
|
|
||||||
{links.traceLinks.map((link, i) => (
|
|
||||||
<MenuItem
|
|
||||||
key={i}
|
|
||||||
label={link.title ?? 'View linked span'}
|
|
||||||
onClick={
|
|
||||||
link.onClick
|
|
||||||
? (event) => {
|
|
||||||
reportInteraction('grafana_traces_trace_view_span_link_clicked', {
|
|
||||||
datasourceType: datasourceType,
|
|
||||||
grafana_version: config.buildInfo.version,
|
|
||||||
type: 'trace',
|
|
||||||
location: 'menu',
|
|
||||||
});
|
|
||||||
event?.preventDefault();
|
|
||||||
link.onClick!(event);
|
|
||||||
closeMenu();
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
url={link.href}
|
|
||||||
className={styles.menuItem}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</MenuGroup>
|
|
||||||
) : null}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SpanLinksMenu = ({ links, datasourceType }: SpanLinksProps) => {
|
export const SpanLinksMenu = ({ links, datasourceType }: SpanLinksProps) => {
|
||||||
@ -130,7 +72,7 @@ export const SpanLinksMenu = ({ links, datasourceType }: SpanLinksProps) => {
|
|||||||
<ContextMenu
|
<ContextMenu
|
||||||
onClose={() => setIsMenuOpen(false)}
|
onClose={() => setIsMenuOpen(false)}
|
||||||
renderMenuItems={() => renderMenuItems(links, styles, closeMenu, datasourceType)}
|
renderMenuItems={() => renderMenuItems(links, styles, closeMenu, datasourceType)}
|
||||||
focusOnOpen={true}
|
focusOnOpen={false}
|
||||||
x={menuPosition.x}
|
x={menuPosition.x}
|
||||||
y={menuPosition.y}
|
y={menuPosition.y}
|
||||||
/>
|
/>
|
||||||
|
@ -4,18 +4,20 @@ import { Field } from '@grafana/data';
|
|||||||
|
|
||||||
import { TraceSpan } from './trace';
|
import { TraceSpan } from './trace';
|
||||||
|
|
||||||
|
export enum SpanLinkType {
|
||||||
|
Logs = 'log',
|
||||||
|
Traces = 'trace',
|
||||||
|
Metrics = 'metric',
|
||||||
|
Unknown = 'unknown',
|
||||||
|
}
|
||||||
|
|
||||||
export type SpanLinkDef = {
|
export type SpanLinkDef = {
|
||||||
href: string;
|
href: string;
|
||||||
onClick?: (event: unknown) => void;
|
onClick?: (event: unknown) => void;
|
||||||
content: React.ReactNode;
|
content: React.ReactNode;
|
||||||
title?: string;
|
title?: string;
|
||||||
field: Field;
|
field: Field;
|
||||||
|
type: SpanLinkType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SpanLinks = {
|
export type SpanLinkFunc = (span: TraceSpan) => SpanLinkDef[] | undefined;
|
||||||
logLinks?: SpanLinkDef[];
|
|
||||||
traceLinks?: SpanLinkDef[];
|
|
||||||
metricLinks?: SpanLinkDef[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type SpanLinkFunc = (span: TraceSpan) => SpanLinks | undefined;
|
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
import { DataSourceInstanceSettings, LinkModel, MutableDataFrame } from '@grafana/data';
|
import {
|
||||||
|
DataSourceInstanceSettings,
|
||||||
|
LinkModel,
|
||||||
|
createDataFrame,
|
||||||
|
SupportedTransformationType,
|
||||||
|
DataLinkConfigOrigin,
|
||||||
|
FieldType,
|
||||||
|
} from '@grafana/data';
|
||||||
import { DataSourceSrv, setDataSourceSrv, setTemplateSrv } from '@grafana/runtime';
|
import { DataSourceSrv, setDataSourceSrv, setTemplateSrv } from '@grafana/runtime';
|
||||||
import { TraceToMetricsOptions } from 'app/core/components/TraceToMetrics/TraceToMetricsSettings';
|
import { TraceToMetricsOptions } from 'app/core/components/TraceToMetrics/TraceToMetricsSettings';
|
||||||
import { DatasourceSrv } from 'app/features/plugins/datasource_srv';
|
import { DatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||||
@ -8,10 +15,17 @@ import { LinkSrv, setLinkSrv } from '../../panel/panellinks/link_srv';
|
|||||||
import { TemplateSrv } from '../../templating/template_srv';
|
import { TemplateSrv } from '../../templating/template_srv';
|
||||||
|
|
||||||
import { Trace, TraceSpan } from './components';
|
import { Trace, TraceSpan } from './components';
|
||||||
|
import { SpanLinkType } from './components/types/links';
|
||||||
import { createSpanLinkFactory } from './createSpanLink';
|
import { createSpanLinkFactory } from './createSpanLink';
|
||||||
|
|
||||||
const dummyTraceData = { duration: 10, traceID: 'trace1', traceName: 'test trace' } as unknown as Trace;
|
const dummyTraceData = { duration: 10, traceID: 'trace1', traceName: 'test trace' } as unknown as Trace;
|
||||||
const dummyDataFrame = new MutableDataFrame({ fields: [{ name: 'traceId', values: ['trace1'] }] });
|
const dummyDataFrame = createDataFrame({ fields: [{ name: 'traceId', values: ['trace1'] }] });
|
||||||
|
|
||||||
|
jest.mock('app/core/services/context_srv', () => ({
|
||||||
|
contextSrv: {
|
||||||
|
hasAccessToExplore: () => true,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
describe('createSpanLinkFactory', () => {
|
describe('createSpanLinkFactory', () => {
|
||||||
it('returns no links if there is no data source uid', () => {
|
it('returns no links if there is no data source uid', () => {
|
||||||
@ -22,9 +36,8 @@ describe('createSpanLinkFactory', () => {
|
|||||||
dataFrame: dummyDataFrame,
|
dataFrame: dummyDataFrame,
|
||||||
});
|
});
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
expect(links?.logLinks).toBeUndefined();
|
expect(links).toBeDefined();
|
||||||
expect(links?.metricLinks).toBeUndefined();
|
expect(links).toHaveLength(0);
|
||||||
expect(links?.traceLinks).toHaveLength(0);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should return loki link', () => {
|
describe('should return loki link', () => {
|
||||||
@ -43,8 +56,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
const createLink = setupSpanLinkFactory();
|
const createLink = setupSpanLinkFactory();
|
||||||
expect(createLink).toBeDefined();
|
expect(createLink).toBeDefined();
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{cluster=\\"cluster1\\", hostname=\\"hostname1\\"}","refId":""}]}'
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{cluster=\\"cluster1\\", hostname=\\"hostname1\\"}","refId":""}]}'
|
||||||
@ -68,8 +82,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{ip=\\"192.168.0.1\\"}","refId":""}]}'
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{ip=\\"192.168.0.1\\"}","refId":""}]}'
|
||||||
@ -93,8 +108,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{ip=\\"192.168.0.1\\", host=\\"host\\"}","refId":""}]}'
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{ip=\\"192.168.0.1\\", host=\\"host\\"}","refId":""}]}'
|
||||||
@ -119,8 +135,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T01:01:00.000Z","to":"2020-10-14T01:01:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{hostname=\\"hostname1\\"}","refId":""}]}'
|
'{"range":{"from":"2020-10-14T01:01:00.000Z","to":"2020-10-14T01:01:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{hostname=\\"hostname1\\"}","refId":""}]}'
|
||||||
@ -136,8 +153,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
expect(createLink).toBeDefined();
|
expect(createLink).toBeDefined();
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(decodeURIComponent(linkDef!.href)).toBe(
|
expect(decodeURIComponent(linkDef!.href)).toBe(
|
||||||
'/explore?left=' +
|
'/explore?left=' +
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
@ -157,7 +175,7 @@ describe('createSpanLinkFactory', () => {
|
|||||||
const splitOpenFn = jest.fn();
|
const splitOpenFn = jest.fn();
|
||||||
const createLink = createSpanLinkFactory({
|
const createLink = createSpanLinkFactory({
|
||||||
splitOpenFn,
|
splitOpenFn,
|
||||||
dataFrame: new MutableDataFrame({
|
dataFrame: createDataFrame({
|
||||||
fields: [
|
fields: [
|
||||||
{ name: 'traceID', values: ['testTraceId'] },
|
{ name: 'traceID', values: ['testTraceId'] },
|
||||||
{
|
{
|
||||||
@ -172,8 +190,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
expect(createLink).toBeDefined();
|
expect(createLink).toBeDefined();
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Unknown);
|
||||||
expect(linkDef!.href).toBe('testSpanId');
|
expect(linkDef!.href).toBe('testSpanId');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -197,8 +216,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{service=\\"serviceName\\", pod=\\"podName\\"}","refId":""}]}'
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{service=\\"serviceName\\", pod=\\"podName\\"}","refId":""}]}'
|
||||||
@ -226,8 +246,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{service.name=\\"serviceName\\", pod=\\"podName\\"}","refId":""}]}'
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"{service.name=\\"serviceName\\", pod=\\"podName\\"}","refId":""}]}'
|
||||||
@ -251,7 +272,8 @@ describe('createSpanLinkFactory', () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
expect(links?.logLinks).toBeUndefined();
|
expect(links).toBeDefined();
|
||||||
|
expect(links?.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('interpolates span intrinsics', () => {
|
it('interpolates span intrinsics', () => {
|
||||||
@ -260,8 +282,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
});
|
});
|
||||||
expect(createLink).toBeDefined();
|
expect(createLink).toBeDefined();
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
expect(links?.logLinks).toBeDefined();
|
expect(links).toBeDefined();
|
||||||
expect(decodeURIComponent(links!.logLinks![0].href)).toContain('spanName=\\"operation\\"');
|
expect(links![0].type).toBe(SpanLinkType.Logs);
|
||||||
|
expect(decodeURIComponent(links![0].href)).toContain('spanName=\\"operation\\"');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -289,8 +312,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
});
|
});
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toContain(`${encodeURIComponent('datasource":"splunkUID","queries":[{"query"')}`);
|
expect(linkDef!.href).toContain(`${encodeURIComponent('datasource":"splunkUID","queries":[{"query"')}`);
|
||||||
expect(linkDef!.href).not.toContain(`${encodeURIComponent('datasource":"splunkUID","queries":[{"expr"')}`);
|
expect(linkDef!.href).not.toContain(`${encodeURIComponent('datasource":"splunkUID","queries":[{"expr"')}`);
|
||||||
});
|
});
|
||||||
@ -301,8 +325,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
});
|
});
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toContain(
|
expect(linkDef!.href).toContain(
|
||||||
`${encodeURIComponent('{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"}')}`
|
`${encodeURIComponent('{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"}')}`
|
||||||
);
|
);
|
||||||
@ -321,8 +346,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
expect(createLink).toBeDefined();
|
expect(createLink).toBeDefined();
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"splunkUID","queries":[{"query":"cluster=\\"cluster1\\" hostname=\\"hostname1\\" \\"7946b05c2e2e4e5a\\" \\"6605c7b08e715d6c\\"","refId":""}]}'
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"splunkUID","queries":[{"query":"cluster=\\"cluster1\\" hostname=\\"hostname1\\" \\"7946b05c2e2e4e5a\\" \\"6605c7b08e715d6c\\"","refId":""}]}'
|
||||||
@ -344,8 +370,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"splunkUID","queries":[{"query":"ip=\\"192.168.0.1\\"","refId":""}]}'
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"splunkUID","queries":[{"query":"ip=\\"192.168.0.1\\"","refId":""}]}'
|
||||||
@ -370,8 +397,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"splunkUID","queries":[{"query":"hostname=\\"hostname1\\" ip=\\"192.168.0.1\\"","refId":""}]}'
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"splunkUID","queries":[{"query":"hostname=\\"hostname1\\" ip=\\"192.168.0.1\\"","refId":""}]}'
|
||||||
@ -399,8 +427,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"splunkUID","queries":[{"query":"service=\\"serviceName\\" pod=\\"podName\\"","refId":""}]}'
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"splunkUID","queries":[{"query":"service=\\"serviceName\\" pod=\\"podName\\"","refId":""}]}'
|
||||||
@ -435,9 +464,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
expect(createLink).toBeDefined();
|
expect(createLink).toBeDefined();
|
||||||
|
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
const linkDef = links?.metricLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
|
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Metrics);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"prom1Uid","queries":[{"expr":"customQuery","refId":"A"}]}'
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"prom1Uid","queries":[{"expr":"customQuery","refId":"A"}]}'
|
||||||
@ -458,7 +487,8 @@ describe('createSpanLinkFactory', () => {
|
|||||||
expect(createLink).toBeDefined();
|
expect(createLink).toBeDefined();
|
||||||
|
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
expect(links?.metricLinks).toBeUndefined();
|
expect(links).toBeDefined();
|
||||||
|
expect(links?.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns multiple queries including default', () => {
|
it('returns multiple queries including default', () => {
|
||||||
@ -479,11 +509,12 @@ describe('createSpanLinkFactory', () => {
|
|||||||
expect(createLink).toBeDefined();
|
expect(createLink).toBeDefined();
|
||||||
|
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
expect(links?.metricLinks).toBeDefined();
|
expect(links).toBeDefined();
|
||||||
expect(links?.metricLinks).toHaveLength(3);
|
expect(links).toHaveLength(3);
|
||||||
|
|
||||||
const namedLink = links?.metricLinks?.[0];
|
const namedLink = links?.[0];
|
||||||
expect(namedLink).toBeDefined();
|
expect(namedLink).toBeDefined();
|
||||||
|
expect(namedLink?.type).toBe(SpanLinkType.Metrics);
|
||||||
expect(namedLink!.title).toBe('Named Query');
|
expect(namedLink!.title).toBe('Named Query');
|
||||||
expect(namedLink!.href).toBe(
|
expect(namedLink!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
@ -491,8 +522,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
)}`
|
)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
const defaultLink = links?.metricLinks?.[1];
|
const defaultLink = links?.[1];
|
||||||
expect(defaultLink).toBeDefined();
|
expect(defaultLink).toBeDefined();
|
||||||
|
expect(defaultLink?.type).toBe(SpanLinkType.Metrics);
|
||||||
expect(defaultLink!.title).toBe('defaultQuery');
|
expect(defaultLink!.title).toBe('defaultQuery');
|
||||||
expect(defaultLink!.href).toBe(
|
expect(defaultLink!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
@ -500,8 +532,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
)}`
|
)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
const unnamedQuery = links?.metricLinks?.[2];
|
const unnamedQuery = links?.[2];
|
||||||
expect(unnamedQuery).toBeDefined();
|
expect(unnamedQuery).toBeDefined();
|
||||||
|
expect(unnamedQuery?.type).toBe(SpanLinkType.Metrics);
|
||||||
expect(unnamedQuery!.title).toBeUndefined();
|
expect(unnamedQuery!.title).toBeUndefined();
|
||||||
expect(unnamedQuery!.href).toBe(
|
expect(unnamedQuery!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
@ -526,9 +559,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
expect(createLink).toBeDefined();
|
expect(createLink).toBeDefined();
|
||||||
|
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
const linkDef = links?.metricLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
|
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Metrics);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T00:00:00.000Z","to":"2020-10-14T02:00:01.000Z"},"datasource":"prom1Uid","queries":[{"expr":"customQuery","refId":"A"}]}'
|
'{"range":{"from":"2020-10-14T00:00:00.000Z","to":"2020-10-14T02:00:01.000Z"},"datasource":"prom1Uid","queries":[{"expr":"customQuery","refId":"A"}]}'
|
||||||
@ -566,7 +599,8 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
expect(links).toBeDefined();
|
expect(links).toBeDefined();
|
||||||
expect(links!.metricLinks![0]!.href).toBe(
|
expect(links![0].type).toBe(SpanLinkType.Metrics);
|
||||||
|
expect(links![0].href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"prom1Uid","queries":[{"expr":"metric{job=\\"tns/app\\", pod=\\"sample-pod\\", job=\\"tns/app\\", pod=\\"sample-pod\\"}[5m]","refId":"A"}]}'
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"prom1Uid","queries":[{"expr":"metric{job=\\"tns/app\\", pod=\\"sample-pod\\", job=\\"tns/app\\", pod=\\"sample-pod\\"}[5m]","refId":"A"}]}'
|
||||||
)}`
|
)}`
|
||||||
@ -587,7 +621,7 @@ describe('createSpanLinkFactory', () => {
|
|||||||
createTraceSpan({ references: [{ refType: 'CHILD_OF', spanID: 'parent', traceID: 'traceID' }] })
|
createTraceSpan({ references: [{ refType: 'CHILD_OF', spanID: 'parent', traceID: 'traceID' }] })
|
||||||
);
|
);
|
||||||
|
|
||||||
const traceLinks = links?.traceLinks;
|
const traceLinks = links;
|
||||||
expect(traceLinks).toBeDefined();
|
expect(traceLinks).toBeDefined();
|
||||||
expect(traceLinks).toHaveLength(0);
|
expect(traceLinks).toHaveLength(0);
|
||||||
});
|
});
|
||||||
@ -609,9 +643,12 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const traceLinks = links?.traceLinks;
|
const traceLinks = links;
|
||||||
expect(traceLinks).toBeDefined();
|
expect(traceLinks).toBeDefined();
|
||||||
expect(traceLinks).toHaveLength(2);
|
expect(traceLinks).toHaveLength(2);
|
||||||
|
expect(traceLinks![0].type).toBe(SpanLinkType.Traces);
|
||||||
|
expect(traceLinks![1].type).toBe(SpanLinkType.Traces);
|
||||||
|
|
||||||
expect(traceLinks![0]).toEqual(
|
expect(traceLinks![0]).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
href: 'traceID-span1',
|
href: 'traceID-span1',
|
||||||
@ -651,8 +688,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
});
|
});
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(decodeURIComponent(linkDef!.href)).toContain(
|
expect(decodeURIComponent(linkDef!.href)).toContain(
|
||||||
`datasource":"${searchUID}","queries":[{"query":"cluster:\\"cluster1\\" AND hostname:\\"hostname1\\"","refId":"","metrics":[{"id":"1","type":"logs"}]}]`
|
`datasource":"${searchUID}","queries":[{"query":"cluster:\\"cluster1\\" AND hostname:\\"hostname1\\"","refId":"","metrics":[{"id":"1","type":"logs"}]}]`
|
||||||
);
|
);
|
||||||
@ -664,8 +702,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
});
|
});
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toContain(
|
expect(linkDef!.href).toContain(
|
||||||
`${encodeURIComponent('{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"}')}`
|
`${encodeURIComponent('{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"}')}`
|
||||||
);
|
);
|
||||||
@ -687,8 +726,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
expect(createLink).toBeDefined();
|
expect(createLink).toBeDefined();
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
`{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"${searchUID}","queries":[{"query":"\\"6605c7b08e715d6c\\" AND \\"7946b05c2e2e4e5a\\" AND cluster:\\"cluster1\\" AND hostname:\\"hostname1\\"","refId":"","metrics":[{"id":"1","type":"logs"}]}]}`
|
`{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"${searchUID}","queries":[{"query":"\\"6605c7b08e715d6c\\" AND \\"7946b05c2e2e4e5a\\" AND cluster:\\"cluster1\\" AND hostname:\\"hostname1\\"","refId":"","metrics":[{"id":"1","type":"logs"}]}]}`
|
||||||
@ -715,8 +755,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(decodeURIComponent(linkDef!.href)).toBe(
|
expect(decodeURIComponent(linkDef!.href)).toBe(
|
||||||
`/explore?left={"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"searchUID","queries":[{"query":"\\"7946b05c2e2e4e5a\\"","refId":"","metrics":[{"id":"1","type":"logs"}]}]}`
|
`/explore?left={"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"searchUID","queries":[{"query":"\\"7946b05c2e2e4e5a\\"","refId":"","metrics":[{"id":"1","type":"logs"}]}]}`
|
||||||
);
|
);
|
||||||
@ -739,8 +780,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
`{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"${searchUID}","queries":[{"query":"ip:\\"192.168.0.1\\"","refId":"","metrics":[{"id":"1","type":"logs"}]}]}`
|
`{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"${searchUID}","queries":[{"query":"ip:\\"192.168.0.1\\"","refId":"","metrics":[{"id":"1","type":"logs"}]}]}`
|
||||||
@ -768,8 +810,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
`{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"${searchUID}","queries":[{"query":"hostname:\\"hostname1\\" AND ip:\\"192.168.0.1\\"","refId":"","metrics":[{"id":"1","type":"logs"}]}]}`
|
`{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"${searchUID}","queries":[{"query":"hostname:\\"hostname1\\" AND ip:\\"192.168.0.1\\"","refId":"","metrics":[{"id":"1","type":"logs"}]}]}`
|
||||||
@ -800,8 +843,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
`{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"${searchUID}","queries":[{"query":"service:\\"serviceName\\" AND pod:\\"podName\\"","refId":"","metrics":[{"id":"1","type":"logs"}]}]}`
|
`{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"${searchUID}","queries":[{"query":"service:\\"serviceName\\" AND pod:\\"podName\\"","refId":"","metrics":[{"id":"1","type":"logs"}]}]}`
|
||||||
@ -834,8 +878,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
});
|
});
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(decodeURIComponent(linkDef!.href)).toContain(
|
expect(decodeURIComponent(linkDef!.href)).toContain(
|
||||||
`datasource":"${searchUID}","queries":[{"query":"cluster=\\"cluster1\\" AND hostname=\\"hostname1\\"","refId":""}]`
|
`datasource":"${searchUID}","queries":[{"query":"cluster=\\"cluster1\\" AND hostname=\\"hostname1\\"","refId":""}]`
|
||||||
);
|
);
|
||||||
@ -847,8 +892,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
});
|
});
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toContain(
|
expect(linkDef!.href).toContain(
|
||||||
`${encodeURIComponent('{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"}')}`
|
`${encodeURIComponent('{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"}')}`
|
||||||
);
|
);
|
||||||
@ -870,8 +916,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
expect(createLink).toBeDefined();
|
expect(createLink).toBeDefined();
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
`{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"${searchUID}","queries":[{"query":"\\"6605c7b08e715d6c\\" AND \\"7946b05c2e2e4e5a\\" AND cluster=\\"cluster1\\" AND hostname=\\"hostname1\\"","refId":""}]}`
|
`{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"${searchUID}","queries":[{"query":"\\"6605c7b08e715d6c\\" AND \\"7946b05c2e2e4e5a\\" AND cluster=\\"cluster1\\" AND hostname=\\"hostname1\\"","refId":""}]}`
|
||||||
@ -898,8 +945,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(decodeURIComponent(linkDef!.href)).toBe(
|
expect(decodeURIComponent(linkDef!.href)).toBe(
|
||||||
`/explore?left={"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"searchUID","queries":[{"query":"\\"7946b05c2e2e4e5a\\"","refId":""}]}`
|
`/explore?left={"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"searchUID","queries":[{"query":"\\"7946b05c2e2e4e5a\\"","refId":""}]}`
|
||||||
);
|
);
|
||||||
@ -922,8 +970,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
`{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"${searchUID}","queries":[{"query":"ip=\\"192.168.0.1\\"","refId":""}]}`
|
`{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"${searchUID}","queries":[{"query":"ip=\\"192.168.0.1\\"","refId":""}]}`
|
||||||
@ -951,8 +1000,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
`{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"${searchUID}","queries":[{"query":"hostname=\\"hostname1\\" AND ip=\\"192.168.0.1\\"","refId":""}]}`
|
`{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"${searchUID}","queries":[{"query":"hostname=\\"hostname1\\" AND ip=\\"192.168.0.1\\"","refId":""}]}`
|
||||||
@ -983,8 +1033,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
`{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"${searchUID}","queries":[{"query":"service=\\"serviceName\\" AND pod=\\"podName\\"","refId":""}]}`
|
`{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"${searchUID}","queries":[{"query":"service=\\"serviceName\\" AND pod=\\"podName\\"","refId":""}]}`
|
||||||
@ -1027,8 +1078,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(decodeURIComponent(linkDef!.href)).toContain(
|
expect(decodeURIComponent(linkDef!.href)).toContain(
|
||||||
'"queries":' +
|
'"queries":' +
|
||||||
JSON.stringify([{ expr: '{service="serviceName", pod="podName"} |="serviceName" |="trace1"', refId: '' }])
|
JSON.stringify([{ expr: '{service="serviceName", pod="podName"} |="serviceName" |="trace1"', refId: '' }])
|
||||||
@ -1043,7 +1095,8 @@ describe('createSpanLinkFactory', () => {
|
|||||||
});
|
});
|
||||||
expect(createLink).toBeDefined();
|
expect(createLink).toBeDefined();
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
expect(links?.logLinks).toBeUndefined();
|
expect(links).toBeDefined();
|
||||||
|
expect(links?.length).toEqual(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1071,8 +1124,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
});
|
});
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toContain(`${encodeURIComponent('datasource":"falconLogScaleUID","queries":[{"lsql"')}`);
|
expect(linkDef!.href).toContain(`${encodeURIComponent('datasource":"falconLogScaleUID","queries":[{"lsql"')}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1086,8 +1140,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
expect(createLink).toBeDefined();
|
expect(createLink).toBeDefined();
|
||||||
const links = createLink!(createTraceSpan());
|
const links = createLink!(createTraceSpan());
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"falconLogScaleUID","queries":[{"lsql":"cluster=\\"cluster1\\" OR hostname=\\"hostname1\\" or \\"7946b05c2e2e4e5a\\" or \\"6605c7b08e715d6c\\"","refId":""}]}'
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"falconLogScaleUID","queries":[{"lsql":"cluster=\\"cluster1\\" OR hostname=\\"hostname1\\" or \\"7946b05c2e2e4e5a\\" or \\"6605c7b08e715d6c\\"","refId":""}]}'
|
||||||
@ -1109,8 +1164,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"falconLogScaleUID","queries":[{"lsql":"ip=\\"192.168.0.1\\"","refId":""}]}'
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"falconLogScaleUID","queries":[{"lsql":"ip=\\"192.168.0.1\\"","refId":""}]}'
|
||||||
@ -1135,8 +1191,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"falconLogScaleUID","queries":[{"lsql":"hostname=\\"hostname1\\" OR ip=\\"192.168.0.1\\"","refId":""}]}'
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"falconLogScaleUID","queries":[{"lsql":"hostname=\\"hostname1\\" OR ip=\\"192.168.0.1\\"","refId":""}]}'
|
||||||
@ -1164,8 +1221,9 @@ describe('createSpanLinkFactory', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const linkDef = links?.logLinks?.[0];
|
const linkDef = links?.[0];
|
||||||
expect(linkDef).toBeDefined();
|
expect(linkDef).toBeDefined();
|
||||||
|
expect(linkDef?.type).toBe(SpanLinkType.Logs);
|
||||||
expect(linkDef!.href).toBe(
|
expect(linkDef!.href).toBe(
|
||||||
`/explore?left=${encodeURIComponent(
|
`/explore?left=${encodeURIComponent(
|
||||||
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"falconLogScaleUID","queries":[{"lsql":"service=\\"serviceName\\" OR pod=\\"podName\\"","refId":""}]}'
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"falconLogScaleUID","queries":[{"lsql":"service=\\"serviceName\\" OR pod=\\"podName\\"","refId":""}]}'
|
||||||
@ -1175,6 +1233,47 @@ describe('createSpanLinkFactory', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('dataFrame links', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
setDataSourceSrv({
|
||||||
|
getInstanceSettings() {
|
||||||
|
return { uid: 'loki1_uid', name: 'loki1', type: 'loki' } as unknown as DataSourceInstanceSettings;
|
||||||
|
},
|
||||||
|
} as unknown as DataSourceSrv);
|
||||||
|
|
||||||
|
setLinkSrv(new LinkSrv());
|
||||||
|
setTemplateSrv(new TemplateSrv());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates multiple span links for the dataframe links', () => {
|
||||||
|
const multiLinkDataFrame = createMultiLinkDataFrame();
|
||||||
|
const splitOpenFn = jest.fn();
|
||||||
|
const createLink = createSpanLinkFactory({
|
||||||
|
splitOpenFn,
|
||||||
|
dataFrame: multiLinkDataFrame,
|
||||||
|
trace: dummyTraceData,
|
||||||
|
});
|
||||||
|
|
||||||
|
const links = createLink!(createTraceSpan());
|
||||||
|
expect(links).toBeDefined();
|
||||||
|
expect(links?.length).toEqual(3);
|
||||||
|
expect(links![0].href).toBe('testSpanId');
|
||||||
|
expect(links![0].type).toBe(SpanLinkType.Unknown);
|
||||||
|
expect(links![1].href).toBe(
|
||||||
|
`/explore?left=${encodeURIComponent(
|
||||||
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"message":"SELECT * FROM superhero WHERE name=host"}]}'
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
expect(links![1].type).toBe(SpanLinkType.Unknown);
|
||||||
|
expect(links![2].href).toBe(
|
||||||
|
`/explore?left=${encodeURIComponent(
|
||||||
|
'{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"loki1_uid","queries":[{"expr":"go_memstats_heap_inuse_bytes{job=\'host\'}"}]}'
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
expect(links![2].type).toBe(SpanLinkType.Unknown);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
function setupSpanLinkFactory(options: Partial<TraceToLogsOptionsV2> = {}, datasourceUid = 'lokiUid') {
|
function setupSpanLinkFactory(options: Partial<TraceToLogsOptionsV2> = {}, datasourceUid = 'lokiUid') {
|
||||||
const splitOpenFn = jest.fn();
|
const splitOpenFn = jest.fn();
|
||||||
return createSpanLinkFactory({
|
return createSpanLinkFactory({
|
||||||
@ -1232,3 +1331,68 @@ function createTraceSpan(overrides: Partial<TraceSpan> = {}) {
|
|||||||
...overrides,
|
...overrides,
|
||||||
} as TraceSpan;
|
} as TraceSpan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createMultiLinkDataFrame() {
|
||||||
|
return createDataFrame({
|
||||||
|
fields: [
|
||||||
|
{ name: 'traceID', values: ['testTraceId'] },
|
||||||
|
{
|
||||||
|
name: 'spanID',
|
||||||
|
config: { links: [{ title: 'link', url: '${__data.fields.spanID}' }] },
|
||||||
|
values: ['testSpanId'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tags',
|
||||||
|
type: FieldType.other,
|
||||||
|
config: {
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
internal: {
|
||||||
|
query: {
|
||||||
|
message: 'SELECT * FROM superhero WHERE name=${job}',
|
||||||
|
},
|
||||||
|
datasourceUid: 'loki1_uid',
|
||||||
|
datasourceName: 'loki1',
|
||||||
|
transformations: [
|
||||||
|
{
|
||||||
|
type: SupportedTransformationType.Regex,
|
||||||
|
expression: '{(?=[^\\}]*\\bkey":"host")[^\\}]*\\bvalue":"(.*?)".*}',
|
||||||
|
mapValue: 'job',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
url: '',
|
||||||
|
title: 'Test',
|
||||||
|
origin: DataLinkConfigOrigin.Correlations,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
internal: {
|
||||||
|
query: {
|
||||||
|
expr: "go_memstats_heap_inuse_bytes{job='${job}'}",
|
||||||
|
},
|
||||||
|
datasourceUid: 'loki1_uid',
|
||||||
|
datasourceName: 'loki1',
|
||||||
|
transformations: [
|
||||||
|
{
|
||||||
|
type: SupportedTransformationType.Regex,
|
||||||
|
expression: '{(?=[^\\}]*\\bkey":"host")[^\\}]*\\bvalue":"(.*?)".*}',
|
||||||
|
mapValue: 'job',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
url: '',
|
||||||
|
title: 'Test2',
|
||||||
|
origin: DataLinkConfigOrigin.Correlations,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
key: 'host',
|
||||||
|
value: 'host',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -23,10 +23,10 @@ import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
|||||||
import { PromQuery } from 'app/plugins/datasource/prometheus/types';
|
import { PromQuery } from 'app/plugins/datasource/prometheus/types';
|
||||||
|
|
||||||
import { LokiQuery } from '../../../plugins/datasource/loki/types';
|
import { LokiQuery } from '../../../plugins/datasource/loki/types';
|
||||||
import { getFieldLinksForExplore, getVariableUsageInfo } from '../utils/links';
|
import { ExploreFieldLinkModel, getFieldLinksForExplore, getVariableUsageInfo } from '../utils/links';
|
||||||
|
|
||||||
import { SpanLinkFunc, Trace, TraceSpan } from './components';
|
import { SpanLinkDef, SpanLinkFunc, Trace, TraceSpan } from './components';
|
||||||
import { SpanLinks } from './components/types/links';
|
import { SpanLinkType } from './components/types/links';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a factory for the link creator. It returns the function mainly so it can return undefined in which case
|
* This is a factory for the link creator. It returns the function mainly so it can return undefined in which case
|
||||||
@ -54,60 +54,62 @@ export function createSpanLinkFactory({
|
|||||||
|
|
||||||
let scopedVars = scopedVarsFromTrace(trace);
|
let scopedVars = scopedVarsFromTrace(trace);
|
||||||
const hasLinks = dataFrame.fields.some((f) => Boolean(f.config.links?.length));
|
const hasLinks = dataFrame.fields.some((f) => Boolean(f.config.links?.length));
|
||||||
const legacyFormat = dataFrame.fields.length === 1;
|
|
||||||
|
|
||||||
if (legacyFormat || !hasLinks) {
|
const createSpanLinks = legacyCreateSpanLinkFactory(
|
||||||
// if the dataframe contains just a single blob of data (legacy format) or does not have any links configured,
|
splitOpenFn,
|
||||||
// let's try to use the old legacy path.
|
// We need this to make the types happy but for this branch of code it does not matter which field we supply.
|
||||||
// TODO: This was mainly a backward compatibility thing but at this point can probably be removed.
|
dataFrame.fields[0],
|
||||||
return legacyCreateSpanLinkFactory(
|
traceToLogsOptions,
|
||||||
splitOpenFn,
|
traceToMetricsOptions,
|
||||||
// We need this to make the types happy but for this branch of code it does not matter which field we supply.
|
createFocusSpanLink,
|
||||||
dataFrame.fields[0],
|
scopedVars
|
||||||
traceToLogsOptions,
|
);
|
||||||
traceToMetricsOptions,
|
|
||||||
createFocusSpanLink,
|
|
||||||
scopedVars
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasLinks) {
|
return function SpanLink(span: TraceSpan): SpanLinkDef[] | undefined {
|
||||||
return function SpanLink(span: TraceSpan): SpanLinks | undefined {
|
let spanLinks = createSpanLinks(span);
|
||||||
|
|
||||||
|
if (hasLinks) {
|
||||||
scopedVars = {
|
scopedVars = {
|
||||||
...scopedVars,
|
...scopedVars,
|
||||||
...scopedVarsFromSpan(span),
|
...scopedVarsFromSpan(span),
|
||||||
};
|
};
|
||||||
// We should be here only if there are some links in the dataframe
|
// We should be here only if there are some links in the dataframe
|
||||||
const field = dataFrame.fields.find((f) => Boolean(f.config.links?.length))!;
|
const fields = dataFrame.fields.filter((f) => Boolean(f.config.links?.length))!;
|
||||||
try {
|
try {
|
||||||
const links = getFieldLinksForExplore({
|
let links: ExploreFieldLinkModel[] = [];
|
||||||
field,
|
fields.forEach((field) => {
|
||||||
rowIndex: span.dataFrameRowIndex!,
|
const fieldLinksForExplore = getFieldLinksForExplore({
|
||||||
splitOpenFn,
|
field,
|
||||||
range: getTimeRangeFromSpan(span),
|
rowIndex: span.dataFrameRowIndex!,
|
||||||
dataFrame,
|
splitOpenFn,
|
||||||
vars: scopedVars,
|
range: getTimeRangeFromSpan(span),
|
||||||
|
dataFrame,
|
||||||
|
vars: scopedVars,
|
||||||
|
});
|
||||||
|
links = links.concat(fieldLinksForExplore);
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
const newSpanLinks: SpanLinkDef[] = links.map((link) => {
|
||||||
logLinks: [
|
return {
|
||||||
{
|
title: link.title,
|
||||||
href: links[0].href,
|
href: link.href,
|
||||||
onClick: links[0].onClick,
|
onClick: link.onClick,
|
||||||
content: <Icon name="gf-logs" title="Explore the logs for this in split view" />,
|
content: <Icon name="link" title={link.title || 'Link'} />,
|
||||||
field: links[0].origin,
|
field: link.origin,
|
||||||
},
|
type: SpanLinkType.Unknown,
|
||||||
],
|
};
|
||||||
};
|
});
|
||||||
|
|
||||||
|
spanLinks.push.apply(spanLinks, newSpanLinks);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// It's fairly easy to crash here for example if data source defines wrong interpolation in the data link
|
// It's fairly easy to crash here for example if data source defines wrong interpolation in the data link
|
||||||
console.error(error);
|
console.error(error);
|
||||||
return undefined;
|
return spanLinks;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
return spanLinks;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -134,12 +136,12 @@ function legacyCreateSpanLinkFactory(
|
|||||||
metricsDataSourceSettings = getDatasourceSrv().getInstanceSettings(traceToMetricsOptions.datasourceUid);
|
metricsDataSourceSettings = getDatasourceSrv().getInstanceSettings(traceToMetricsOptions.datasourceUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return function SpanLink(span: TraceSpan): SpanLinks {
|
return function SpanLink(span: TraceSpan): SpanLinkDef[] {
|
||||||
scopedVars = {
|
scopedVars = {
|
||||||
...scopedVars,
|
...scopedVars,
|
||||||
...scopedVarsFromSpan(span),
|
...scopedVarsFromSpan(span),
|
||||||
};
|
};
|
||||||
const links: SpanLinks = { traceLinks: [] };
|
const links: SpanLinkDef[] = [];
|
||||||
let query: DataQuery | undefined;
|
let query: DataQuery | undefined;
|
||||||
let tags = '';
|
let tags = '';
|
||||||
|
|
||||||
@ -216,21 +218,20 @@ function legacyCreateSpanLinkFactory(
|
|||||||
replaceVariables: getTemplateSrv().replace.bind(getTemplateSrv()),
|
replaceVariables: getTemplateSrv().replace.bind(getTemplateSrv()),
|
||||||
});
|
});
|
||||||
|
|
||||||
links.logLinks = [
|
links.push({
|
||||||
{
|
href: link.href,
|
||||||
href: link.href,
|
title: 'Related logs',
|
||||||
onClick: link.onClick,
|
onClick: link.onClick,
|
||||||
content: <Icon name="gf-logs" title="Explore the logs for this in split view" />,
|
content: <Icon name="gf-logs" title="Explore the logs for this in split view" />,
|
||||||
field,
|
field,
|
||||||
},
|
type: SpanLinkType.Logs,
|
||||||
];
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get metrics links
|
// Get metrics links
|
||||||
if (metricsDataSourceSettings && traceToMetricsOptions?.queries) {
|
if (metricsDataSourceSettings && traceToMetricsOptions?.queries) {
|
||||||
links.metricLinks = [];
|
|
||||||
for (const query of traceToMetricsOptions.queries) {
|
for (const query of traceToMetricsOptions.queries) {
|
||||||
const expr = buildMetricsQuery(query, traceToMetricsOptions?.tags || [], span);
|
const expr = buildMetricsQuery(query, traceToMetricsOptions?.tags || [], span);
|
||||||
const dataLink: DataLink<PromQuery> = {
|
const dataLink: DataLink<PromQuery> = {
|
||||||
@ -263,12 +264,13 @@ function legacyCreateSpanLinkFactory(
|
|||||||
replaceVariables: getTemplateSrv().replace.bind(getTemplateSrv()),
|
replaceVariables: getTemplateSrv().replace.bind(getTemplateSrv()),
|
||||||
});
|
});
|
||||||
|
|
||||||
links.metricLinks.push({
|
links.push({
|
||||||
title: query?.name,
|
title: query?.name,
|
||||||
href: link.href,
|
href: link.href,
|
||||||
onClick: link.onClick,
|
onClick: link.onClick,
|
||||||
content: <Icon name="chart-line" title="Explore metrics for this span" />,
|
content: <Icon name="chart-line" title="Explore metrics for this span" />,
|
||||||
field,
|
field,
|
||||||
|
type: SpanLinkType.Metrics,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -283,12 +285,13 @@ function legacyCreateSpanLinkFactory(
|
|||||||
|
|
||||||
const link = createFocusSpanLink(reference.traceID, reference.spanID);
|
const link = createFocusSpanLink(reference.traceID, reference.spanID);
|
||||||
|
|
||||||
links.traceLinks!.push({
|
links!.push({
|
||||||
href: link.href,
|
href: link.href,
|
||||||
title: reference.span ? reference.span.operationName : 'View linked span',
|
title: reference.span ? reference.span.operationName : 'View linked span',
|
||||||
content: <Icon name="link" title="View linked span" />,
|
content: <Icon name="link" title="View linked span" />,
|
||||||
onClick: link.onClick,
|
onClick: link.onClick,
|
||||||
field: link.origin,
|
field: link.origin,
|
||||||
|
type: SpanLinkType.Traces,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -297,12 +300,13 @@ function legacyCreateSpanLinkFactory(
|
|||||||
for (const reference of span.subsidiarilyReferencedBy) {
|
for (const reference of span.subsidiarilyReferencedBy) {
|
||||||
const link = createFocusSpanLink(reference.traceID, reference.spanID);
|
const link = createFocusSpanLink(reference.traceID, reference.spanID);
|
||||||
|
|
||||||
links.traceLinks!.push({
|
links!.push({
|
||||||
href: link.href,
|
href: link.href,
|
||||||
title: reference.span ? reference.span.operationName : 'View linked span',
|
title: reference.span ? reference.span.operationName : 'View linked span',
|
||||||
content: <Icon name="link" title="View linked span" />,
|
content: <Icon name="link" title="View linked span" />,
|
||||||
onClick: link.onClick,
|
onClick: link.onClick,
|
||||||
field: link.origin,
|
field: link.origin,
|
||||||
|
type: SpanLinkType.Traces,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,6 +358,61 @@ describe('explore links utils', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns internal links within a result consistent with trace data', () => {
|
||||||
|
const transformationLink: DataLink = {
|
||||||
|
title: '',
|
||||||
|
url: '',
|
||||||
|
internal: {
|
||||||
|
query: { query: 'http_requests{env=${msg}}' },
|
||||||
|
datasourceUid: 'uid_1',
|
||||||
|
datasourceName: 'test_ds',
|
||||||
|
transformations: [
|
||||||
|
{
|
||||||
|
type: SupportedTransformationType.Regex,
|
||||||
|
expression: '{(?=[^\\}]*\\bkey":"keyA")[^\\}]*\\bvalue":"(.*?)".*}',
|
||||||
|
field: 'serviceTags',
|
||||||
|
mapValue: 'msg',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const { field, range, dataFrame } = setup(transformationLink, true, {
|
||||||
|
name: 'serviceTags',
|
||||||
|
type: FieldType.other,
|
||||||
|
values: [
|
||||||
|
[
|
||||||
|
{ value: 'broccoli', key: 'keyA' },
|
||||||
|
{ value: 'apple', key: 'keyB' },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{ key: 'keyA', value: 'cauliflower' },
|
||||||
|
{ value: 'durian', key: 'keyB' },
|
||||||
|
],
|
||||||
|
],
|
||||||
|
config: {
|
||||||
|
links: [transformationLink],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const links = [
|
||||||
|
getFieldLinksForExplore({ field, rowIndex: 0, range, dataFrame }),
|
||||||
|
getFieldLinksForExplore({ field, rowIndex: 1, range, dataFrame }),
|
||||||
|
];
|
||||||
|
expect(links[0]).toHaveLength(1);
|
||||||
|
expect(links[0][0].href).toBe(
|
||||||
|
`/explore?left=${encodeURIComponent(
|
||||||
|
'{"range":{"from":"now-1h","to":"now"},"datasource":"uid_1","queries":[{"query":"http_requests{env=broccoli}"}]}'
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
expect(links[1]).toHaveLength(1);
|
||||||
|
expect(links[1][0].href).toBe(
|
||||||
|
`/explore?left=${encodeURIComponent(
|
||||||
|
'{"range":{"from":"now-1h","to":"now"},"datasource":"uid_1","queries":[{"query":"http_requests{env=cauliflower}"}]}'
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('returns internal links with logfmt with stringified booleans', () => {
|
it('returns internal links with logfmt with stringified booleans', () => {
|
||||||
const transformationLink: DataLink = {
|
const transformationLink: DataLink = {
|
||||||
title: '',
|
title: '',
|
||||||
@ -684,7 +739,7 @@ const ROW_WITH_NULL_VALUE = { value: null, index: 1 };
|
|||||||
function setup(
|
function setup(
|
||||||
link: DataLink,
|
link: DataLink,
|
||||||
hasAccess = true,
|
hasAccess = true,
|
||||||
fieldOverride?: Field<string | null>,
|
fieldOverride?: Field<string | Array<{ key: string; value: string }> | null>, // key/value array for traceView fields
|
||||||
dataFrameOtherFieldOverride?: Field[]
|
dataFrameOtherFieldOverride?: Field[]
|
||||||
) {
|
) {
|
||||||
setLinkSrv({
|
setLinkSrv({
|
||||||
|
Loading…
Reference in New Issue
Block a user