mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 03:35:52 +08:00
feat: introduce search trace ID component (#1551)
* feat: searchTraceID checkpoint * feat: filter spans using TraceID from trace filter page Co-authored-by: palashgdev <palashgdev@gmail.com> Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
This commit is contained in:
parent
1ec9248975
commit
eaadc3bb95
@ -0,0 +1,127 @@
|
|||||||
|
import { Input, notification } from 'antd';
|
||||||
|
import getFilters from 'api/trace/getFilters';
|
||||||
|
import { AxiosError } from 'axios';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import { Dispatch } from 'redux';
|
||||||
|
import { getFilter, updateURL } from 'store/actions/trace/util';
|
||||||
|
import { AppState } from 'store/reducers';
|
||||||
|
import AppActions from 'types/actions';
|
||||||
|
import { UPDATE_ALL_FILTERS } from 'types/actions/trace';
|
||||||
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
import { TraceReducer } from 'types/reducer/trace';
|
||||||
|
|
||||||
|
const { Search } = Input;
|
||||||
|
|
||||||
|
function TraceID(): JSX.Element {
|
||||||
|
const {
|
||||||
|
selectedFilter,
|
||||||
|
filterToFetchData,
|
||||||
|
spansAggregate,
|
||||||
|
selectedTags,
|
||||||
|
userSelectedFilter,
|
||||||
|
isFilterExclude,
|
||||||
|
} = useSelector<AppState, TraceReducer>((state) => state.traces);
|
||||||
|
const dispatch = useDispatch<Dispatch<AppActions>>();
|
||||||
|
const globalTime = useSelector<AppState, GlobalReducer>(
|
||||||
|
(state) => state.globalTime,
|
||||||
|
);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [userEnteredValue, setUserEnteredValue] = useState<string>('');
|
||||||
|
useEffect(() => {
|
||||||
|
setUserEnteredValue(selectedFilter.get('traceID')?.[0] || '');
|
||||||
|
}, [selectedFilter]);
|
||||||
|
const onSearch = async (value: string): Promise<void> => {
|
||||||
|
try {
|
||||||
|
setIsLoading(true);
|
||||||
|
const preSelectedFilter = new Map(selectedFilter);
|
||||||
|
const preUserSelected = new Map(userSelectedFilter);
|
||||||
|
|
||||||
|
if (value !== '') {
|
||||||
|
preUserSelected.set('traceID', [value]);
|
||||||
|
preSelectedFilter.set('traceID', [value]);
|
||||||
|
} else {
|
||||||
|
preUserSelected.delete('traceID');
|
||||||
|
preSelectedFilter.delete('traceID');
|
||||||
|
}
|
||||||
|
const response = await getFilters({
|
||||||
|
other: Object.fromEntries(preSelectedFilter),
|
||||||
|
end: String(globalTime.maxTime),
|
||||||
|
start: String(globalTime.minTime),
|
||||||
|
getFilters: filterToFetchData,
|
||||||
|
isFilterExclude,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.statusCode === 200) {
|
||||||
|
const preFilter = getFilter(response.payload);
|
||||||
|
preFilter.set('traceID', { traceID: value });
|
||||||
|
preFilter.forEach((value, key) => {
|
||||||
|
const values = Object.keys(value);
|
||||||
|
if (key !== 'duration' && values.length) {
|
||||||
|
preUserSelected.set(key, values);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: UPDATE_ALL_FILTERS,
|
||||||
|
payload: {
|
||||||
|
current: spansAggregate.currentPage,
|
||||||
|
filter: preFilter,
|
||||||
|
filterToFetchData,
|
||||||
|
selectedFilter: preSelectedFilter,
|
||||||
|
selectedTags,
|
||||||
|
userSelected: preUserSelected,
|
||||||
|
isFilterExclude,
|
||||||
|
order: spansAggregate.order,
|
||||||
|
pageSize: spansAggregate.pageSize,
|
||||||
|
orderParam: spansAggregate.orderParam,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
updateURL(
|
||||||
|
preSelectedFilter,
|
||||||
|
filterToFetchData,
|
||||||
|
spansAggregate.currentPage,
|
||||||
|
selectedTags,
|
||||||
|
isFilterExclude,
|
||||||
|
userSelectedFilter,
|
||||||
|
spansAggregate.order,
|
||||||
|
spansAggregate.pageSize,
|
||||||
|
spansAggregate.orderParam,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
notification.error({
|
||||||
|
message: (error as AxiosError).toString() || 'Something went wrong',
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const onChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
|
setUserEnteredValue(e.target.value);
|
||||||
|
};
|
||||||
|
const onBlur = (): void => {
|
||||||
|
if (userEnteredValue !== selectedFilter.get('traceID')?.[0]) {
|
||||||
|
onSearch(userEnteredValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Search
|
||||||
|
placeholder="Filter by Trace ID"
|
||||||
|
onSearch={onSearch}
|
||||||
|
style={{
|
||||||
|
marginBottom: '5rem',
|
||||||
|
padding: '0 3%',
|
||||||
|
}}
|
||||||
|
loading={isLoading}
|
||||||
|
value={userEnteredValue}
|
||||||
|
onChange={onChange}
|
||||||
|
onBlur={onBlur}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TraceID;
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable no-nested-ternary */
|
||||||
import { Card } from 'antd';
|
import { Card } from 'antd';
|
||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@ -7,6 +8,7 @@ import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
|||||||
|
|
||||||
import CommonCheckBox from './CommonCheckBox';
|
import CommonCheckBox from './CommonCheckBox';
|
||||||
import Duration from './Duration';
|
import Duration from './Duration';
|
||||||
|
import TraceID from './SearchTraceID';
|
||||||
|
|
||||||
function PanelBody(props: PanelBodyProps): JSX.Element {
|
function PanelBody(props: PanelBodyProps): JSX.Element {
|
||||||
const { type } = props;
|
const { type } = props;
|
||||||
@ -22,12 +24,17 @@ function PanelBody(props: PanelBodyProps): JSX.Element {
|
|||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const renderBody = (type: TraceFilterEnum): JSX.Element => {
|
||||||
return (
|
switch (type) {
|
||||||
<Card bordered={false}>
|
case 'traceID':
|
||||||
{type === 'duration' ? <Duration /> : <CommonCheckBox name={type} />}
|
return <TraceID />;
|
||||||
</Card>
|
case 'duration':
|
||||||
);
|
return <Duration />;
|
||||||
|
default:
|
||||||
|
return <CommonCheckBox name={type} />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return <Card bordered={false}>{renderBody(type)}</Card>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PanelBodyProps {
|
interface PanelBodyProps {
|
||||||
|
@ -16,6 +16,7 @@ export const AllTraceFilterEnum: TraceFilterEnum[] = [
|
|||||||
'httpMethod',
|
'httpMethod',
|
||||||
'httpRoute',
|
'httpRoute',
|
||||||
'httpUrl',
|
'httpUrl',
|
||||||
|
'traceID',
|
||||||
];
|
];
|
||||||
|
|
||||||
function Filters(): JSX.Element {
|
function Filters(): JSX.Element {
|
||||||
|
@ -68,6 +68,7 @@ const initialValue: TraceReducer = {
|
|||||||
['responseStatusCode', INITIAL_FILTER_VALUE],
|
['responseStatusCode', INITIAL_FILTER_VALUE],
|
||||||
['serviceName', INITIAL_FILTER_VALUE],
|
['serviceName', INITIAL_FILTER_VALUE],
|
||||||
['status', INITIAL_FILTER_VALUE],
|
['status', INITIAL_FILTER_VALUE],
|
||||||
|
['traceID', INITIAL_FILTER_VALUE],
|
||||||
]),
|
]),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -71,7 +71,8 @@ export type TraceFilterEnum =
|
|||||||
| 'serviceName'
|
| 'serviceName'
|
||||||
| 'status'
|
| 'status'
|
||||||
| 'responseStatusCode'
|
| 'responseStatusCode'
|
||||||
| 'rpcMethod';
|
| 'rpcMethod'
|
||||||
|
| 'traceID';
|
||||||
|
|
||||||
export const AllPanelHeading: {
|
export const AllPanelHeading: {
|
||||||
key: TraceFilterEnum;
|
key: TraceFilterEnum;
|
||||||
@ -125,4 +126,8 @@ export const AllPanelHeading: {
|
|||||||
key: 'status',
|
key: 'status',
|
||||||
displayValue: 'Status',
|
displayValue: 'Status',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'traceID',
|
||||||
|
displayValue: 'Trace ID',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
@ -936,6 +936,9 @@ func (r *ClickHouseReader) GetSpanFilters(ctx context.Context, queryParams *mode
|
|||||||
}
|
}
|
||||||
|
|
||||||
args := []interface{}{clickhouse.Named("timestampL", strconv.FormatInt(queryParams.Start.UnixNano(), 10)), clickhouse.Named("timestampU", strconv.FormatInt(queryParams.End.UnixNano(), 10))}
|
args := []interface{}{clickhouse.Named("timestampL", strconv.FormatInt(queryParams.Start.UnixNano(), 10)), clickhouse.Named("timestampU", strconv.FormatInt(queryParams.End.UnixNano(), 10))}
|
||||||
|
if len(queryParams.TraceID) > 0 {
|
||||||
|
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.TraceID, constants.TraceID, &query, args)
|
||||||
|
}
|
||||||
if len(queryParams.ServiceName) > 0 {
|
if len(queryParams.ServiceName) > 0 {
|
||||||
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.ServiceName, constants.ServiceName, &query, args)
|
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.ServiceName, constants.ServiceName, &query, args)
|
||||||
}
|
}
|
||||||
@ -995,6 +998,8 @@ func (r *ClickHouseReader) GetSpanFilters(ctx context.Context, queryParams *mode
|
|||||||
|
|
||||||
for _, e := range queryParams.GetFilters {
|
for _, e := range queryParams.GetFilters {
|
||||||
switch e {
|
switch e {
|
||||||
|
case constants.TraceID:
|
||||||
|
continue
|
||||||
case constants.ServiceName:
|
case constants.ServiceName:
|
||||||
finalQuery := fmt.Sprintf("SELECT serviceName, count() as count FROM %s.%s WHERE timestamp >= @timestampL AND timestamp <= @timestampU", r.traceDB, r.indexTable)
|
finalQuery := fmt.Sprintf("SELECT serviceName, count() as count FROM %s.%s WHERE timestamp >= @timestampL AND timestamp <= @timestampU", r.traceDB, r.indexTable)
|
||||||
finalQuery += query
|
finalQuery += query
|
||||||
@ -1271,6 +1276,9 @@ func (r *ClickHouseReader) GetFilteredSpans(ctx context.Context, queryParams *mo
|
|||||||
|
|
||||||
var query string
|
var query string
|
||||||
args := []interface{}{clickhouse.Named("timestampL", strconv.FormatInt(queryParams.Start.UnixNano(), 10)), clickhouse.Named("timestampU", strconv.FormatInt(queryParams.End.UnixNano(), 10))}
|
args := []interface{}{clickhouse.Named("timestampL", strconv.FormatInt(queryParams.Start.UnixNano(), 10)), clickhouse.Named("timestampU", strconv.FormatInt(queryParams.End.UnixNano(), 10))}
|
||||||
|
if len(queryParams.TraceID) > 0 {
|
||||||
|
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.TraceID, constants.TraceID, &query, args)
|
||||||
|
}
|
||||||
if len(queryParams.ServiceName) > 0 {
|
if len(queryParams.ServiceName) > 0 {
|
||||||
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.ServiceName, constants.ServiceName, &query, args)
|
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.ServiceName, constants.ServiceName, &query, args)
|
||||||
}
|
}
|
||||||
@ -1461,6 +1469,9 @@ func (r *ClickHouseReader) GetTagFilters(ctx context.Context, queryParams *model
|
|||||||
|
|
||||||
var query string
|
var query string
|
||||||
args := []interface{}{clickhouse.Named("timestampL", strconv.FormatInt(queryParams.Start.UnixNano(), 10)), clickhouse.Named("timestampU", strconv.FormatInt(queryParams.End.UnixNano(), 10))}
|
args := []interface{}{clickhouse.Named("timestampL", strconv.FormatInt(queryParams.Start.UnixNano(), 10)), clickhouse.Named("timestampU", strconv.FormatInt(queryParams.End.UnixNano(), 10))}
|
||||||
|
if len(queryParams.TraceID) > 0 {
|
||||||
|
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.TraceID, constants.TraceID, &query, args)
|
||||||
|
}
|
||||||
if len(queryParams.ServiceName) > 0 {
|
if len(queryParams.ServiceName) > 0 {
|
||||||
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.ServiceName, constants.ServiceName, &query, args)
|
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.ServiceName, constants.ServiceName, &query, args)
|
||||||
}
|
}
|
||||||
@ -1557,6 +1568,9 @@ func (r *ClickHouseReader) GetTagValues(ctx context.Context, queryParams *model.
|
|||||||
|
|
||||||
var query string
|
var query string
|
||||||
args := []interface{}{clickhouse.Named("timestampL", strconv.FormatInt(queryParams.Start.UnixNano(), 10)), clickhouse.Named("timestampU", strconv.FormatInt(queryParams.End.UnixNano(), 10))}
|
args := []interface{}{clickhouse.Named("timestampL", strconv.FormatInt(queryParams.Start.UnixNano(), 10)), clickhouse.Named("timestampU", strconv.FormatInt(queryParams.End.UnixNano(), 10))}
|
||||||
|
if len(queryParams.TraceID) > 0 {
|
||||||
|
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.TraceID, constants.TraceID, &query, args)
|
||||||
|
}
|
||||||
if len(queryParams.ServiceName) > 0 {
|
if len(queryParams.ServiceName) > 0 {
|
||||||
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.ServiceName, constants.ServiceName, &query, args)
|
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.ServiceName, constants.ServiceName, &query, args)
|
||||||
}
|
}
|
||||||
@ -1864,6 +1878,9 @@ func (r *ClickHouseReader) GetFilteredSpansAggregates(ctx context.Context, query
|
|||||||
query = fmt.Sprintf("SELECT toStartOfInterval(timestamp, INTERVAL %d minute) as time, %s FROM %s.%s WHERE timestamp >= @timestampL AND timestamp <= @timestampU", queryParams.StepSeconds/60, aggregation_query, r.traceDB, r.indexTable)
|
query = fmt.Sprintf("SELECT toStartOfInterval(timestamp, INTERVAL %d minute) as time, %s FROM %s.%s WHERE timestamp >= @timestampL AND timestamp <= @timestampU", queryParams.StepSeconds/60, aggregation_query, r.traceDB, r.indexTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(queryParams.TraceID) > 0 {
|
||||||
|
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.TraceID, constants.TraceID, &query, args)
|
||||||
|
}
|
||||||
if len(queryParams.ServiceName) > 0 {
|
if len(queryParams.ServiceName) > 0 {
|
||||||
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.ServiceName, constants.ServiceName, &query, args)
|
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.ServiceName, constants.ServiceName, &query, args)
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ var AmChannelApiPath = GetOrDefaultEnv("ALERTMANAGER_API_CHANNEL_PATH", "v1/rout
|
|||||||
var RELATIONAL_DATASOURCE_PATH = GetOrDefaultEnv("SIGNOZ_LOCAL_DB_PATH", "/var/lib/signoz/signoz.db")
|
var RELATIONAL_DATASOURCE_PATH = GetOrDefaultEnv("SIGNOZ_LOCAL_DB_PATH", "/var/lib/signoz/signoz.db")
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
TraceID = "traceID"
|
||||||
ServiceName = "serviceName"
|
ServiceName = "serviceName"
|
||||||
HttpRoute = "httpRoute"
|
HttpRoute = "httpRoute"
|
||||||
HttpCode = "httpCode"
|
HttpCode = "httpCode"
|
||||||
|
@ -182,6 +182,7 @@ type TagQuery struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetFilteredSpansParams struct {
|
type GetFilteredSpansParams struct {
|
||||||
|
TraceID []string `json:"traceID"`
|
||||||
ServiceName []string `json:"serviceName"`
|
ServiceName []string `json:"serviceName"`
|
||||||
Operation []string `json:"operation"`
|
Operation []string `json:"operation"`
|
||||||
Kind string `json:"kind"`
|
Kind string `json:"kind"`
|
||||||
@ -209,6 +210,7 @@ type GetFilteredSpansParams struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetFilteredSpanAggregatesParams struct {
|
type GetFilteredSpanAggregatesParams struct {
|
||||||
|
TraceID []string `json:"traceID"`
|
||||||
ServiceName []string `json:"serviceName"`
|
ServiceName []string `json:"serviceName"`
|
||||||
Operation []string `json:"operation"`
|
Operation []string `json:"operation"`
|
||||||
Kind string `json:"kind"`
|
Kind string `json:"kind"`
|
||||||
@ -237,6 +239,7 @@ type GetFilteredSpanAggregatesParams struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SpanFilterParams struct {
|
type SpanFilterParams struct {
|
||||||
|
TraceID []string `json:"traceID"`
|
||||||
Status []string `json:"status"`
|
Status []string `json:"status"`
|
||||||
ServiceName []string `json:"serviceName"`
|
ServiceName []string `json:"serviceName"`
|
||||||
HttpRoute []string `json:"httpRoute"`
|
HttpRoute []string `json:"httpRoute"`
|
||||||
@ -259,6 +262,7 @@ type SpanFilterParams struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TagFilterParams struct {
|
type TagFilterParams struct {
|
||||||
|
TraceID []string `json:"traceID"`
|
||||||
Status []string `json:"status"`
|
Status []string `json:"status"`
|
||||||
ServiceName []string `json:"serviceName"`
|
ServiceName []string `json:"serviceName"`
|
||||||
HttpRoute []string `json:"httpRoute"`
|
HttpRoute []string `json:"httpRoute"`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user