From b3838d372e114236ac07a13a785e55f214864e49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Bedi?= Date: Thu, 10 Dec 2020 19:42:43 +0100 Subject: [PATCH] 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> --- docs/sources/datasources/jaeger.md | 33 ++-- docs/sources/datasources/tempo.md | 30 ++- docs/sources/datasources/testdata.md | 2 +- docs/sources/datasources/zipkin.md | 33 ++-- docs/sources/explore/index.md | 17 +- packages/grafana-data/src/types/config.ts | 2 - packages/grafana-runtime/src/config.ts | 1 - .../core/components/TraceToLogsSettings.tsx | 72 +++++++ .../explore/TraceView/TraceView.test.tsx | 13 ++ .../features/explore/TraceView/TraceView.tsx | 12 +- .../explore/TraceView/createSpanLink.test.ts | 175 +++++++++++------- .../explore/TraceView/createSpanLink.tsx | 40 ++-- .../datasource/jaeger/ConfigEditor.tsx | 7 +- .../plugins/datasource/tempo/ConfigEditor.tsx | 19 +- .../datasource/zipkin/ConfigEditor.tsx | 19 +- 15 files changed, 340 insertions(+), 135 deletions(-) create mode 100644 public/app/core/components/TraceToLogsSettings.tsx diff --git a/docs/sources/datasources/jaeger.md b/docs/sources/datasources/jaeger.md index a3ebe839e9e..546d383a7c3 100644 --- a/docs/sources/datasources/jaeger.md +++ b/docs/sources/datasources/jaeger.md @@ -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. diff --git a/docs/sources/datasources/tempo.md b/docs/sources/datasources/tempo.md index 49ba9bfea5a..2e8d2a385fe 100644 --- a/docs/sources/datasources/tempo.md +++ b/docs/sources/datasources/tempo.md @@ -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 diff --git a/docs/sources/datasources/testdata.md b/docs/sources/datasources/testdata.md index fed671a3a2d..ecd47dff50f 100644 --- a/docs/sources/datasources/testdata.md +++ b/docs/sources/datasources/testdata.md @@ -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 diff --git a/docs/sources/datasources/zipkin.md b/docs/sources/datasources/zipkin.md index f6daa62a98c..e27de588560 100644 --- a/docs/sources/datasources/zipkin.md +++ b/docs/sources/datasources/zipkin.md @@ -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. diff --git a/docs/sources/explore/index.md b/docs/sources/explore/index.md index c15d2b6d296..8222016d5c7 100644 --- a/docs/sources/explore/index.md +++ b/docs/sources/explore/index.md @@ -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" >}} diff --git a/packages/grafana-data/src/types/config.ts b/packages/grafana-data/src/types/config.ts index 0f5e796eaf4..f48138a473d 100644 --- a/packages/grafana-data/src/types/config.ts +++ b/packages/grafana-data/src/types/config.ts @@ -35,8 +35,6 @@ export interface FeatureToggles { live: boolean; expressions: boolean; ngalert: boolean; - // Just for demo at the moment - traceToLogs: boolean; panelLibrary: boolean; /** diff --git a/packages/grafana-runtime/src/config.ts b/packages/grafana-runtime/src/config.ts index 64295fd97e5..e58af9466aa 100644 --- a/packages/grafana-runtime/src/config.ts +++ b/packages/grafana-runtime/src/config.ts @@ -56,7 +56,6 @@ export class GrafanaBootConfig implements GrafanaConfig { expressions: false, meta: false, ngalert: false, - traceToLogs: false, panelLibrary: false, }; licenseInfo: LicenseInfo = {} as LicenseInfo; diff --git a/public/app/core/components/TraceToLogsSettings.tsx b/public/app/core/components/TraceToLogsSettings.tsx new file mode 100644 index 00000000000..bc3b92467cc --- /dev/null +++ b/public/app/core/components/TraceToLogsSettings.tsx @@ -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 {} + +export function TraceToLogsSettings({ options, onOptionsChange }: Props) { + const styles = useStyles(getStyles); + + return ( + <> +

