From a610226f408495c9023095133b33dec9be60ba16 Mon Sep 17 00:00:00 2001 From: Jeremy Clements <79224539+jeclrsg@users.noreply.github.com> Date: Fri, 25 Oct 2024 12:30:08 -0400 Subject: [PATCH] HPCC-32824 ECL Watch v9 show Open Telemetry ids on WU details adds the Open Telemetry trace and span ids to the WU details page, as well as a button to easily copy these values out of the UI Signed-off-by: Jeremy Clements <79224539+jeclrsg@users.noreply.github.com> --- .../eclwatch/img/opentelemetry-icon-color.svg | 1 + esp/src/src-react/components/Variables.tsx | 9 ++-- .../src-react/components/WorkunitDetails.tsx | 13 +++-- .../src-react/components/WorkunitSummary.tsx | 52 ++++++++++++++++++- esp/src/src/nls/hpcc.ts | 3 ++ 5 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 esp/src/eclwatch/img/opentelemetry-icon-color.svg diff --git a/esp/src/eclwatch/img/opentelemetry-icon-color.svg b/esp/src/eclwatch/img/opentelemetry-icon-color.svg new file mode 100644 index 00000000000..6633300d0ac --- /dev/null +++ b/esp/src/eclwatch/img/opentelemetry-icon-color.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/esp/src/src-react/components/Variables.tsx b/esp/src/src-react/components/Variables.tsx index 6cb7f193df6..b3ca2e58453 100644 --- a/esp/src/src-react/components/Variables.tsx +++ b/esp/src/src-react/components/Variables.tsx @@ -2,24 +2,25 @@ import * as React from "react"; import { CommandBar, ContextualMenuItemType, ICommandBarItemProps } from "@fluentui/react"; import nlsHPCC from "src/nlsHPCC"; import { QuerySortItem } from "src/store/Store"; -import { useWorkunitVariables } from "../hooks/workunit"; +import { Variable } from "../hooks/workunit"; import { HolyGrail } from "../layouts/HolyGrail"; import { FluentGrid, useCopyButtons, useFluentStoreState, FluentColumns } from "./controls/Grid"; import { ShortVerticalDivider } from "./Common"; interface VariablesProps { - wuid: string; + variables: Variable[]; + refreshData: () => void; sort?: QuerySortItem; } const defaultSort = { attribute: "Wuid", descending: true }; export const Variables: React.FunctionComponent = ({ - wuid, + variables, + refreshData, sort = defaultSort }) => { - const [variables, , , refreshData] = useWorkunitVariables(wuid); const [data, setData] = React.useState([]); const { selection, setSelection, diff --git a/esp/src/src-react/components/WorkunitDetails.tsx b/esp/src/src-react/components/WorkunitDetails.tsx index 47d632db043..0451dbd98b5 100644 --- a/esp/src/src-react/components/WorkunitDetails.tsx +++ b/esp/src/src-react/components/WorkunitDetails.tsx @@ -7,7 +7,7 @@ import nlsHPCC from "src/nlsHPCC"; import { hasLogAccess } from "src/ESPLog"; import { wuidToDate, wuidToTime } from "src/Utility"; import { emptyFilter, formatQuery } from "src/ESPWorkunit"; -import { useWorkunit } from "../hooks/workunit"; +import { Variable, useWorkunit, useWorkunitVariables } from "../hooks/workunit"; import { useDeepEffect } from "../hooks/deepHooks"; import { DojoAdapter } from "../layouts/DojoAdapter"; import { parseQuery, pushUrl } from "../util/history"; @@ -52,6 +52,8 @@ export const WorkunitDetails: React.FunctionComponent = ({ }) => { const [workunit] = useWorkunit(wuid, true); + const [variables, , , refreshVariables] = useWorkunitVariables(wuid); + const [otTraceParent, setOtTraceParent] = React.useState(""); const [logCount, setLogCount] = React.useState("*"); const [logsDisabled, setLogsDisabled] = React.useState(true); const [_nextPrev, setNextPrev] = useNextPrev(); @@ -64,6 +66,11 @@ export const WorkunitDetails: React.FunctionComponent = ({ return parseQuery("?" + parentUrlParts[1]); }, [parentUrl]); + React.useEffect(() => { + const traceInfo: Variable = variables.filter(v => v.Name === "ottraceparent")[0]; + setOtTraceParent(traceInfo?.Value ?? ""); + }, [variables]); + const nextWuid = React.useCallback((wuids: WsWorkunits.ECLWorkunit[]) => { let found = false; for (const wu of wuids) { @@ -177,10 +184,10 @@ export const WorkunitDetails: React.FunctionComponent = ({
- + - + {state?.outputs ? diff --git a/esp/src/src-react/components/WorkunitSummary.tsx b/esp/src/src-react/components/WorkunitSummary.tsx index a519dd1a36c..3bf1e0b4337 100644 --- a/esp/src/src-react/components/WorkunitSummary.tsx +++ b/esp/src/src-react/components/WorkunitSummary.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import { CommandBar, ContextualMenuItemType, ICommandBarItemProps, MessageBar, MessageBarType, ScrollablePane, ScrollbarVisibility, Sticky, StickyPositionType } from "@fluentui/react"; +import { CommandBar, ContextualMenuItemType, ICommandBarItemProps, mergeStyles, MessageBar, MessageBarType, registerIcons, ScrollablePane, ScrollbarVisibility, Sticky, StickyPositionType } from "@fluentui/react"; import { scopedLogger } from "@hpcc-js/util"; import nlsHPCC from "src/nlsHPCC"; import { WUStatus } from "src/react/index"; @@ -20,6 +20,35 @@ import { WorkunitPersona } from "./controls/StateIcon"; const logger = scopedLogger("../components/WorkunitDetails.tsx"); +registerIcons({ + icons: { + "open-telemetry": ( + // .../eclwatch/img/opentelemetry-icon-color.svg + + ) + } +}); + +const otIconStyle = mergeStyles({ + width: 16 +}); + +interface OtTraceSchema { + traceId: string; + spanId: string; +} + +const parseOtTraceParent = (parent: string = ""): OtTraceSchema => { + const retVal = { traceId: "", spanId: "" }; + const regex = /00\-([0-9a-z]+)\-([0-9a-z]+)\-01/; + const matches = parent.match(regex); + if (matches) { + retVal.traceId = matches[1] ?? ""; + retVal.spanId = matches[2] ?? ""; + } + return retVal; +}; + interface MessageBarContent { type: MessageBarType; message: string; @@ -27,11 +56,13 @@ interface MessageBarContent { interface WorkunitSummaryProps { wuid: string; + otTraceParent?: string; fullscreen?: boolean; } export const WorkunitSummary: React.FunctionComponent = ({ wuid, + otTraceParent = "", fullscreen = false }) => { @@ -39,6 +70,8 @@ export const WorkunitSummary: React.FunctionComponent = ({ const [exceptions, , refreshSavings] = useWorkunitExceptions(wuid); const [jobname, setJobname] = React.useState(""); const [description, setDescription] = React.useState(""); + const [otTraceId, setOtTraceId] = React.useState(""); + const [otSpanId, setOtSpanId] = React.useState(""); const [_protected, setProtected] = React.useState(false); const [showPublishForm, setShowPublishForm] = React.useState(false); const [showZapForm, setShowZapForm] = React.useState(false); @@ -60,6 +93,12 @@ export const WorkunitSummary: React.FunctionComponent = ({ setProtected(workunit?.Protected); }, [workunit?.Description, workunit?.Jobname, workunit?.Protected]); + React.useEffect(() => { + const otTrace = parseOtTraceParent(otTraceParent); + setOtTraceId(otTrace.traceId); + setOtSpanId(otTrace.spanId); + }, [otTraceParent]); + const canSave = workunit && ( jobname !== workunit.Jobname || description !== workunit.Description || @@ -98,6 +137,13 @@ export const WorkunitSummary: React.FunctionComponent = ({ navigator?.clipboard?.writeText(wuid); } }, + { + key: "copyOtel", text: nlsHPCC.CopyOpenTelemetry, iconProps: { iconName: "open-telemetry", className: otIconStyle }, + disabled: otTraceParent === "", + onClick: () => { + navigator?.clipboard?.writeText(JSON.stringify(parseOtTraceParent(otTraceParent))); + } + }, { key: "divider_1", itemType: ContextualMenuItemType.Divider, onRender: () => }, { key: "save", text: nlsHPCC.Save, iconProps: { iconName: "Save" }, disabled: !canSave, @@ -172,7 +218,7 @@ export const WorkunitSummary: React.FunctionComponent = ({ key: "slaveLogs", text: nlsHPCC.SlaveLogs, disabled: !workunit?.ThorLogList, onClick: () => setShowThorSlaveLogs(true) }, - ], [_protected, canDelete, canDeschedule, canReschedule, canSave, description, jobname, refresh, refreshSavings, setShowDeleteConfirm, showMessageBar, workunit, wuid]); + ], [_protected, canDelete, canDeschedule, canReschedule, canSave, description, jobname, otTraceParent, refresh, refreshSavings, setShowDeleteConfirm, showMessageBar, workunit, wuid]); const rightButtons = React.useMemo((): ICommandBarItemProps[] => [ { @@ -222,6 +268,8 @@ export const WorkunitSummary: React.FunctionComponent = ({