Traces: Span bar label (#50931)

* Add SpanBarSettings

* Add SpanBarSettings to Jaeger

* Add SpanBarSettings to Zipkin

* Updated title

* Add dropdown to select identifer and make duration a default option

* Show duration by default

* Add option to hide

* Move identifers into constants

* Add process

* Update text

* Update placeholders

* Text/meta data updates

* Added tests

* Added docs

* Update find

* Merge tag and prcoess options

* Update docs

* Updated tests

* Update betterer results and trace view to match

* Updated docs
This commit is contained in:
Joey Tawadrous 2022-07-06 08:14:03 +01:00 committed by GitHub
parent 21591be469
commit 01130f22b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 8611 additions and 8 deletions

File diff suppressed because it is too large Load Diff

View File

@ -66,6 +66,16 @@ This is a configuration for the beta Node Graph visualization. The Node Graph is
-- **Enable Node Graph -** Enables the Node Graph visualization. -- **Enable Node Graph -** Enables the Node Graph visualization.
### Span bar label
You can configure the span bar label. The span bar label allows you add additional information to the span bar row.
Select one of the following four options. The default selection is Duration.
- **None -** Do not show any additional information on the span bar row.
- **Duration -** Show the span duration on the span bar row.
- **Tag -** Show the span tag on the span bar row. Note: You will also need to specify the tag key to use to get the tag value. For example, `span.kind`.
## Query traces ## Query traces
You can query and display traces from Jaeger via [Explore]({{< relref "../explore/" >}}). You can query and display traces from Jaeger via [Explore]({{< relref "../explore/" >}}).

View File

@ -84,6 +84,16 @@ This is a configuration for the Loki search query type.
-- **Data source -** The Loki instance in which you want to search traces. You must configure derived fields in the Loki instance. -- **Data source -** The Loki instance in which you want to search traces. You must configure derived fields in the Loki instance.
### Span bar label
You can configure the span bar label. The span bar label allows you add additional information to the span bar row.
Select one of the following four options. The default selection is Duration.
- **None -** Do not show any additional information on the span bar row.
- **Duration -** Show the span duration on the span bar row.
- **Tag -** Show the span tag on the span bar row. Note: You will also need to specify the tag key to use to get the tag value. For example, `span.kind`.
## Query traces ## Query traces
You can query and display traces from Tempo via [Explore]({{< relref "../explore/" >}}). You can query and display traces from Tempo via [Explore]({{< relref "../explore/" >}}).

View File

@ -65,6 +65,16 @@ This is a configuration for the beta Node Graph visualization. The Node Graph is
-- **Enable Node Graph -** Enables the Node Graph visualization. -- **Enable Node Graph -** Enables the Node Graph visualization.
### Span bar label
You can configure the span bar label. The span bar label allows you add additional information to the span bar row.
Select one of the following four options. The default selection is Duration.
- **None -** Do not show any additional information on the span bar row.
- **Duration -** Show the span duration on the span bar row.
- **Tag -** Show the span tag on the span bar row. Note: You will also need to specify the tag key to use to get the tag value. For example, `span.kind`.
## Query traces ## Query traces
Querying and displaying traces from Zipkin is available via [Explore]({{< relref "../explore/" >}}). Querying and displaying traces from Zipkin is available via [Explore]({{< relref "../explore/" >}}).

View File

@ -16,6 +16,8 @@ import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event'; import userEvent from '@testing-library/user-event';
import React from 'react'; import React from 'react';
import { NONE, DURATION, TAG } from '../settings/SpanBarSettings';
import SpanBarRow from './SpanBarRow'; import SpanBarRow from './SpanBarRow';
describe('<SpanBarRow>', () => { describe('<SpanBarRow>', () => {
@ -43,11 +45,10 @@ describe('<SpanBarRow>', () => {
showErrorIcon: false, showErrorIcon: false,
getViewedBounds: () => ({ start: 0, end: 1 }), getViewedBounds: () => ({ start: 0, end: 1 }),
span: { span: {
duration: 'test-duration', duration: 9000,
hasChildren: true, hasChildren: true,
process: { process: {
serviceName: 'service-name', serviceName: 'service-name',
tags: [],
}, },
spanID, spanID,
logs: [], logs: [],
@ -181,4 +182,89 @@ describe('<SpanBarRow>', () => {
); );
expect(screen.getAllByTestId('SpanLinksMenu')).toHaveLength(1); expect(screen.getAllByTestId('SpanLinksMenu')).toHaveLength(1);
}); });
describe('render span bar label', () => {
it('with default value', () => {
render(<SpanBarRow {...props} />);
expect(screen.getByText('(9ms)')).toBeInTheDocument();
});
it('with none value', () => {
const testProps = Object.assign(
{
spanBarOptions: {
type: NONE,
},
},
props
);
render(<SpanBarRow {...testProps} />);
expect(screen.queryByText('(9ms)')).not.toBeInTheDocument();
});
it('with duration value', () => {
const testProps = Object.assign(
{
spanBarOptions: {
type: DURATION,
},
},
props
);
render(<SpanBarRow {...testProps} />);
expect(screen.getByText('(9ms)')).toBeInTheDocument();
});
it('with tag value', () => {
const testProps = Object.assign(
{
spanBarOptions: {
type: TAG,
tag: 'tag',
},
},
{
...props,
span: {
process: {},
tags: [
{
key: 'tag',
value: 'tag-value',
},
],
},
}
);
render(<SpanBarRow {...testProps} />);
expect(screen.getByText('(tag-value)')).toBeInTheDocument();
});
it('with process value', () => {
let testProps = Object.assign(
{
spanBarOptions: {
type: TAG,
tag: 'tag',
},
},
{
...props,
span: {
process: {
tags: [
{
key: 'tag',
value: 'process-value',
},
],
},
tags: [],
},
}
);
render(<SpanBarRow {...testProps} />);
expect(screen.getByText('(process-value)')).toBeInTheDocument();
});
});
}); });

View File

@ -18,11 +18,12 @@ import * as React from 'react';
import IoAlert from 'react-icons/lib/io/alert'; import IoAlert from 'react-icons/lib/io/alert';
import IoArrowRightA from 'react-icons/lib/io/arrow-right-a'; import IoArrowRightA from 'react-icons/lib/io/arrow-right-a';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2, TraceKeyValuePair } from '@grafana/data';
import { stylesFactory, withTheme2 } from '@grafana/ui'; import { stylesFactory, withTheme2 } from '@grafana/ui';
import { autoColor } from '../Theme'; import { autoColor } from '../Theme';
import { SpanLinkFunc, TNil } from '../types'; import { DURATION, NONE, TAG } from '../settings/SpanBarSettings';
import { SpanBarOptions, SpanLinkFunc, TNil } from '../types';
import { SpanLinks } from '../types/links'; import { SpanLinks } from '../types/links';
import { TraceSpan } from '../types/trace'; import { TraceSpan } from '../types/trace';
@ -290,6 +291,7 @@ type SpanBarRowProps = {
className?: string; className?: string;
theme: GrafanaTheme2; theme: GrafanaTheme2;
color: string; color: string;
spanBarOptions: SpanBarOptions | undefined;
columnDivision: number; columnDivision: number;
isChildrenExpanded: boolean; isChildrenExpanded: boolean;
isDetailExpanded: boolean; isDetailExpanded: boolean;
@ -352,6 +354,7 @@ export class UnthemedSpanBarRow extends React.PureComponent<SpanBarRowProps> {
const { const {
className, className,
color, color,
spanBarOptions,
columnDivision, columnDivision,
isChildrenExpanded, isChildrenExpanded,
isDetailExpanded, isDetailExpanded,
@ -379,6 +382,7 @@ export class UnthemedSpanBarRow extends React.PureComponent<SpanBarRowProps> {
process: { serviceName }, process: { serviceName },
} = span; } = span;
const label = formatDuration(duration); const label = formatDuration(duration);
const viewBounds = getViewedBounds(span.startTime, span.startTime + span.duration); const viewBounds = getViewedBounds(span.startTime, span.startTime + span.duration);
const viewStart = viewBounds.start; const viewStart = viewBounds.start;
const viewEnd = viewBounds.end; const viewEnd = viewBounds.end;
@ -473,7 +477,7 @@ export class UnthemedSpanBarRow extends React.PureComponent<SpanBarRowProps> {
)} )}
</span> </span>
<small className={styles.endpointName}>{rpc ? rpc.operationName : operationName}</small> <small className={styles.endpointName}>{rpc ? rpc.operationName : operationName}</small>
<small className={styles.endpointName}> | {label}</small> <small className={styles.endpointName}> {this.getSpanBarLabel(span, spanBarOptions, label)}</small>
</a> </a>
{createSpanLink && {createSpanLink &&
(() => { (() => {
@ -542,6 +546,35 @@ export class UnthemedSpanBarRow extends React.PureComponent<SpanBarRowProps> {
</TimelineRow> </TimelineRow>
); );
} }
getSpanBarLabel = (span: TraceSpan, spanBarOptions: SpanBarOptions | undefined, duration: string) => {
const type = spanBarOptions?.type ?? '';
if (type === NONE) {
return '';
} else if (type === '' || type === DURATION) {
return `(${duration})`;
} else if (type === TAG) {
const tagKey = spanBarOptions?.tag?.trim() ?? '';
if (tagKey !== '' && span.tags) {
const tag = span.tags?.find((tag: TraceKeyValuePair) => {
return tag.key === tagKey;
});
const process = span.process?.tags?.find((process: TraceKeyValuePair) => {
return process.key === tagKey;
});
if (tag) {
return `(${tag.value})`;
}
if (process) {
return `(${process.value})`;
}
}
}
return '';
};
} }
export default withTheme2(UnthemedSpanBarRow); export default withTheme2(UnthemedSpanBarRow);

View File

@ -23,7 +23,7 @@ import { stylesFactory, withTheme2, ToolbarButton } from '@grafana/ui';
import { Accessors } from '../ScrollManager'; import { Accessors } from '../ScrollManager';
import { PEER_SERVICE } from '../constants/tag-keys'; import { PEER_SERVICE } from '../constants/tag-keys';
import { SpanLinkFunc, TNil } from '../types'; import { SpanBarOptions, SpanLinkFunc, TNil } from '../types';
import TTraceTimeline from '../types/TTraceTimeline'; import TTraceTimeline from '../types/TTraceTimeline';
import { TraceLog, TraceSpan, Trace, TraceKeyValuePair, TraceLink, TraceSpanReference } from '../types/trace'; import { TraceLog, TraceSpan, Trace, TraceKeyValuePair, TraceLink, TraceSpanReference } from '../types/trace';
import { getColorByKey } from '../utils/color-generator'; import { getColorByKey } from '../utils/color-generator';
@ -89,6 +89,7 @@ type TVirtualizedTraceViewOwnProps = {
scrollToFirstVisibleSpan: () => void; scrollToFirstVisibleSpan: () => void;
registerAccessors: (accesors: Accessors) => void; registerAccessors: (accesors: Accessors) => void;
trace: Trace; trace: Trace;
spanBarOptions: SpanBarOptions | undefined;
linksGetter: (span: TraceSpan, items: TraceKeyValuePair[], itemIndex: number) => TraceLink[]; linksGetter: (span: TraceSpan, items: TraceKeyValuePair[], itemIndex: number) => TraceLink[];
childrenToggle: (spanID: string) => void; childrenToggle: (spanID: string) => void;
clearShouldScrollToFirstUiFindMatch: () => void; clearShouldScrollToFirstUiFindMatch: () => void;
@ -387,6 +388,7 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
findMatchesIDs, findMatchesIDs,
spanNameColumnWidth, spanNameColumnWidth,
trace, trace,
spanBarOptions,
hoverIndentGuideIds, hoverIndentGuideIds,
addHoverIndentGuideId, addHoverIndentGuideId,
removeHoverIndentGuideId, removeHoverIndentGuideId,
@ -440,6 +442,7 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
clippingLeft={this.getClipping().left} clippingLeft={this.getClipping().left}
clippingRight={this.getClipping().right} clippingRight={this.getClipping().right}
color={color} color={color}
spanBarOptions={spanBarOptions}
columnDivision={spanNameColumnWidth} columnDivision={spanNameColumnWidth}
isChildrenExpanded={!isCollapsed} isChildrenExpanded={!isCollapsed}
isDetailExpanded={isDetailExpanded} isDetailExpanded={isDetailExpanded}

View File

@ -21,6 +21,7 @@ import { stylesFactory, withTheme2 } from '@grafana/ui';
import { Accessors } from '../ScrollManager'; import { Accessors } from '../ScrollManager';
import { autoColor } from '../Theme'; import { autoColor } from '../Theme';
import { merge as mergeShortcuts } from '../keyboard-shortcuts'; import { merge as mergeShortcuts } from '../keyboard-shortcuts';
import { SpanBarOptions } from '../settings/SpanBarSettings';
import { SpanLinkFunc, TNil } from '../types'; import { SpanLinkFunc, TNil } from '../types';
import TTraceTimeline from '../types/TTraceTimeline'; import TTraceTimeline from '../types/TTraceTimeline';
import { TraceSpan, Trace, TraceLog, TraceKeyValuePair, TraceLink, TraceSpanReference } from '../types/trace'; import { TraceSpan, Trace, TraceLog, TraceKeyValuePair, TraceLink, TraceSpanReference } from '../types/trace';
@ -75,6 +76,7 @@ type TProps = TExtractUiFindFromStateReturn & {
scrollToFirstVisibleSpan: () => void; scrollToFirstVisibleSpan: () => void;
traceTimeline: TTraceTimeline; traceTimeline: TTraceTimeline;
trace: Trace; trace: Trace;
spanBarOptions: SpanBarOptions | undefined;
updateNextViewRangeTime: (update: ViewRangeTimeUpdate) => void; updateNextViewRangeTime: (update: ViewRangeTimeUpdate) => void;
updateViewRangeTime: TUpdateViewRangeTimeFunction; updateViewRangeTime: TUpdateViewRangeTimeFunction;
viewRange: ViewRange; viewRange: ViewRange;

View File

@ -1,5 +1,6 @@
export { default as TraceTimelineViewer } from './TraceTimelineViewer'; export { default as TraceTimelineViewer } from './TraceTimelineViewer';
export { default as TracePageHeader } from './TracePageHeader'; export { default as TracePageHeader } from './TracePageHeader';
export { default as SpanBarSettings } from './settings/SpanBarSettings';
export * from './types'; export * from './types';
export * from './TraceTimelineViewer/types'; export * from './TraceTimelineViewer/types';
export { default as DetailState } from './TraceTimelineViewer/SpanDetail/DetailState'; export { default as DetailState } from './TraceTimelineViewer/SpanDetail/DetailState';

View File

@ -0,0 +1,90 @@
import { css } from '@emotion/css';
import React from 'react';
import {
DataSourceJsonData,
DataSourcePluginOptionsEditorProps,
GrafanaTheme,
toOption,
updateDatasourcePluginJsonDataOption,
} from '@grafana/data';
import { InlineField, InlineFieldRow, Input, Select, useStyles } from '@grafana/ui';
export interface SpanBarOptions {
type?: string;
tag?: string;
}
export interface SpanBarOptionsData extends DataSourceJsonData {
spanBar?: SpanBarOptions;
}
export const NONE = 'None';
export const DURATION = 'Duration';
export const TAG = 'Tag';
interface Props extends DataSourcePluginOptionsEditorProps<SpanBarOptionsData> {}
export default function SpanBarSettings({ options, onOptionsChange }: Props) {
const styles = useStyles(getStyles);
const selectOptions = [NONE, DURATION, TAG].map(toOption);
return (
<div className={css({ width: '100%' })}>
<h3 className="page-heading">Span bar label</h3>
<div className={styles.infoText}>Span bar label lets you add additional info to the span bar row.</div>
<InlineFieldRow className={styles.row}>
<InlineField label="Label" labelWidth={26} grow>
<Select
inputId="label"
options={selectOptions}
value={options.jsonData.spanBar?.type || ''}
onChange={(v) => {
updateDatasourcePluginJsonDataOption({ onOptionsChange, options }, 'spanBar', {
...options.jsonData.spanBar,
type: v?.value ?? '',
});
}}
placeholder="Duration"
isClearable
aria-label={'select-label-name'}
width={25}
/>
</InlineField>
</InlineFieldRow>
{options.jsonData.spanBar?.type === TAG && (
<InlineFieldRow className={styles.row}>
<InlineField label="Tag key" labelWidth={26} tooltip="Tag key which will be used to get the tag value">
<Input
type="text"
placeholder="Enter tag key"
onChange={(v) =>
updateDatasourcePluginJsonDataOption({ onOptionsChange, options }, 'spanBar', {
...options.jsonData.spanBar,
tag: v.currentTarget.value,
})
}
value={options.jsonData.spanBar?.tag || ''}
width={25}
/>
</InlineField>
</InlineFieldRow>
)}
</div>
);
}
const getStyles = (theme: GrafanaTheme) => ({
infoText: css`
label: infoText;
padding-bottom: ${theme.spacing.md};
color: ${theme.colors.textSemiWeak};
`,
row: css`
label: row;
align-items: baseline;
`,
});

View File

@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
export { TraceSpan, TraceResponse, Trace, TraceProcess, TraceKeyValuePair, TraceLink } from './trace'; export { TraceSpan, TraceResponse, Trace, TraceProcess, TraceKeyValuePair, TraceLink } from './trace';
export { SpanLinkFunc, SpanLinkDef } from './links'; export { SpanBarOptions, SpanBarOptionsData } from '../settings/SpanBarSettings';
export { default as TTraceTimeline } from './TTraceTimeline'; export { default as TTraceTimeline } from './TTraceTimeline';
export { default as TNil } from './TNil'; export { default as TNil } from './TNil';
export { SpanLinkFunc, SpanLinkDef } from './links';

View File

@ -18,7 +18,13 @@ import {
} from '@grafana/data'; } from '@grafana/data';
import { getTemplateSrv } from '@grafana/runtime'; import { getTemplateSrv } from '@grafana/runtime';
import { useStyles2 } from '@grafana/ui'; import { useStyles2 } from '@grafana/ui';
import { Trace, TracePageHeader, TraceTimelineViewer, TTraceTimeline } from '@jaegertracing/jaeger-ui-components'; import {
SpanBarOptionsData,
Trace,
TracePageHeader,
TraceTimelineViewer,
TTraceTimeline,
} from '@jaegertracing/jaeger-ui-components';
import { TraceToLogsData } from 'app/core/components/TraceToLogs/TraceToLogsSettings'; import { TraceToLogsData } from 'app/core/components/TraceToLogs/TraceToLogsSettings';
import { TraceToMetricsData } from 'app/core/components/TraceToMetrics/TraceToMetricsSettings'; import { TraceToMetricsData } from 'app/core/components/TraceToMetrics/TraceToMetricsSettings';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
@ -118,6 +124,7 @@ export function TraceView(props: Props) {
const instanceSettings = getDatasourceSrv().getInstanceSettings(datasource?.name); const instanceSettings = getDatasourceSrv().getInstanceSettings(datasource?.name);
const traceToLogsOptions = (instanceSettings?.jsonData as TraceToLogsData)?.tracesToLogs; const traceToLogsOptions = (instanceSettings?.jsonData as TraceToLogsData)?.tracesToLogs;
const traceToMetricsOptions = (instanceSettings?.jsonData as TraceToMetricsData)?.tracesToMetrics; const traceToMetricsOptions = (instanceSettings?.jsonData as TraceToMetricsData)?.tracesToMetrics;
const spanBarOptions: SpanBarOptionsData | undefined = instanceSettings?.jsonData;
const createSpanLink = useMemo( const createSpanLink = useMemo(
() => () =>
@ -155,6 +162,7 @@ export function TraceView(props: Props) {
scrollToFirstVisibleSpan={noop} scrollToFirstVisibleSpan={noop}
findMatchesIDs={spanFindMatches} findMatchesIDs={spanFindMatches}
trace={traceProp} trace={traceProp}
spanBarOptions={spanBarOptions?.spanBar}
traceTimeline={traceTimeline} traceTimeline={traceTimeline}
updateNextViewRangeTime={updateNextViewRangeTime} updateNextViewRangeTime={updateNextViewRangeTime}
updateViewRangeTime={updateViewRangeTime} updateViewRangeTime={updateViewRangeTime}

View File

@ -3,6 +3,7 @@ import React from 'react';
import { DataSourcePluginOptionsEditorProps } from '@grafana/data'; import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
import { config } from '@grafana/runtime'; import { config } from '@grafana/runtime';
import { DataSourceHttpSettings } from '@grafana/ui'; import { DataSourceHttpSettings } from '@grafana/ui';
import { SpanBarSettings } from '@jaegertracing/jaeger-ui-components';
import { NodeGraphSettings } from 'app/core/components/NodeGraphSettings'; import { NodeGraphSettings } from 'app/core/components/NodeGraphSettings';
import { TraceToLogsSettings } from 'app/core/components/TraceToLogs/TraceToLogsSettings'; import { TraceToLogsSettings } from 'app/core/components/TraceToLogs/TraceToLogsSettings';
import { TraceToMetricsSettings } from 'app/core/components/TraceToMetrics/TraceToMetricsSettings'; import { TraceToMetricsSettings } from 'app/core/components/TraceToMetrics/TraceToMetricsSettings';
@ -32,6 +33,10 @@ export const ConfigEditor: React.FC<Props> = ({ options, onOptionsChange }) => {
<div className="gf-form-group"> <div className="gf-form-group">
<NodeGraphSettings options={options} onOptionsChange={onOptionsChange} /> <NodeGraphSettings options={options} onOptionsChange={onOptionsChange} />
</div> </div>
<div className="gf-form-group">
<SpanBarSettings options={options} onOptionsChange={onOptionsChange} />
</div>
</> </>
); );
}; };

View File

@ -15,6 +15,7 @@ import {
ScopedVars, ScopedVars,
} from '@grafana/data'; } from '@grafana/data';
import { BackendSrvRequest, getBackendSrv, getTemplateSrv, TemplateSrv } from '@grafana/runtime'; import { BackendSrvRequest, getBackendSrv, getTemplateSrv, TemplateSrv } from '@grafana/runtime';
import { SpanBarOptions } from '@jaegertracing/jaeger-ui-components';
import { NodeGraphOptions } from 'app/core/components/NodeGraphSettings'; import { NodeGraphOptions } from 'app/core/components/NodeGraphSettings';
import { serializeParams } from 'app/core/utils/fetch'; import { serializeParams } from 'app/core/utils/fetch';
import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv';
@ -32,6 +33,7 @@ export interface JaegerJsonData extends DataSourceJsonData {
export class JaegerDatasource extends DataSourceApi<JaegerQuery, JaegerJsonData> { export class JaegerDatasource extends DataSourceApi<JaegerQuery, JaegerJsonData> {
uploadedJson: string | ArrayBuffer | null = null; uploadedJson: string | ArrayBuffer | null = null;
nodeGraph?: NodeGraphOptions; nodeGraph?: NodeGraphOptions;
spanBar?: SpanBarOptions;
constructor( constructor(
private instanceSettings: DataSourceInstanceSettings<JaegerJsonData>, private instanceSettings: DataSourceInstanceSettings<JaegerJsonData>,
private readonly timeSrv: TimeSrv = getTimeSrv(), private readonly timeSrv: TimeSrv = getTimeSrv(),

View File

@ -3,6 +3,7 @@ import React from 'react';
import { DataSourcePluginOptionsEditorProps } from '@grafana/data'; import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
import { config } from '@grafana/runtime'; import { config } from '@grafana/runtime';
import { DataSourceHttpSettings } from '@grafana/ui'; import { DataSourceHttpSettings } from '@grafana/ui';
import { SpanBarSettings } from '@jaegertracing/jaeger-ui-components';
import { NodeGraphSettings } from 'app/core/components/NodeGraphSettings'; import { NodeGraphSettings } from 'app/core/components/NodeGraphSettings';
import { TraceToLogsSettings } from 'app/core/components/TraceToLogs/TraceToLogsSettings'; import { TraceToLogsSettings } from 'app/core/components/TraceToLogs/TraceToLogsSettings';
import { TraceToMetricsSettings } from 'app/core/components/TraceToMetrics/TraceToMetricsSettings'; import { TraceToMetricsSettings } from 'app/core/components/TraceToMetrics/TraceToMetricsSettings';
@ -50,6 +51,10 @@ export const ConfigEditor: React.FC<Props> = ({ options, onOptionsChange }) => {
<div className="gf-form-group"> <div className="gf-form-group">
<LokiSearchSettings options={options} onOptionsChange={onOptionsChange} /> <LokiSearchSettings options={options} onOptionsChange={onOptionsChange} />
</div> </div>
<div className="gf-form-group">
<SpanBarSettings options={options} onOptionsChange={onOptionsChange} />
</div>
</> </>
); );
}; };

View File

@ -24,6 +24,7 @@ import {
TemplateSrv, TemplateSrv,
getTemplateSrv, getTemplateSrv,
} from '@grafana/runtime'; } from '@grafana/runtime';
import { SpanBarOptions } from '@jaegertracing/jaeger-ui-components';
import { NodeGraphOptions } from 'app/core/components/NodeGraphSettings'; import { NodeGraphOptions } from 'app/core/components/NodeGraphSettings';
import { TraceToLogsOptions } from 'app/core/components/TraceToLogs/TraceToLogsSettings'; import { TraceToLogsOptions } from 'app/core/components/TraceToLogs/TraceToLogsSettings';
import { serializeParams } from 'app/core/utils/fetch'; import { serializeParams } from 'app/core/utils/fetch';
@ -65,6 +66,9 @@ export interface TempoJsonData extends DataSourceJsonData {
lokiSearch?: { lokiSearch?: {
datasourceUid?: string; datasourceUid?: string;
}; };
spanBar?: {
tag: string;
};
} }
export interface TempoQuery extends DataQuery { export interface TempoQuery extends DataQuery {
@ -105,6 +109,7 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
datasourceUid?: string; datasourceUid?: string;
}; };
uploadedJson?: string | ArrayBuffer | null = null; uploadedJson?: string | ArrayBuffer | null = null;
spanBar?: SpanBarOptions;
constructor( constructor(
private instanceSettings: DataSourceInstanceSettings<TempoJsonData>, private instanceSettings: DataSourceInstanceSettings<TempoJsonData>,

View File

@ -3,6 +3,7 @@ import React from 'react';
import { DataSourcePluginOptionsEditorProps } from '@grafana/data'; import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
import { config } from '@grafana/runtime'; import { config } from '@grafana/runtime';
import { DataSourceHttpSettings } from '@grafana/ui'; import { DataSourceHttpSettings } from '@grafana/ui';
import { SpanBarSettings } from '@jaegertracing/jaeger-ui-components';
import { NodeGraphSettings } from 'app/core/components/NodeGraphSettings'; import { NodeGraphSettings } from 'app/core/components/NodeGraphSettings';
import { TraceToLogsSettings } from 'app/core/components/TraceToLogs/TraceToLogsSettings'; import { TraceToLogsSettings } from 'app/core/components/TraceToLogs/TraceToLogsSettings';
import { TraceToMetricsSettings } from 'app/core/components/TraceToMetrics/TraceToMetricsSettings'; import { TraceToMetricsSettings } from 'app/core/components/TraceToMetrics/TraceToMetricsSettings';
@ -32,6 +33,10 @@ export const ConfigEditor: React.FC<Props> = ({ options, onOptionsChange }) => {
<div className="gf-form-group"> <div className="gf-form-group">
<NodeGraphSettings options={options} onOptionsChange={onOptionsChange} /> <NodeGraphSettings options={options} onOptionsChange={onOptionsChange} />
</div> </div>
<div className="gf-form-group">
<SpanBarSettings options={options} onOptionsChange={onOptionsChange} />
</div>
</> </>
); );
}; };

View File

@ -11,6 +11,7 @@ import {
MutableDataFrame, MutableDataFrame,
} from '@grafana/data'; } from '@grafana/data';
import { BackendSrvRequest, FetchResponse, getBackendSrv } from '@grafana/runtime'; import { BackendSrvRequest, FetchResponse, getBackendSrv } from '@grafana/runtime';
import { SpanBarOptions } from '@jaegertracing/jaeger-ui-components';
import { NodeGraphOptions } from 'app/core/components/NodeGraphSettings'; import { NodeGraphOptions } from 'app/core/components/NodeGraphSettings';
import { serializeParams } from '../../../core/utils/fetch'; import { serializeParams } from '../../../core/utils/fetch';
@ -27,6 +28,7 @@ export interface ZipkinJsonData extends DataSourceJsonData {
export class ZipkinDatasource extends DataSourceApi<ZipkinQuery, ZipkinJsonData> { export class ZipkinDatasource extends DataSourceApi<ZipkinQuery, ZipkinJsonData> {
uploadedJson: string | ArrayBuffer | null = null; uploadedJson: string | ArrayBuffer | null = null;
nodeGraph?: NodeGraphOptions; nodeGraph?: NodeGraphOptions;
spanBar?: SpanBarOptions;
constructor(private instanceSettings: DataSourceInstanceSettings<ZipkinJsonData>) { constructor(private instanceSettings: DataSourceInstanceSettings<ZipkinJsonData>) {
super(instanceSettings); super(instanceSettings);
this.nodeGraph = instanceSettings.jsonData.nodeGraph; this.nodeGraph = instanceSettings.jsonData.nodeGraph;