From b5e61f508c848b37b808d1102e714d59928b02ef Mon Sep 17 00:00:00 2001 From: Anthony Ramine <123095+nox@users.noreply.github.com> Date: Tue, 30 Apr 2024 04:53:12 +0200 Subject: [PATCH] Improve trace page title with data and unique emoji (fixes #2256) (#2275) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Which problem is this PR solving? - This solves #2256. ## Description of the changes - Trace page titles are changed to ` : () — Jaeger UI`. ## How was this change tested? - Page titles are checked in tests. ## Checklist - [x] I have read https://github.com/jaegertracing/jaeger/blob/master/CONTRIBUTING_GUIDELINES.md - [x] I have signed all commits - [ ] I have added unit tests for the new functionality - [x] I have run lint and test steps successfully - for `jaeger`: `make lint test` - for `jaeger-ui`: `yarn lint` and `yarn test` --------- Signed-off-by: Anthony Ramine --- .../TracePageHeader/TracePageHeader.tsx | 8 ++- ...s => find-trace-page-header-parts.test.js} | 20 ++++--- packages/jaeger-ui/src/model/trace-viewer.tsx | 57 ++++++++++++++++++- .../src/model/transform-trace-data.tsx | 6 +- packages/jaeger-ui/src/types/trace.tsx | 2 + 5 files changed, 78 insertions(+), 15 deletions(-) rename packages/jaeger-ui/src/model/{find-trace-name.test.js => find-trace-page-header-parts.test.js} (87%) diff --git a/packages/jaeger-ui/src/components/TracePage/TracePageHeader/TracePageHeader.tsx b/packages/jaeger-ui/src/components/TracePage/TracePageHeader/TracePageHeader.tsx index 998d73097c..ac66389f83 100644 --- a/packages/jaeger-ui/src/components/TracePage/TracePageHeader/TracePageHeader.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TracePageHeader/TracePageHeader.tsx @@ -20,6 +20,7 @@ import _values from 'lodash/values'; import { IoArrowBack, IoFileTrayFull, IoChevronForward } from 'react-icons/io5'; import { Link } from 'react-router-dom'; +import { Helmet } from 'react-helmet'; import AltViewOptions from './AltViewOptions'; import KeyboardShortcutsHelp from './KeyboardShortcutsHelp'; import SpanGraph from './SpanGraph'; @@ -28,7 +29,6 @@ import { TUpdateViewRangeTimeFunction, IViewRange, ViewRangeTimeUpdate, ETraceVi import LabeledList from '../../common/LabeledList'; import NewWindowIcon from '../../common/NewWindowIcon'; import TraceName from '../../common/TraceName'; -import { getTraceName } from '../../../model/trace-viewer'; import { TNil } from '../../../types'; import { Trace } from '../../../types/trace'; import { formatDatetime, formatDuration } from '../../../utils/date'; @@ -149,15 +149,17 @@ export function TracePageHeaderFn(props: TracePageHeaderEmbedProps & { forwarded return { ...rest, value: renderer(trace) }; }); + const traceShortID = trace.traceID.slice(0, 7); + const title = (

- {' '} - {trace.traceID.slice(0, 7)} + {traceShortID}

); return (
+
{toSearch && ( diff --git a/packages/jaeger-ui/src/model/find-trace-name.test.js b/packages/jaeger-ui/src/model/find-trace-page-header-parts.test.js similarity index 87% rename from packages/jaeger-ui/src/model/find-trace-name.test.js rename to packages/jaeger-ui/src/model/find-trace-page-header-parts.test.js index 39c9653a52..c2a5565c63 100644 --- a/packages/jaeger-ui/src/model/find-trace-name.test.js +++ b/packages/jaeger-ui/src/model/find-trace-page-header-parts.test.js @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { _getTraceNameImpl as getTraceName } from './trace-viewer'; +import { _getTracePageHeaderPartsImpl as getTracePageHeaderParts } from './trace-viewer'; -describe('getTraceName', () => { +describe('getTracePageHeaderParts', () => { const firstSpanId = 'firstSpanId'; const secondSpanId = 'secondSpanId'; const thirdSpanId = 'thirdSpanId'; @@ -220,25 +220,29 @@ describe('getTraceName', () => { }, ]; - const fullTraceName = `${serviceName}: ${operationName}`; + const fullTracePageHeaderParts = { serviceName, operationName }; it('returns an empty string if given spans with no root among them', () => { - expect(getTraceName(spansWithNoRoots)).toEqual(''); + expect(getTracePageHeaderParts(spansWithNoRoots)).toEqual(null); }); it('returns an id of root span with the earliest startTime', () => { - expect(getTraceName(spansWithMultipleRootsDifferentByStartTime)).toEqual(fullTraceName); + expect(getTracePageHeaderParts(spansWithMultipleRootsDifferentByStartTime)).toEqual( + fullTracePageHeaderParts + ); }); it('returns an id of root span without any refs', () => { - expect(getTraceName(spansWithMultipleRootsWithOneWithoutRefs)).toEqual(fullTraceName); + expect(getTracePageHeaderParts(spansWithMultipleRootsWithOneWithoutRefs)).toEqual( + fullTracePageHeaderParts + ); }); it('returns an id of root span with remote ref', () => { - expect(getTraceName(spansWithOneRootWithRemoteRef)).toEqual(fullTraceName); + expect(getTracePageHeaderParts(spansWithOneRootWithRemoteRef)).toEqual(fullTracePageHeaderParts); }); it('returns an id of root span with no refs', () => { - expect(getTraceName(spansWithOneRootWithNoRefs)).toEqual(fullTraceName); + expect(getTracePageHeaderParts(spansWithOneRootWithNoRefs)).toEqual(fullTracePageHeaderParts); }); }); diff --git a/packages/jaeger-ui/src/model/trace-viewer.tsx b/packages/jaeger-ui/src/model/trace-viewer.tsx index e551b3b664..13076d3a64 100644 --- a/packages/jaeger-ui/src/model/trace-viewer.tsx +++ b/packages/jaeger-ui/src/model/trace-viewer.tsx @@ -16,7 +16,12 @@ import _memoize from 'lodash/memoize'; import { Span } from '../types/trace'; -export function _getTraceNameImpl(spans: Span[]) { +export type TracePageHeaderParts = { + serviceName: string; + operationName: string; +}; + +export function _getTracePageHeaderPartsImpl(spans: Span[]): TracePageHeaderParts | null { // Use a span with no references to another span in given array // prefering the span with the fewest references // using start time as a tie breaker @@ -44,10 +49,56 @@ export function _getTraceNameImpl(spans: Span[]) { candidateSpan = spans[i]; } } - return candidateSpan ? `${candidateSpan.process.serviceName}: ${candidateSpan.operationName}` : ''; + + if (!candidateSpan) { + return null; + } + + return { + serviceName: candidateSpan.process.serviceName, + operationName: candidateSpan.operationName, + }; } -export const getTraceName = _memoize(_getTraceNameImpl, (spans: Span[]) => { +export const getTracePageHeaderParts = _memoize(_getTracePageHeaderPartsImpl, (spans: Span[]) => { if (!spans.length) return 0; return spans[0].traceID; }); + +export function getTraceName(spans: Span[]): string { + const parts = getTracePageHeaderParts(spans); + + return parts ? `${parts.serviceName}: ${parts.operationName}` : ''; +} + +export function getTracePageTitle(spans: Span[]): string { + const parts = getTracePageHeaderParts(spans); + + return parts ? `${parts.operationName} (${parts.serviceName})` : ''; +} + +export function getTraceEmoji(spans: Span[]): string { + if (!spans.length) return ''; + + // prettier-ignore + const emojiSet = [ + 'ðŸķ', 'ðŸą', '🐭', 'ðŸĶŠ', 'ðŸĻ', 'ðŸŪ', '🐷', 'ðŸļ', 'ðŸĩ', '🐔', 'ðŸĪ', 'ðŸĶ†', + 'ðŸĶ‰', '🐝', 'ðŸĶ‹', 'ðŸĒ', 'ðŸĶ€', 'ðŸģ', '🐊', 'ðŸĶ’', 'ðŸŠķ', 'ðŸĶĐ', '🐉', '🍄', + 'ðŸŒļ', '🌜', 'ðŸ”Ĩ', '🌊ïļ', '💧', '🍏', '🍊', '🍉', '🍒', 'ðŸĨĶ', 'ðŸŒ―', '🍠', + 'ðŸĨ', 'ðŸĨ–', 'ðŸĨš', '🧀', '🍗', '🍟', '🍕', 'ðŸĢ', 'ðŸĪ', '🍙', '🍊', 'âš―ïļ', + '🏀', 'ðŸĨŽ', 'ðŸŽđ', 'ðŸŽē', 'ðŸŽŪ', 'ðŸ§Đ', '🚗', 'ðŸšē', '🚂', '⛹ïļ', '📞', '⏰', + '🔌', '💎', '🊚', 'ðŸ§ē', '🧎', '🎀', '📎', '📘', 'ðŸĐ·', 'ðŸŽĩ', 'ðŸī', 'ðŸšĐ', + ]; + + const traceID = spans[0].traceID; + let index = 0; + + if (traceID) { + for (let i = 0; i < traceID.length; i++) { + const hexChar = traceID.slice(i, i + 1); + index = (index * 16 + parseInt(hexChar, 16)) % emojiSet.length; + } + } + + return emojiSet[index]; +} diff --git a/packages/jaeger-ui/src/model/transform-trace-data.tsx b/packages/jaeger-ui/src/model/transform-trace-data.tsx index 86d73a77ba..f3e2905732 100644 --- a/packages/jaeger-ui/src/model/transform-trace-data.tsx +++ b/packages/jaeger-ui/src/model/transform-trace-data.tsx @@ -16,7 +16,7 @@ import _isEqual from 'lodash/isEqual'; import { getTraceSpanIdsAsTree, TREE_ROOT_ID } from '../selectors/trace'; import { getConfigValue } from '../utils/config/get-config'; -import { getTraceName } from './trace-viewer'; +import { getTraceEmoji, getTraceName, getTracePageTitle } from './trace-viewer'; import { KeyValuePair, Span, SpanData, Trace, TraceData } from '../types/trace'; import TreeNode from '../utils/TreeNode'; @@ -170,12 +170,16 @@ export default function transformTraceData(data: TraceData & { spans: SpanData[] spans.push(span); }); const traceName = getTraceName(spans); + const tracePageTitle = getTracePageTitle(spans); + const traceEmoji = getTraceEmoji(spans); const services = Object.keys(svcCounts).map(name => ({ name, numberOfSpans: svcCounts[name] })); return { services, spans, traceID, traceName, + tracePageTitle, + traceEmoji, // TODO why not store `tree` here for easier access to tree structure? // ... // Can't use spread operator for intersection types diff --git a/packages/jaeger-ui/src/types/trace.tsx b/packages/jaeger-ui/src/types/trace.tsx index 514c191440..b50a4b6182 100644 --- a/packages/jaeger-ui/src/types/trace.tsx +++ b/packages/jaeger-ui/src/types/trace.tsx @@ -81,6 +81,8 @@ export type Trace = TraceData & { spans: Span[]; startTime: number; traceName: string; + tracePageTitle: string; + traceEmoji: string; services: { name: string; numberOfSpans: number }[]; };