Trace to logs

+ +
+ Trace to logs let's you navigate from a trace span to the selected data source's log. +
+ +
+ Data source + + updateDatasourcePluginJsonDataOption({ onOptionsChange, options }, 'tracesToLogs', { + datasourceUid: ds.uid, + tags: options.jsonData.tracesToLogs?.tags, + }) + } + /> +
+ +
+ + Tags + + + updateDatasourcePluginJsonDataOption({ onOptionsChange, options }, 'tracesToLogs', { + datasourceUid: options.jsonData.tracesToLogs?.datasourceUid, + tags: tags, + }) + } + /> +
+ + ); +} + +const getStyles = (theme: GrafanaTheme) => ({ + infoText: css` + padding-bottom: ${theme.spacing.md}; + color: ${theme.colors.textSemiWeak}; + `, +}); diff --git a/public/app/features/explore/TraceView/TraceView.test.tsx b/public/app/features/explore/TraceView/TraceView.test.tsx index 45eb36af215..90adc42b71d 100644 --- a/public/app/features/explore/TraceView/TraceView.test.tsx +++ b/public/app/features/explore/TraceView/TraceView.test.tsx @@ -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( {}} />); @@ -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); diff --git a/public/app/features/explore/TraceView/TraceView.tsx b/public/app/features/explore/TraceView/TraceView.tsx index b7e7dcd8083..03fab339b45 100644 --- a/public/app/features/explore/TraceView/TraceView.tsx +++ b/public/app/features/explore/TraceView/TraceView.tsx @@ -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) { diff --git a/public/app/features/explore/TraceView/createSpanLink.test.ts b/public/app/features/explore/TraceView/createSpanLink.test.ts index 7ff974bb9b1..2374e252861 100644 --- a/public/app/features/explore/TraceView/createSpanLink.test.ts +++ b/public/app/features/explore/TraceView/createSpanLink.test.ts @@ -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":""}]}` + ); + }); }); }); diff --git a/public/app/features/explore/TraceView/createSpanLink.tsx b/public/app/features/explore/TraceView/createSpanLink.tsx index e71976c7e58..8d5927b1a31 100644 --- a/public/app/features/explore/TraceView/createSpanLink.tsx +++ b/public/app/features/explore/TraceView/createSpanLink.tsx @@ -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 = { - 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; diff --git a/public/app/plugins/datasource/jaeger/ConfigEditor.tsx b/public/app/plugins/datasource/jaeger/ConfigEditor.tsx index c9c092bd661..b0e5f11c7cb 100644 --- a/public/app/plugins/datasource/jaeger/ConfigEditor.tsx +++ b/public/app/plugins/datasource/jaeger/ConfigEditor.tsx @@ -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 = ({ options, onOptionsChange }) => { return ( <> + + ); }; diff --git a/public/app/plugins/datasource/tempo/ConfigEditor.tsx b/public/app/plugins/datasource/tempo/ConfigEditor.tsx index 3f903cd1226..29d02ee1691 100644 --- a/public/app/plugins/datasource/tempo/ConfigEditor.tsx +++ b/public/app/plugins/datasource/tempo/ConfigEditor.tsx @@ -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 = ({ options, onOptionsChange }) => { return ( - + <> + + + + ); }; diff --git a/public/app/plugins/datasource/zipkin/ConfigEditor.tsx b/public/app/plugins/datasource/zipkin/ConfigEditor.tsx index 3d63fc7e6c4..d58403456c4 100644 --- a/public/app/plugins/datasource/zipkin/ConfigEditor.tsx +++ b/public/app/plugins/datasource/zipkin/ConfigEditor.tsx @@ -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 = ({ options, onOptionsChange }) => { return ( - + <> + + + + ); };