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 = ({