{
}
interface SearchSectionProps {
- linkedDatasourceUid?: string;
+ logsDatasourceUid?: string;
onChange: (value: LokiQuery) => void;
onRunQuery: () => void;
query: TempoQuery;
}
-function SearchSection({ linkedDatasourceUid, onChange, onRunQuery, query }: SearchSectionProps) {
- const dsState = useAsync(() => getDS(linkedDatasourceUid), [linkedDatasourceUid]);
+function SearchSection({ logsDatasourceUid, onChange, onRunQuery, query }: SearchSectionProps) {
+ const dsState = useAsync(() => getDS(logsDatasourceUid), [logsDatasourceUid]);
if (dsState.loading) {
return null;
}
@@ -246,15 +213,15 @@ function SearchSection({ linkedDatasourceUid, onChange, onRunQuery, query }: Sea
);
}
- if (!linkedDatasourceUid) {
- return Please set up a Traces-to-logs datasource in the datasource settings.
;
+ if (!logsDatasourceUid) {
+ return Please set up a Loki search datasource in the datasource settings.
;
}
- if (linkedDatasourceUid && !ds) {
+ if (logsDatasourceUid && !ds) {
return (
- Traces-to-logs datasource is configured but the data source no longer exists. Please configure existing data
- source to use the search.
+ Loki search datasource is configured but the data source no longer exists. Please configure existing data source
+ to use the search.
);
}
diff --git a/public/app/plugins/datasource/tempo/configuration/ConfigEditor.tsx b/public/app/plugins/datasource/tempo/configuration/ConfigEditor.tsx
index d00d8955ae0..ac9276770b7 100644
--- a/public/app/plugins/datasource/tempo/configuration/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/tempo/configuration/ConfigEditor.tsx
@@ -6,6 +6,7 @@ import { ServiceGraphSettings } from './ServiceGraphSettings';
import { config } from '@grafana/runtime';
import { SearchSettings } from './SearchSettings';
import { NodeGraphSettings } from 'app/core/components/NodeGraphSettings';
+import { LokiSearchSettings } from './LokiSearchSettings';
export type Props = DataSourcePluginOptionsEditorProps;
@@ -35,6 +36,9 @@ export const ConfigEditor: React.FC = ({ options, onOptionsChange }) => {
+
+
+
>
);
};
diff --git a/public/app/plugins/datasource/tempo/configuration/LokiSearchSettings.tsx b/public/app/plugins/datasource/tempo/configuration/LokiSearchSettings.tsx
new file mode 100644
index 00000000000..c0374df4d17
--- /dev/null
+++ b/public/app/plugins/datasource/tempo/configuration/LokiSearchSettings.tsx
@@ -0,0 +1,77 @@
+import { css } from '@emotion/css';
+import { DataSourcePluginOptionsEditorProps, GrafanaTheme, updateDatasourcePluginJsonDataOption } from '@grafana/data';
+import { DataSourcePicker } from '@grafana/runtime';
+import { Button, InlineField, InlineFieldRow, useStyles } from '@grafana/ui';
+import React from 'react';
+import { TempoJsonData } from '../datasource';
+
+interface Props extends DataSourcePluginOptionsEditorProps {}
+
+export function LokiSearchSettings({ options, onOptionsChange }: Props) {
+ const styles = useStyles(getStyles);
+
+ // Default to the trace to logs datasource if configured and loki search was enabled
+ // but only if jsonData.lokiSearch hasn't been set
+ const legacyDatasource =
+ options.jsonData.tracesToLogs?.lokiSearch !== false ? options.jsonData.tracesToLogs?.datasourceUid : undefined;
+ if (legacyDatasource && options.jsonData.lokiSearch === undefined) {
+ updateDatasourcePluginJsonDataOption({ onOptionsChange, options }, 'lokiSearch', {
+ datasourceUid: legacyDatasource,
+ });
+ }
+
+ return (
+
+
Loki Search
+
+
+ Select a Loki datasource to search for traces. Derived fields must be configured in the Loki data source.
+
+
+
+
+
+ updateDatasourcePluginJsonDataOption({ onOptionsChange, options }, 'lokiSearch', {
+ datasourceUid: ds.uid,
+ })
+ }
+ />
+
+ {options.jsonData.lokiSearch?.datasourceUid ? (
+
+ ) : null}
+
+
+ );
+}
+
+const getStyles = (theme: GrafanaTheme) => ({
+ infoText: css`
+ label: infoText;
+ padding-bottom: ${theme.spacing.md};
+ color: ${theme.colors.textSemiWeak};
+ `,
+
+ row: css`
+ label: row;
+ align-items: baseline;
+ `,
+});
diff --git a/public/app/plugins/datasource/tempo/datasource.test.ts b/public/app/plugins/datasource/tempo/datasource.test.ts
index 2fe42ea2da0..e5884138fe9 100644
--- a/public/app/plugins/datasource/tempo/datasource.test.ts
+++ b/public/app/plugins/datasource/tempo/datasource.test.ts
@@ -223,6 +223,55 @@ describe('Tempo data source', () => {
'Service Name: frontend, Span Name: /config, Search: root.http.status_code=500, Min Duration: 1ms, Max Duration: 100s, Limit: 10'
);
});
+
+ it('should get loki search datasource', () => {
+ // 1. Get lokiSearch.datasource if present
+ const ds1 = new TempoDatasource({
+ ...defaultSettings,
+ jsonData: {
+ lokiSearch: {
+ datasourceUid: 'loki-1',
+ },
+ },
+ });
+ const lokiDS1 = ds1.getLokiSearchDS();
+ expect(lokiDS1).toBe('loki-1');
+
+ // 2. Get traceToLogs.datasource
+ const ds2 = new TempoDatasource({
+ ...defaultSettings,
+ jsonData: {
+ tracesToLogs: {
+ lokiSearch: true,
+ datasourceUid: 'loki-2',
+ },
+ },
+ });
+ const lokiDS2 = ds2.getLokiSearchDS();
+ expect(lokiDS2).toBe('loki-2');
+
+ // 3. Return undefined if neither is available
+ const ds3 = new TempoDatasource(defaultSettings);
+ const lokiDS3 = ds3.getLokiSearchDS();
+ expect(lokiDS3).toBe(undefined);
+
+ // 4. Return undefined if lokiSearch is undefined, even if traceToLogs is present
+ // since this indicates the user cleared the fallback setting
+ const ds4 = new TempoDatasource({
+ ...defaultSettings,
+ jsonData: {
+ tracesToLogs: {
+ lokiSearch: true,
+ datasourceUid: 'loki-2',
+ },
+ lokiSearch: {
+ datasourceUid: undefined,
+ },
+ },
+ });
+ const lokiDS4 = ds4.getLokiSearchDS();
+ expect(lokiDS4).toBe(undefined);
+ });
});
const backendSrvWithPrometheus = {
diff --git a/public/app/plugins/datasource/tempo/datasource.ts b/public/app/plugins/datasource/tempo/datasource.ts
index 4b77522a3eb..b12bba78b59 100644
--- a/public/app/plugins/datasource/tempo/datasource.ts
+++ b/public/app/plugins/datasource/tempo/datasource.ts
@@ -45,6 +45,9 @@ export interface TempoJsonData extends DataSourceJsonData {
hide?: boolean;
};
nodeGraph?: NodeGraphOptions;
+ lokiSearch?: {
+ datasourceUid?: string;
+ };
}
export interface TempoQuery extends DataQuery {
@@ -81,6 +84,9 @@ export class TempoDatasource extends DataSourceWithBackend) {
@@ -89,6 +95,7 @@ export class TempoDatasource extends DataSourceWithBackend): Observable {
@@ -100,11 +107,13 @@ export class TempoDatasource extends DataSourceWithBackend 0) {
+ if (logsDatasourceUid && targets.search?.length > 0) {
const dsSrv = getDatasourceSrv();
subQueries.push(
- from(dsSrv.get(this.tracesToLogs.datasourceUid)).pipe(
+ from(dsSrv.get(logsDatasourceUid)).pipe(
mergeMap((linkedDatasource: DataSourceApi) => {
// Wrap linked query into a data request based on original request
const linkedRequest: DataQueryRequest = { ...options, targets: targets.search.map((t) => t.linkedQuery!) };
@@ -300,6 +309,15 @@ export class TempoDatasource extends DataSourceWithBackend {
+ const legacyLogsDatasourceUid =
+ this.tracesToLogs?.lokiSearch !== false && this.lokiSearch === undefined
+ ? this.tracesToLogs?.datasourceUid
+ : undefined;
+ return this.lokiSearch?.datasourceUid ?? legacyLogsDatasourceUid;
+ };
}
function queryServiceMapPrometheus(request: DataQueryRequest, datasourceUid: string) {