mirror of
https://github.com/grafana/grafana.git
synced 2024-11-22 00:47:38 -06:00
Tracing: Release trace to logs feature (#29443)
* Remove feature flag * Add data source setting for Jaeger * Refactor trace to logs settings * Fix tests * Get ds settings in two steps * Add info to settings * Update docs for trace to logs * Update yarn.lock * Apply suggestions from code review Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> * Update TraceToLogsSettings after merge with master * Add config for tags * Add tags to check for keys * Apply suggestions from code review Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> * Update docs Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>
This commit is contained in:
parent
8a3fdc3055
commit
b3838d372e
@ -11,18 +11,28 @@ weight = 800
|
||||
Grafana ships with built-in support for Jaeger, which provides open source, end-to-end distributed tracing.
|
||||
Just add it as a data source and you are ready to query your traces in [Explore]({{< relref "../explore/index.md" >}}).
|
||||
|
||||
## Adding the data source
|
||||
To access Jaeger settings, click the **Configuration** (gear) icon, then click **Data Sources**, and then click **Jaeger**.
|
||||
## Add data source
|
||||
|
||||
| Name | Description |
|
||||
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `Name` | The data source name. This is how you refer to the data source in panels, queries, and Explore. |
|
||||
| `Default` | Default data source means that it will be pre-selected for new panels. |
|
||||
| `URL` | The URL of the Jaeger instance, e.g., `http://localhost:16686` |
|
||||
| `Access` | Server (default) = URL needs to be accessible from the Grafana backend/server, Browser = URL needs to be accessible from the browser. |
|
||||
| `Basic Auth` | Enable basic authentication to the Jaeger data source. |
|
||||
| `User` | User name for basic authentication. |
|
||||
| `Password` | Password for basic authentication. |
|
||||
To access Jaeger settings, click the **Configuration** (gear) icon, then click **Data Sources** > **Jaeger**.
|
||||
|
||||
| Name | Description |
|
||||
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `Name` | The data source name. This is how you refer to the data source in panels, queries, and Explore. |
|
||||
| `Default` | Data source will be pre-selected for new panels. |
|
||||
| `URL` | The URL of the Jaeger instance, for example, `http://localhost:16686` |
|
||||
| `Access` | Server (default) = URL needs to be accessible from the Grafana backend/server. Browser = URL needs to be accessible from the browser. |
|
||||
| `Basic Auth` | Enable basic authentication to the Jaeger data source. |
|
||||
| `User` | User name for basic authentication. |
|
||||
| `Password` | Password for basic authentication. |
|
||||
|
||||
### Trace to logs
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v74/trace-to-logs-settings.png" class="docs-image--no-shadow" caption="Screenshot of the trace to logs settings" >}}
|
||||
|
||||
This is a configuration for the [trace to logs feature]({{< relref "../explore/index.md#trace-to-logs" >}}). Select target data source (at this moment limited to Loki data sources) and select which tags will be used in the logs query.
|
||||
|
||||
- **Data source -** Target data source.
|
||||
- **Tags -** The tags that will be used in the Loki query. Default is `'cluster', 'hostname', 'namespace', 'pod'`.
|
||||
|
||||
## Query traces
|
||||
|
||||
@ -35,6 +45,7 @@ The Jaeger query editor allows you to query by trace ID directly or selecting a
|
||||
{{< docs-imagebox img="/img/docs/v70/jaeger-query-editor-open.png" class="docs-image--no-shadow" caption="Screenshot of the Jaeger query editor with trace selector expanded" >}}
|
||||
|
||||
Use the trace selector to pick particular trace from all traces logged in the time range you have selected in Explore. The trace selector has three levels of nesting:
|
||||
|
||||
1. The service you are interested in.
|
||||
1. Particular operation is part of the selected service.
|
||||
1. Specific trace in which the selected operation occurred, represented by the root operation name and trace duration.
|
||||
|
@ -3,24 +3,34 @@ title = "Tempo"
|
||||
description = "High volume, minimal dependency trace storage. OSS tracing solution from Grafana Labs."
|
||||
keywords = ["grafana", "tempo", "guide", "tracing"]
|
||||
aliases = ["/docs/grafana/latest/features/datasources/tempo"]
|
||||
weight = 800
|
||||
weight = 1400
|
||||
+++
|
||||
|
||||
# Tempo data source
|
||||
|
||||
Grafana ships with built-in support for Tempo a high volume, minimal dependency trace storage, OSS tracing solution from Grafana Labs. Add it as a data source, and you are ready to query your traces in [Explore]({{< relref "../explore/index.md" >}}).
|
||||
|
||||
## Adding the data source
|
||||
## Add data source
|
||||
|
||||
To access Tempo settings, click the **Configuration** (gear) icon, then click **Data Sources** > **Tempo**.
|
||||
|
||||
| Name | Description |
|
||||
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| _Name_ | The data source name using which you will refer to the data source in panels, queries, and Explore. |
|
||||
| _Default_ | The default data source will be pre-selected for new panels. |
|
||||
| _URL_ | The URL of the Tempo instance, e.g., `http://localhost:16686` |
|
||||
| _Basic Auth_ | Enable basic authentication to the Tempo data source. |
|
||||
| _User_ | User name for basic authentication. |
|
||||
| _Password_ | Password for basic authentication. |
|
||||
| Name | Description |
|
||||
| ------------ | --------------------------------------------------------------------------------------- |
|
||||
| `Name` | The name using which you will refer to the data source in panels, queries, and Explore. |
|
||||
| `Default` | The default data source will be pre-selected for new panels. |
|
||||
| `URL` | The URL of the Tempo instance, e.g., `http://localhost:16686` |
|
||||
| `Basic Auth` | Enable basic authentication to the Tempo data source. |
|
||||
| `User` | User name for basic authentication. |
|
||||
| `Password` | Password for basic authentication. |
|
||||
|
||||
### Trace to logs
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v74/trace-to-logs-settings.png" class="docs-image--no-shadow" caption="Screenshot of the trace to logs settings" >}}
|
||||
|
||||
This is a configuration for the [trace to logs feature]({{< relref "../explore/index.md#trace-to-logs" >}}). Select target data source (at this moment limited to Loki data sources) and select which tags will be used in the logs query.
|
||||
|
||||
- **Data source -** Target data source.
|
||||
- **Tags -** The tags that will be used in the Loki query. Default is `'cluster', 'hostname', 'namespace', 'pod'`.
|
||||
|
||||
## Query traces
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
title = "TestData"
|
||||
keywords = ["grafana", "dashboard", "documentation", "panels", "testdata"]
|
||||
aliases = ["/docs/grafana/latest/features/datasources/testdata"]
|
||||
weight = 1400
|
||||
weight = 1500
|
||||
+++
|
||||
|
||||
# Grafana TestData DB
|
||||
|
@ -3,7 +3,7 @@ title = "Zipkin"
|
||||
description = "Guide for using Zipkin in Grafana"
|
||||
keywords = ["grafana", "zipkin", "guide", "tracing"]
|
||||
aliases = ["/docs/grafana/latest/datasources/zipkin"]
|
||||
weight = 1500
|
||||
weight = 1600
|
||||
+++
|
||||
|
||||
# Zipkin data source
|
||||
@ -12,17 +12,27 @@ Grafana ships with built-in support for Zipkin, an open source, distributed trac
|
||||
Just add it as a data source and you are ready to query your traces in [Explore]({{< relref "../explore" >}}).
|
||||
|
||||
## Adding the data source
|
||||
To access Zipkin settings, click the **Configuration** (gear) icon, then click **Data Sources**, and then click **Zipkin**.
|
||||
|
||||
| Name | Description |
|
||||
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `Name` | The data source name. This is how you refer to the data source in panels, queries, and Explore. |
|
||||
| `Default` | Default data source means that it will be pre-selected for new panels. |
|
||||
| `URL` | The URL of the Zipkin instance, e.g., `http://localhost:9411` |
|
||||
| `Access` | Server (default) = URL needs to be accessible from the Grafana backend/server, Browser = URL needs to be accessible from the browser. |
|
||||
| `Basic Auth` | Enable basic authentication to the Zipkin data source. |
|
||||
| `User` | User name for basic authentication. |
|
||||
| `Password` | Password for basic authentication. |
|
||||
To access Zipkin settings, click the **Configuration** (gear) icon, then click **Data Sources** > **Zipkin**.
|
||||
|
||||
| Name | Description |
|
||||
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `Name` | The data source name. This is how you refer to the data source in panels, queries, and Explore. |
|
||||
| `Default` | Data source will be pre-selected for new panels. |
|
||||
| `URL` | The URL of the Zipkin instance, e.g., `http://localhost:9411`. |
|
||||
| `Access` | Server (default) = URL needs to be accessible from the Grafana backend/server. Browser = URL needs to be accessible from the browser. |
|
||||
| `Basic Auth` | Enable basic authentication to the Zipkin data source. |
|
||||
| `User` | User name for basic authentication. |
|
||||
| `Password` | Password for basic authentication. |
|
||||
|
||||
### Trace to logs
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v74/trace-to-logs-settings.png" class="docs-image--no-shadow" caption="Screenshot of the trace to logs settings" >}}
|
||||
|
||||
This is a configuration for the [trace to logs feature]({{< relref "../explore/index.md#trace-to-logs" >}}). Select target data source (at this moment limited to Loki data sources) and select which tags will be used in the logs query.
|
||||
|
||||
- **Data source -** Target data source.
|
||||
- **Tags -** The tags that will be used in the Loki query. Default is `'cluster', 'hostname', 'namespace', 'pod'`.
|
||||
|
||||
## Query traces
|
||||
|
||||
@ -35,6 +45,7 @@ The Zipkin query editor allows you to query by trace ID directly or selecting a
|
||||
{{< docs-imagebox img="/img/docs/v70/zipkin-query-editor-open.png" class="docs-image--no-shadow" caption="Screenshot of the Zipkin query editor with trace selector expanded" >}}
|
||||
|
||||
Use the trace selector to pick particular trace from all traces logged in the time range you have selected in Explore. The trace selector has three levels of nesting:
|
||||
|
||||
1. The service you are interested in.
|
||||
1. Particular operation is part of the selected service
|
||||
1. Specific trace in which the selected operation occurred, represented by the root operation name and trace duration.
|
||||
|
@ -258,6 +258,8 @@ You can visualize traces from tracing data sources in explore. Data sources curr
|
||||
|
||||
- [Jaeger]({{< relref "../datasources/jaeger.md" >}})
|
||||
- [Zipkin]({{< relref "../datasources/zipkin.md" >}})
|
||||
- [Tempo]({{< relref "../datasources/tempo.md" >}})
|
||||
- [X-Ray](https://grafana.com/grafana/plugins/grafana-x-ray-datasource)
|
||||
|
||||
For information about how to use the query editor see documentation for specific data source.
|
||||
|
||||
@ -300,10 +302,19 @@ Clicking anywhere on the span row shows span details.
|
||||
- Process metadata: Metadata about the process that logged this span.
|
||||
- Logs: List of logs logged by this span and associated key values. In case of Zipkin logs section shows Zipkin annotations.
|
||||
|
||||
## Navigating between Explore and a dashboard
|
||||
##### Trace to logs
|
||||
|
||||
To help accelerate workflows that involve regularly switching from Explore to a dashboard and vice-versa, we've added the ability to return to the origin dashboard
|
||||
after navigating to Explore from the panel's dropdown.
|
||||
> This feature is only available in Grafana 7.4+.
|
||||
|
||||
You can navigate from a span in a trace view directly to logs relevant for that span. This is available for Tempo, Jaeger and Zipkin data source at this moment. See their relevant documentation for instruction how to configure this feature.
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v74/trace-to-logs.png" class="docs-image--no-shadow" caption="Screenshot of the trace view in Explore with new icon next to the spans" >}}
|
||||
|
||||
Click the document icon to open a split view in Explore with the configured data source and query relevant logs for the span.
|
||||
|
||||
## Navigate between Explore and a dashboard
|
||||
|
||||
To help accelerate workflows that involve regularly switching from Explore to a dashboard and vice-versa, we've added the ability to return to the origin dashboard after navigating to Explore from the panel's dropdown.
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v64/panel_dropdown.png" class="docs-image--no-shadow" caption="Screenshot of the panel dropdown" >}}
|
||||
|
||||
|
@ -35,8 +35,6 @@ export interface FeatureToggles {
|
||||
live: boolean;
|
||||
expressions: boolean;
|
||||
ngalert: boolean;
|
||||
// Just for demo at the moment
|
||||
traceToLogs: boolean;
|
||||
panelLibrary: boolean;
|
||||
|
||||
/**
|
||||
|
@ -56,7 +56,6 @@ export class GrafanaBootConfig implements GrafanaConfig {
|
||||
expressions: false,
|
||||
meta: false,
|
||||
ngalert: false,
|
||||
traceToLogs: false,
|
||||
panelLibrary: false,
|
||||
};
|
||||
licenseInfo: LicenseInfo = {} as LicenseInfo;
|
||||
|
72
public/app/core/components/TraceToLogsSettings.tsx
Normal file
72
public/app/core/components/TraceToLogsSettings.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import {
|
||||
DataSourceJsonData,
|
||||
DataSourcePluginOptionsEditorProps,
|
||||
GrafanaTheme,
|
||||
updateDatasourcePluginJsonDataOption,
|
||||
} from '@grafana/data';
|
||||
import { InlineFormLabel, TagsInput, useStyles } from '@grafana/ui';
|
||||
import { css } from 'emotion';
|
||||
import React from 'react';
|
||||
import { DataSourcePicker } from './Select/DataSourcePicker';
|
||||
|
||||
export interface TraceToLogsOptions {
|
||||
datasourceUid?: string;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
export interface TraceToLogsData extends DataSourceJsonData {
|
||||
tracesToLogs?: TraceToLogsOptions;
|
||||
}
|
||||
|
||||
interface Props extends DataSourcePluginOptionsEditorProps<TraceToLogsData> {}
|
||||
|
||||
export function TraceToLogsSettings({ options, onOptionsChange }: Props) {
|
||||
const styles = useStyles(getStyles);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3 className="page-heading">Trace to logs</h3>
|
||||
|
||||
<div className={styles.infoText}>
|
||||
Trace to logs let's you navigate from a trace span to the selected data source's log.
|
||||
</div>
|
||||
|
||||
<div className="gf-form">
|
||||
<InlineFormLabel tooltip="The data source the trace is going to navigate to">Data source</InlineFormLabel>
|
||||
<DataSourcePicker
|
||||
pluginId="loki"
|
||||
current={options.jsonData.tracesToLogs?.datasourceUid}
|
||||
noDefault={true}
|
||||
onChange={ds =>
|
||||
updateDatasourcePluginJsonDataOption({ onOptionsChange, options }, 'tracesToLogs', {
|
||||
datasourceUid: ds.uid,
|
||||
tags: options.jsonData.tracesToLogs?.tags,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="gf-form">
|
||||
<InlineFormLabel tooltip="Tags that will be used in the Loki query. Default tags: 'cluster', 'hostname', 'namespace', 'pod'">
|
||||
Tags
|
||||
</InlineFormLabel>
|
||||
<TagsInput
|
||||
tags={options.jsonData.tracesToLogs?.tags}
|
||||
onChange={tags =>
|
||||
updateDatasourcePluginJsonDataOption({ onOptionsChange, options }, 'tracesToLogs', {
|
||||
datasourceUid: options.jsonData.tracesToLogs?.datasourceUid,
|
||||
tags: tags,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme) => ({
|
||||
infoText: css`
|
||||
padding-bottom: ${theme.spacing.md};
|
||||
color: ${theme.colors.textSemiWeak};
|
||||
`,
|
||||
});
|
@ -4,6 +4,11 @@ import { render } from '@testing-library/react';
|
||||
import { TraceView } from './TraceView';
|
||||
import { TracePageHeader, TraceTimelineViewer } from '@jaegertracing/jaeger-ui-components';
|
||||
import { TraceSpanData, TraceData } from '@grafana/data';
|
||||
import { setDataSourceSrv } from '@grafana/runtime';
|
||||
|
||||
jest.mock('react-redux', () => ({
|
||||
useSelector: jest.fn(() => undefined),
|
||||
}));
|
||||
|
||||
function renderTraceView() {
|
||||
const wrapper = shallow(<TraceView trace={response} splitOpenFn={() => {}} />);
|
||||
@ -15,6 +20,14 @@ function renderTraceView() {
|
||||
}
|
||||
|
||||
describe('TraceView', () => {
|
||||
beforeAll(() => {
|
||||
setDataSourceSrv({
|
||||
getInstanceSettings() {
|
||||
return undefined;
|
||||
},
|
||||
} as any);
|
||||
});
|
||||
|
||||
it('renders TraceTimelineViewer', () => {
|
||||
const { timeline, header } = renderTraceView();
|
||||
expect(timeline).toHaveLength(1);
|
||||
|
@ -18,6 +18,10 @@ import { useHoverIndentGuide } from './useHoverIndentGuide';
|
||||
import { colors, useTheme } from '@grafana/ui';
|
||||
import { TraceViewData, Trace, TraceSpan, TraceKeyValuePair, TraceLink } from '@grafana/data';
|
||||
import { createSpanLinkFactory } from './createSpanLink';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { StoreState } from 'app/types';
|
||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
import { TraceToLogsData } from 'app/core/components/TraceToLogsSettings';
|
||||
|
||||
type Props = {
|
||||
trace?: TraceViewData;
|
||||
@ -54,6 +58,9 @@ export function TraceView(props: Props) {
|
||||
|
||||
const traceProp = useMemo(() => transformTraceData(props.trace), [props.trace]);
|
||||
const { search, setSearch, spanFindMatches } = useSearch(traceProp?.spans);
|
||||
const dataSourceName = useSelector((state: StoreState) => state.explore.left.datasourceInstance?.name);
|
||||
const traceToLogsOptions = (getDatasourceSrv().getInstanceSettings(dataSourceName)?.jsonData as TraceToLogsData)
|
||||
?.tracesToLogs;
|
||||
|
||||
const theme = useTheme();
|
||||
const traceTheme = useMemo(
|
||||
@ -82,7 +89,10 @@ export function TraceView(props: Props) {
|
||||
[childrenHiddenIDs, detailStates, hoverIndentGuideIds, spanNameColumnWidth, traceProp?.traceID]
|
||||
);
|
||||
|
||||
const createSpanLink = useMemo(() => createSpanLinkFactory(props.splitOpenFn), [props.splitOpenFn]);
|
||||
const createSpanLink = useMemo(() => createSpanLinkFactory(props.splitOpenFn, traceToLogsOptions), [
|
||||
props.splitOpenFn,
|
||||
traceToLogsOptions,
|
||||
]);
|
||||
const scrollElement = document.getElementsByClassName('scroll-canvas')[0];
|
||||
|
||||
if (!traceProp) {
|
||||
|
@ -1,82 +1,133 @@
|
||||
import { createSpanLinkFactory } from './createSpanLink';
|
||||
import { config, setDataSourceSrv, setTemplateSrv } from '@grafana/runtime';
|
||||
import { DataSourceInstanceSettings, ScopedVars } from '@grafana/data';
|
||||
import { setDataSourceSrv, setTemplateSrv } from '@grafana/runtime';
|
||||
import { createSpanLinkFactory } from './createSpanLink';
|
||||
|
||||
describe('createSpanLinkFactory', () => {
|
||||
beforeAll(() => {
|
||||
config.featureToggles.traceToLogs = true;
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
config.featureToggles.traceToLogs = false;
|
||||
});
|
||||
|
||||
it('returns undefined if there is no loki data source', () => {
|
||||
setDataSourceSrv({
|
||||
getList() {
|
||||
return [];
|
||||
},
|
||||
} as any);
|
||||
it('returns undefined if there is no data source uid', () => {
|
||||
const splitOpenFn = jest.fn();
|
||||
const createLink = createSpanLinkFactory(splitOpenFn);
|
||||
expect(createLink).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('creates correct link', () => {
|
||||
setDataSourceSrv({
|
||||
getList() {
|
||||
return [
|
||||
{
|
||||
name: 'loki1',
|
||||
uid: 'lokiUid',
|
||||
meta: {
|
||||
id: 'loki',
|
||||
},
|
||||
} as DataSourceInstanceSettings,
|
||||
];
|
||||
},
|
||||
getInstanceSettings(uid: string): DataSourceInstanceSettings | undefined {
|
||||
if (uid === 'lokiUid') {
|
||||
describe('should return link', () => {
|
||||
beforeAll(() => {
|
||||
setDataSourceSrv({
|
||||
getInstanceSettings(uid: string): DataSourceInstanceSettings | undefined {
|
||||
return {
|
||||
uid: 'loki1',
|
||||
name: 'loki1',
|
||||
} as any;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
} as any);
|
||||
},
|
||||
} as any);
|
||||
|
||||
setTemplateSrv({
|
||||
replace(target?: string, scopedVars?: ScopedVars, format?: string | Function): string {
|
||||
return target!;
|
||||
},
|
||||
} as any);
|
||||
setTemplateSrv({
|
||||
replace(target?: string, scopedVars?: ScopedVars, format?: string | Function): string {
|
||||
return target!;
|
||||
},
|
||||
} as any);
|
||||
});
|
||||
|
||||
const splitOpenFn = jest.fn();
|
||||
const createLink = createSpanLinkFactory(splitOpenFn);
|
||||
expect(createLink).toBeDefined();
|
||||
const linkDef = createLink!({
|
||||
startTime: new Date('2020-10-14T01:00:00Z').valueOf() * 1000,
|
||||
duration: 1000 * 1000,
|
||||
process: {
|
||||
it('with default keys when tags not configured', () => {
|
||||
const splitOpenFn = jest.fn();
|
||||
const createLink = createSpanLinkFactory(splitOpenFn, { datasourceUid: 'lokiUid' });
|
||||
expect(createLink).toBeDefined();
|
||||
const linkDef = createLink!({
|
||||
startTime: new Date('2020-10-14T01:00:00Z').valueOf() * 1000,
|
||||
duration: 1000 * 1000,
|
||||
tags: [
|
||||
{
|
||||
key: 'cluster',
|
||||
value: 'cluster1',
|
||||
},
|
||||
{
|
||||
key: 'hostname',
|
||||
value: 'hostname1',
|
||||
},
|
||||
{
|
||||
key: 'label2',
|
||||
value: 'val2',
|
||||
key: 'host',
|
||||
value: 'host',
|
||||
},
|
||||
],
|
||||
} as any,
|
||||
} as any);
|
||||
process: {
|
||||
tags: [
|
||||
{
|
||||
key: 'cluster',
|
||||
value: 'cluster1',
|
||||
},
|
||||
{
|
||||
key: 'hostname',
|
||||
value: 'hostname1',
|
||||
},
|
||||
{
|
||||
key: 'label2',
|
||||
value: 'val2',
|
||||
},
|
||||
],
|
||||
} as any,
|
||||
} as any);
|
||||
|
||||
expect(linkDef.href).toBe(
|
||||
`/explore?left={"range":{"from":"20201014T000000","to":"20201014T010006"},"datasource":"loki1","queries":[{"expr":"{cluster=\\"cluster1\\", hostname=\\"hostname1\\"}","refId":""}]}`
|
||||
);
|
||||
expect(linkDef.href).toBe(
|
||||
`/explore?left={"range":{"from":"20201014T000000","to":"20201014T010006"},"datasource":"loki1","queries":[{"expr":"{cluster=\\"cluster1\\", hostname=\\"hostname1\\"}","refId":""}]}`
|
||||
);
|
||||
});
|
||||
|
||||
it('with tags that passed in and without tags that are not in the span', () => {
|
||||
const splitOpenFn = jest.fn();
|
||||
const createLink = createSpanLinkFactory(splitOpenFn, { datasourceUid: 'lokiUid', tags: ['ip', 'newTag'] });
|
||||
expect(createLink).toBeDefined();
|
||||
const linkDef = createLink!({
|
||||
startTime: new Date('2020-10-14T01:00:00Z').valueOf() * 1000,
|
||||
duration: 1000 * 1000,
|
||||
tags: [
|
||||
{
|
||||
key: 'host',
|
||||
value: 'host',
|
||||
},
|
||||
],
|
||||
process: {
|
||||
tags: [
|
||||
{
|
||||
key: 'hostname',
|
||||
value: 'hostname1',
|
||||
},
|
||||
{
|
||||
key: 'ip',
|
||||
value: '192.168.0.1',
|
||||
},
|
||||
],
|
||||
} as any,
|
||||
} as any);
|
||||
|
||||
expect(linkDef.href).toBe(
|
||||
`/explore?left={"range":{"from":"20201014T000000","to":"20201014T010006"},"datasource":"loki1","queries":[{"expr":"{ip=\\"192.168.0.1\\"}","refId":""}]}`
|
||||
);
|
||||
});
|
||||
|
||||
it('from tags and process tags as well', () => {
|
||||
const splitOpenFn = jest.fn();
|
||||
const createLink = createSpanLinkFactory(splitOpenFn, {
|
||||
datasourceUid: 'lokiUid',
|
||||
tags: ['ip', 'host'],
|
||||
});
|
||||
expect(createLink).toBeDefined();
|
||||
const linkDef = createLink!({
|
||||
startTime: new Date('2020-10-14T01:00:00Z').valueOf() * 1000,
|
||||
duration: 1000 * 1000,
|
||||
tags: [
|
||||
{
|
||||
key: 'host',
|
||||
value: 'host',
|
||||
},
|
||||
],
|
||||
process: {
|
||||
tags: [
|
||||
{
|
||||
key: 'hostname',
|
||||
value: 'hostname1',
|
||||
},
|
||||
{
|
||||
key: 'ip',
|
||||
value: '192.168.0.1',
|
||||
},
|
||||
],
|
||||
} as any,
|
||||
} as any);
|
||||
|
||||
expect(linkDef.href).toBe(
|
||||
`/explore?left={"range":{"from":"20201014T000000","to":"20201014T010006"},"datasource":"loki1","queries":[{"expr":"{ip=\\"192.168.0.1\\", host=\\"host\\"}","refId":""}]}`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,23 +1,28 @@
|
||||
import React from 'react';
|
||||
import { config, getDataSourceSrv, getTemplateSrv } from '@grafana/runtime';
|
||||
import { DataLink, dateTime, Field, mapInternalLinkToExplore, TimeRange, TraceSpan } from '@grafana/data';
|
||||
import { LokiQuery } from '../../../plugins/datasource/loki/types';
|
||||
import { getTemplateSrv } from '@grafana/runtime';
|
||||
import { Icon } from '@grafana/ui';
|
||||
import { TraceToLogsOptions } from 'app/core/components/TraceToLogsSettings';
|
||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
import React from 'react';
|
||||
import { LokiQuery } from '../../../plugins/datasource/loki/types';
|
||||
|
||||
/**
|
||||
* This is a factory for the link creator. It returns the function mainly so it can return undefined in which case
|
||||
* the trace view won't create any links and to capture the datasource and split function making it easier to memoize
|
||||
* with useMemo.
|
||||
*/
|
||||
export function createSpanLinkFactory(splitOpenFn: (options: { datasourceUid: string; query: any }) => void) {
|
||||
if (!config.featureToggles.traceToLogs) {
|
||||
export function createSpanLinkFactory(
|
||||
splitOpenFn: (options: { datasourceUid: string; query: any }) => void,
|
||||
traceToLogsOptions?: TraceToLogsOptions
|
||||
) {
|
||||
// We should return if dataSourceUid is undefined otherwise getInstanceSettings would return testDataSource.
|
||||
if (!traceToLogsOptions?.datasourceUid) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Right now just hardcoded for first loki DS we can find
|
||||
const lokiDs = getDataSourceSrv().getList({ pluginId: 'loki' })[0];
|
||||
const dataSourceSettings = getDatasourceSrv().getInstanceSettings(traceToLogsOptions.datasourceUid);
|
||||
|
||||
if (!lokiDs) {
|
||||
if (!dataSourceSettings) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -28,13 +33,13 @@ export function createSpanLinkFactory(splitOpenFn: (options: { datasourceUid: st
|
||||
// it manually here instead of leaving it for the data source to supply the config.
|
||||
|
||||
const dataLink: DataLink<LokiQuery> = {
|
||||
title: lokiDs.name,
|
||||
title: dataSourceSettings.name,
|
||||
url: '',
|
||||
internal: {
|
||||
datasourceUid: lokiDs.uid,
|
||||
datasourceName: lokiDs.name,
|
||||
datasourceUid: dataSourceSettings.uid,
|
||||
datasourceName: dataSourceSettings.name,
|
||||
query: {
|
||||
expr: getLokiQueryFromSpan(span),
|
||||
expr: getLokiQueryFromSpan(span, traceToLogsOptions.tags),
|
||||
refId: '',
|
||||
},
|
||||
},
|
||||
@ -59,13 +64,14 @@ export function createSpanLinkFactory(splitOpenFn: (options: { datasourceUid: st
|
||||
}
|
||||
|
||||
/**
|
||||
* Right now this is just hardcoded and later will probably be part of some user configuration.
|
||||
* Default keys to use when there are no configured tags.
|
||||
*/
|
||||
const allowedKeys = ['cluster', 'hostname', 'namespace', 'pod'];
|
||||
const defaultKeys = ['cluster', 'hostname', 'namespace', 'pod'];
|
||||
|
||||
function getLokiQueryFromSpan(span: TraceSpan): string {
|
||||
const tags = span.process.tags.reduce((acc, tag) => {
|
||||
if (allowedKeys.includes(tag.key)) {
|
||||
function getLokiQueryFromSpan(span: TraceSpan, keys?: string[]): string {
|
||||
const keysToCheck = keys?.length ? keys : defaultKeys;
|
||||
const tags = [...span.process.tags, ...span.tags].reduce((acc, tag) => {
|
||||
if (keysToCheck.includes(tag.key)) {
|
||||
acc.push(`${tag.key}="${tag.value}"`);
|
||||
}
|
||||
return acc;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
|
||||
import { DataSourceHttpSettings } from '@grafana/ui';
|
||||
import { TraceToLogsSettings } from 'app/core/components/TraceToLogsSettings';
|
||||
import React from 'react';
|
||||
|
||||
export type Props = DataSourcePluginOptionsEditorProps;
|
||||
|
||||
@ -8,11 +9,13 @@ export const ConfigEditor: React.FC<Props> = ({ options, onOptionsChange }) => {
|
||||
return (
|
||||
<>
|
||||
<DataSourceHttpSettings
|
||||
defaultUrl={'http://localhost:16686'}
|
||||
defaultUrl="http://localhost:16686"
|
||||
dataSourceConfig={options}
|
||||
showAccessOptions={true}
|
||||
onChange={onOptionsChange}
|
||||
/>
|
||||
|
||||
<TraceToLogsSettings options={options} onOptionsChange={onOptionsChange} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,16 +1,21 @@
|
||||
import React from 'react';
|
||||
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
|
||||
import { DataSourceHttpSettings } from '@grafana/ui';
|
||||
import { TraceToLogsSettings } from 'app/core/components/TraceToLogsSettings';
|
||||
import React from 'react';
|
||||
|
||||
export type Props = DataSourcePluginOptionsEditorProps;
|
||||
|
||||
export const ConfigEditor: React.FC<Props> = ({ options, onOptionsChange }) => {
|
||||
return (
|
||||
<DataSourceHttpSettings
|
||||
defaultUrl="http://localhost:16686"
|
||||
dataSourceConfig={options}
|
||||
showAccessOptions={false}
|
||||
onChange={onOptionsChange}
|
||||
/>
|
||||
<>
|
||||
<DataSourceHttpSettings
|
||||
defaultUrl="http://localhost:16686"
|
||||
dataSourceConfig={options}
|
||||
showAccessOptions={false}
|
||||
onChange={onOptionsChange}
|
||||
/>
|
||||
|
||||
<TraceToLogsSettings options={options} onOptionsChange={onOptionsChange} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,16 +1,21 @@
|
||||
import React from 'react';
|
||||
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
|
||||
import { DataSourceHttpSettings } from '@grafana/ui';
|
||||
import { TraceToLogsSettings } from 'app/core/components/TraceToLogsSettings';
|
||||
import React from 'react';
|
||||
|
||||
export type Props = DataSourcePluginOptionsEditorProps;
|
||||
|
||||
export const ConfigEditor: React.FC<Props> = ({ options, onOptionsChange }) => {
|
||||
return (
|
||||
<DataSourceHttpSettings
|
||||
defaultUrl={'http://localhost:9411'}
|
||||
dataSourceConfig={options}
|
||||
showAccessOptions={true}
|
||||
onChange={onOptionsChange}
|
||||
/>
|
||||
<>
|
||||
<DataSourceHttpSettings
|
||||
defaultUrl="http://localhost:9411"
|
||||
dataSourceConfig={options}
|
||||
showAccessOptions={true}
|
||||
onChange={onOptionsChange}
|
||||
/>
|
||||
|
||||
<TraceToLogsSettings options={options} onOptionsChange={onOptionsChange} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user