-
Notifications
You must be signed in to change notification settings - Fork 51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update custom traces table with filters #2178
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,3 +24,35 @@ export const TRACE_ANALYTICS_DSL_ROUTE = '/api/observability/trace_analytics/que | |
|
||
export const TRACE_CUSTOM_SPAN_INDEX_SETTING = 'observability:traceAnalyticsSpanIndices'; | ||
export const TRACE_CUSTOM_SERVICE_INDEX_SETTING = 'observability:traceAnalyticsServiceIndices'; | ||
|
||
export enum TRACE_TABLE_TITLES { | ||
all_spans = 'Spans', | ||
trace_root_spans = 'Trace root spans', | ||
service_entry_spans = 'Service entry spans', | ||
traces = 'Traces', | ||
} | ||
|
||
export const TRACE_TABLE_OPTIONS = [ | ||
{ | ||
label: TRACE_TABLE_TITLES.all_spans, | ||
key: 'all_spans', | ||
'aria-describedby': 'All spans from all traces', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
label: TRACE_TABLE_TITLES.trace_root_spans, | ||
key: 'trace_root_spans', | ||
'aria-describedby': 'The root spans which represent the starting point of a trace', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
label: TRACE_TABLE_TITLES.service_entry_spans, | ||
key: 'service_entry_spans', | ||
'aria-describedby': 'The spans that mark start of server-side processing (SPAN_KIND_SERVER)', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel SPAN_KIND_SERVER is not needed. If required, bring in the exact description of SPAN_KIND_SERVER from open telemetry. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
label: TRACE_TABLE_TITLES.traces, | ||
key: 'traces', | ||
'aria-describedby': 'Aggregates all spans by traceId to show all traces', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Do we need to How is this different from first option? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This table is the old way of showing just traces using the aggregation query. Kept this option if users still want aggregation and are not concerned about the wait time. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the only table where we shows traces and not spans |
||
}, | ||
]; | ||
|
||
export const TRACE_TABLE_TYPE_KEY = 'TraceAnalyticsTraceTableType'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ideally the constants are in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That makes sense. Will keep this one here for now. Will sort out this and others in common/constants during a mini refactor. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,248 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { | ||
EuiButtonIcon, | ||
EuiCopy, | ||
EuiFlexGroup, | ||
EuiFlexItem, | ||
EuiLink, | ||
EuiTableFieldDataColumnType, | ||
EuiText, | ||
EuiToolTip, | ||
} from '@elastic/eui'; | ||
import { round } from 'lodash'; | ||
import moment from 'moment'; | ||
import React from 'react'; | ||
import { TRACE_ANALYTICS_DATE_FORMAT } from '../../../../../common/constants/trace_analytics'; | ||
import { TraceAnalyticsMode, TraceQueryMode } from '../../../../../common/types/trace_analytics'; | ||
import { nanoToMilliSec } from '../common/helper_functions'; | ||
|
||
export const fetchDynamicColumns = (columnItems: string[]) => { | ||
return columnItems | ||
.filter((col) => col.includes('attributes') || col.includes('instrumentation')) | ||
.map((col) => ({ | ||
className: 'attributes-column', | ||
field: col, | ||
name: ( | ||
<EuiText className="euiTableCellContent"> | ||
<EuiToolTip content={col}> | ||
<p className="euiTableCellContent__text attributes-column-header">{col}</p> | ||
</EuiToolTip> | ||
</EuiText> | ||
), | ||
align: 'right', | ||
sortable: true, | ||
truncateText: true, | ||
render: (item) => | ||
item ? ( | ||
<EuiText> | ||
<EuiToolTip content={item}> | ||
<EuiText size="s" className="attributes-column" title={item}> | ||
{item} | ||
</EuiText> | ||
</EuiToolTip> | ||
</EuiText> | ||
) : ( | ||
'-' | ||
), | ||
})); | ||
}; | ||
|
||
export const getTableColumns = ( | ||
showAttributes: boolean, | ||
columnItems: string[], | ||
mode: TraceAnalyticsMode, | ||
tracesTableMode: TraceQueryMode, | ||
getTraceViewUri?: (traceId: string) => string, | ||
openTraceFlyout?: (traceId: string) => void | ||
): Array<EuiTableFieldDataColumnType<any>> => { | ||
// Helper functions for rendering table fields | ||
const renderIdField = (item: string) => | ||
item ? ( | ||
<EuiText> | ||
<EuiToolTip content={item}> | ||
<EuiText size="s" className="traces-table traces-table-trace-id" title={item}> | ||
{item} | ||
</EuiText> | ||
</EuiToolTip> | ||
</EuiText> | ||
) : ( | ||
'-' | ||
); | ||
|
||
const renderTraceLinkField = (item: string) => ( | ||
<EuiFlexGroup gutterSize="s" alignItems="center"> | ||
<EuiFlexItem grow={false}> | ||
<EuiLink | ||
data-test-subj="trace-link" | ||
{...(getTraceViewUri && { href: getTraceViewUri(item) })} | ||
{...(openTraceFlyout && { onClick: () => openTraceFlyout(item) })} | ||
> | ||
<EuiText size="s" className="traces-table traces-table-trace-id" title={item}> | ||
{item} | ||
</EuiText> | ||
</EuiLink> | ||
</EuiFlexItem> | ||
<EuiFlexItem grow={false}> | ||
<EuiCopy textToCopy={item}> | ||
{(copy) => ( | ||
<EuiButtonIcon aria-label="Copy trace id" iconType="copyClipboard" onClick={copy} /> | ||
)} | ||
</EuiCopy> | ||
</EuiFlexItem> | ||
</EuiFlexGroup> | ||
); | ||
|
||
const renderErrorsField = (item: number) => | ||
item == null ? ( | ||
'-' | ||
) : +item > 0 ? ( | ||
<EuiText color="danger" size="s"> | ||
Yes | ||
</EuiText> | ||
) : ( | ||
'No' | ||
); | ||
|
||
const renderDurationField = (item: number) => | ||
item ? <EuiText size="s">{round(nanoToMilliSec(Math.max(0, item)), 2)}</EuiText> : '-'; | ||
|
||
const renderDateField = (item: number) => | ||
item === 0 || item ? moment(item).format(TRACE_ANALYTICS_DATE_FORMAT) : '-'; | ||
|
||
// Columns for custom_data_prepper mode | ||
if (mode === 'custom_data_prepper' && tracesTableMode !== 'traces') { | ||
return [ | ||
{ | ||
field: 'spanId', | ||
name: 'Span Id', | ||
align: 'left', | ||
sortable: true, | ||
render: renderIdField, | ||
className: 'span-group-column', | ||
}, | ||
{ | ||
field: 'traceId', | ||
name: 'Trace Id', | ||
align: 'left', | ||
sortable: true, | ||
render: renderTraceLinkField, | ||
}, | ||
{ | ||
field: 'parentSpanId', | ||
name: 'Parent Span Id', | ||
align: 'left', | ||
sortable: true, | ||
render: renderIdField, | ||
className: 'span-group-column', | ||
}, | ||
{ | ||
field: 'traceGroup', | ||
name: 'Trace group', | ||
align: 'left', | ||
sortable: true, | ||
truncateText: true, | ||
}, | ||
{ | ||
field: 'durationInNanos', | ||
name: 'Duration (ms)', | ||
align: 'right', | ||
sortable: true, | ||
render: renderDurationField, | ||
}, | ||
{ | ||
field: 'status.code', | ||
name: 'Errors', | ||
align: 'right', | ||
sortable: true, | ||
render: renderErrorsField, | ||
}, | ||
{ | ||
field: 'endTime', | ||
name: 'Last updated', | ||
align: 'right', | ||
sortable: true, | ||
render: renderDateField, | ||
className: 'span-group-column', | ||
}, | ||
...(showAttributes ? fetchDynamicColumns(columnItems) : []), | ||
] as Array<EuiTableFieldDataColumnType<any>>; | ||
} | ||
|
||
// Columns for non-jaeger traces mode | ||
if (mode !== 'jaeger' && tracesTableMode === 'traces') { | ||
return [ | ||
{ | ||
field: 'trace_id', | ||
name: 'Trace ID', | ||
align: 'left', | ||
sortable: true, | ||
render: renderTraceLinkField, | ||
}, | ||
{ | ||
field: 'trace_group', | ||
name: 'Trace group', | ||
align: 'left', | ||
sortable: true, | ||
truncateText: true, | ||
}, | ||
{ | ||
field: 'latency', | ||
name: 'Duration (ms)', | ||
align: 'right', | ||
sortable: true, | ||
truncateText: true, | ||
}, | ||
{ | ||
field: 'percentile_in_trace_group', | ||
name: 'Percentile in trace group', | ||
align: 'right', | ||
sortable: true, | ||
render: (item) => (item ? `${round(item, 2)}th` : '-'), | ||
}, | ||
{ | ||
field: 'error_count', | ||
name: 'Errors', | ||
align: 'right', | ||
sortable: true, | ||
render: renderErrorsField, | ||
}, | ||
{ | ||
field: 'last_updated', | ||
name: 'Last updated', | ||
align: 'left', | ||
sortable: true, | ||
className: 'span-group-column', | ||
}, | ||
] as Array<EuiTableFieldDataColumnType<any>>; | ||
} | ||
|
||
// Default columns for other modes | ||
return [ | ||
{ | ||
field: 'trace_id', | ||
name: 'Trace ID', | ||
align: 'left', | ||
sortable: true, | ||
render: renderTraceLinkField, | ||
}, | ||
{ field: 'latency', name: 'Latency (ms)', align: 'right', sortable: true }, | ||
{ | ||
field: 'error_count', | ||
name: 'Errors', | ||
align: 'right', | ||
sortable: true, | ||
render: renderErrorsField, | ||
}, | ||
{ | ||
field: 'last_updated', | ||
name: 'Last updated', | ||
align: 'left', | ||
sortable: true, | ||
className: 'span-group-column', | ||
}, | ||
] as Array<EuiTableFieldDataColumnType<any>>; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Users might ask for caching selected option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, for now I've added the selection in the session storage similar to how we store filters. So the table type selection is persisted in the session lifecycle.