Skip to content

Commit 8aa5d47

Browse files
adrapereiraaocenas
andauthored
Tempo: Fix streaming query restart after Grafana server reboot (grafana#77614)
* Fix streaming query restart after Grafana server reboot * TraceQL Search filter name improvements * Add flag to enable streaming in tempo docker block --------- Co-authored-by: Andrej Ocenas <[email protected]>
1 parent 25779bb commit 8aa5d47

File tree

5 files changed

+68
-55
lines changed

5 files changed

+68
-55
lines changed

devenv/docker/blocks/tempo/tempo.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,5 @@ storage:
5252

5353
overrides:
5454
metrics_generator_processors: [local-blocks, service-graphs, span-metrics]
55+
56+
stream_over_http_enabled: true

public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -342,9 +342,9 @@ export const SpanFilters = memo((props: SpanFilterProps) => {
342342
</InlineFieldRow>
343343
<InlineFieldRow>
344344
<InlineField
345-
label="Span Duration"
345+
label="Duration"
346346
labelWidth={16}
347-
tooltip="Filter by span duration. Accepted units are ns, us, ms, s, m, h"
347+
tooltip="Filter by duration. Accepted units are ns, us, ms, s, m, h"
348348
>
349349
<HorizontalGroup spacing="xs" align="flex-start">
350350
<Select

public/app/plugins/datasource/tempo/SearchTraceQLEditor/TraceQLSearch.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ const TraceQLSearch = ({ datasource, query, onChange }: Props) => {
150150
/>
151151
</InlineSearchField>
152152
<InlineSearchField
153-
label={'Duration'}
153+
label={'Span Duration'}
154154
tooltip="The span duration, i.e. end - start time of the span. Accepted units are ns, ms, s, m, h"
155155
>
156156
<HorizontalGroup spacing={'sm'}>

public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.ts

+4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ export const filterTitle = (f: TraceqlFilter) => {
4141
if (f.tag === 'name') {
4242
return 'Span Name';
4343
}
44+
// Special case for the resource service name
45+
if (f.tag === 'service.name' && f.scope === TraceqlSearchScope.Resource) {
46+
return 'Service Name';
47+
}
4448
return startCase(filterScopedTag(f));
4549
};
4650

public/app/plugins/datasource/tempo/streaming.ts

+59-52
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { capitalize } from 'lodash';
2-
import { map, Observable, defer, mergeMap } from 'rxjs';
2+
import { map, Observable, takeWhile } from 'rxjs';
33
import { v4 as uuidv4 } from 'uuid';
44

55
import {
@@ -20,7 +20,7 @@ import { SearchStreamingState } from './dataquery.gen';
2020
import { DEFAULT_SPSS, TempoDatasource } from './datasource';
2121
import { formatTraceQLResponse } from './resultTransformer';
2222
import { SearchMetrics, TempoJsonData, TempoQuery } from './types';
23-
export async function getLiveStreamKey(): Promise<string> {
23+
function getLiveStreamKey(): string {
2424
return uuidv4();
2525
}
2626

@@ -34,59 +34,66 @@ export function doTempoChannelStream(
3434

3535
let frames: DataFrame[] | undefined = undefined;
3636
let state: LoadingState = LoadingState.NotStarted;
37+
const requestTime = performance.now();
3738

38-
return defer(() => getLiveStreamKey()).pipe(
39-
mergeMap((key) => {
40-
const requestTime = performance.now();
41-
return getGrafanaLiveSrv()
42-
.getStream<MutableDataFrame>({
43-
scope: LiveChannelScope.DataSource,
44-
namespace: ds.uid,
45-
path: `search/${key}`,
46-
data: {
47-
...query,
48-
SpansPerSpanSet: query.spss ?? DEFAULT_SPSS,
49-
timeRange: {
50-
from: range.from.toISOString(),
51-
to: range.to.toISOString(),
52-
},
53-
},
54-
})
55-
.pipe(
56-
map((evt) => {
57-
if ('message' in evt && evt?.message) {
58-
const currentTime = performance.now();
59-
const elapsedTime = currentTime - requestTime;
60-
// Schema should be [traces, metrics, state, error]
61-
const traces = evt.message.data.values[0][0];
62-
const metrics = evt.message.data.values[1][0];
63-
const frameState: SearchStreamingState = evt.message.data.values[2][0];
64-
const error = evt.message.data.values[3][0];
39+
return getGrafanaLiveSrv()
40+
.getStream<MutableDataFrame>({
41+
scope: LiveChannelScope.DataSource,
42+
namespace: ds.uid,
43+
path: `search/${getLiveStreamKey()}`,
44+
data: {
45+
...query,
46+
SpansPerSpanSet: query.spss ?? DEFAULT_SPSS,
47+
timeRange: {
48+
from: range.from.toISOString(),
49+
to: range.to.toISOString(),
50+
},
51+
},
52+
})
53+
.pipe(
54+
takeWhile((evt) => {
55+
if ('message' in evt && evt?.message) {
56+
const frameState: SearchStreamingState = evt.message.data.values[2][0];
57+
if (frameState === SearchStreamingState.Done || frameState === SearchStreamingState.Error) {
58+
return false;
59+
}
60+
}
61+
return true;
62+
}, true)
63+
)
64+
.pipe(
65+
map((evt) => {
66+
if ('message' in evt && evt?.message) {
67+
const currentTime = performance.now();
68+
const elapsedTime = currentTime - requestTime;
69+
// Schema should be [traces, metrics, state, error]
70+
const traces = evt.message.data.values[0][0];
71+
const metrics = evt.message.data.values[1][0];
72+
const frameState: SearchStreamingState = evt.message.data.values[2][0];
73+
const error = evt.message.data.values[3][0];
6574

66-
switch (frameState) {
67-
case SearchStreamingState.Done:
68-
state = LoadingState.Done;
69-
break;
70-
case SearchStreamingState.Streaming:
71-
state = LoadingState.Streaming;
72-
break;
73-
case SearchStreamingState.Error:
74-
throw new Error(error);
75-
}
75+
switch (frameState) {
76+
case SearchStreamingState.Done:
77+
state = LoadingState.Done;
78+
break;
79+
case SearchStreamingState.Streaming:
80+
state = LoadingState.Streaming;
81+
break;
82+
case SearchStreamingState.Error:
83+
throw new Error(error);
84+
}
7685

77-
frames = [
78-
metricsDataFrame(metrics, frameState, elapsedTime),
79-
...formatTraceQLResponse(traces, instanceSettings, query.tableType),
80-
];
81-
}
82-
return {
83-
data: frames || [],
84-
state,
85-
};
86-
})
87-
);
88-
})
89-
);
86+
frames = [
87+
metricsDataFrame(metrics, frameState, elapsedTime),
88+
...formatTraceQLResponse(traces, instanceSettings, query.tableType),
89+
];
90+
}
91+
return {
92+
data: frames || [],
93+
state,
94+
};
95+
})
96+
);
9097
}
9198

9299
function metricsDataFrame(metrics: SearchMetrics, state: SearchStreamingState, elapsedTime: number) {

0 commit comments

Comments
 (0)