mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 19:28:59 +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 Spinner from 'components/Spinner';
|
||||
import React from 'react';
|
||||
@ -7,6 +8,7 @@ import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import CommonCheckBox from './CommonCheckBox';
|
||||
import Duration from './Duration';
|
||||
import TraceID from './SearchTraceID';
|
||||
|
||||
function PanelBody(props: PanelBodyProps): JSX.Element {
|
||||
const { type } = props;
|
||||
@ -22,12 +24,17 @@ function PanelBody(props: PanelBodyProps): JSX.Element {
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Card bordered={false}>
|
||||
{type === 'duration' ? <Duration /> : <CommonCheckBox name={type} />}
|
||||
</Card>
|
||||
);
|
||||
const renderBody = (type: TraceFilterEnum): JSX.Element => {
|
||||
switch (type) {
|
||||
case 'traceID':
|
||||
return <TraceID />;
|
||||
case 'duration':
|
||||
return <Duration />;
|
||||
default:
|
||||
return <CommonCheckBox name={type} />;
|
||||
}
|
||||
};
|
||||
return <Card bordered={false}>{renderBody(type)}</Card>;
|
||||
}
|
||||
|
||||
interface PanelBodyProps {
|
||||
|
@ -16,6 +16,7 @@ export const AllTraceFilterEnum: TraceFilterEnum[] = [
|
||||
'httpMethod',
|
||||
'httpRoute',
|
||||
'httpUrl',
|
||||
'traceID',
|
||||
];
|
||||
|
||||
function Filters(): JSX.Element {
|
||||
|
@ -68,6 +68,7 @@ const initialValue: TraceReducer = {
|
||||
['responseStatusCode', INITIAL_FILTER_VALUE],
|
||||
['serviceName', INITIAL_FILTER_VALUE],
|
||||
['status', INITIAL_FILTER_VALUE],
|
||||
['traceID', INITIAL_FILTER_VALUE],
|
||||
]),
|
||||
};
|
||||
|
||||
|
@ -71,7 +71,8 @@ export type TraceFilterEnum =
|
||||
| 'serviceName'
|
||||
| 'status'
|
||||
| 'responseStatusCode'
|
||||
| 'rpcMethod';
|
||||
| 'rpcMethod'
|
||||
| 'traceID';
|
||||
|
||||
export const AllPanelHeading: {
|
||||
key: TraceFilterEnum;
|
||||
@ -125,4 +126,8 @@ export const AllPanelHeading: {
|
||||
key: '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))}
|
||||
if len(queryParams.TraceID) > 0 {
|
||||
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.TraceID, constants.TraceID, &query, args)
|
||||
}
|
||||
if len(queryParams.ServiceName) > 0 {
|
||||
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 {
|
||||
switch e {
|
||||
case constants.TraceID:
|
||||
continue
|
||||
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 += query
|
||||
@ -1271,6 +1276,9 @@ func (r *ClickHouseReader) GetFilteredSpans(ctx context.Context, queryParams *mo
|
||||
|
||||
var query string
|
||||
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 {
|
||||
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
|
||||
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 {
|
||||
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
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
if len(queryParams.TraceID) > 0 {
|
||||
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.TraceID, constants.TraceID, &query, args)
|
||||
}
|
||||
if len(queryParams.ServiceName) > 0 {
|
||||
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")
|
||||
|
||||
const (
|
||||
TraceID = "traceID"
|
||||
ServiceName = "serviceName"
|
||||
HttpRoute = "httpRoute"
|
||||
HttpCode = "httpCode"
|
||||
|
@ -182,6 +182,7 @@ type TagQuery struct {
|
||||
}
|
||||
|
||||
type GetFilteredSpansParams struct {
|
||||
TraceID []string `json:"traceID"`
|
||||
ServiceName []string `json:"serviceName"`
|
||||
Operation []string `json:"operation"`
|
||||
Kind string `json:"kind"`
|
||||
@ -209,6 +210,7 @@ type GetFilteredSpansParams struct {
|
||||
}
|
||||
|
||||
type GetFilteredSpanAggregatesParams struct {
|
||||
TraceID []string `json:"traceID"`
|
||||
ServiceName []string `json:"serviceName"`
|
||||
Operation []string `json:"operation"`
|
||||
Kind string `json:"kind"`
|
||||
@ -237,6 +239,7 @@ type GetFilteredSpanAggregatesParams struct {
|
||||
}
|
||||
|
||||
type SpanFilterParams struct {
|
||||
TraceID []string `json:"traceID"`
|
||||
Status []string `json:"status"`
|
||||
ServiceName []string `json:"serviceName"`
|
||||
HttpRoute []string `json:"httpRoute"`
|
||||
@ -259,6 +262,7 @@ type SpanFilterParams struct {
|
||||
}
|
||||
|
||||
type TagFilterParams struct {
|
||||
TraceID []string `json:"traceID"`
|
||||
Status []string `json:"status"`
|
||||
ServiceName []string `json:"serviceName"`
|
||||
HttpRoute []string `json:"httpRoute"`
|
||||
|
Loading…
x
Reference in New Issue
Block a user