From ef807072dfdcc39edd3063bc15f691da8c92bda4 Mon Sep 17 00:00:00 2001 From: Mathieu Larose Date: Thu, 9 Jan 2025 15:09:54 -0500 Subject: [PATCH] [dagster-azure]: Frontend --- .../dagster-ui/packages/ui-core/client.json | 4 +- .../ui-core/src/graphql/schema.graphql | 3 + .../packages/ui-core/src/graphql/types.ts | 15 +++ .../ui-core/src/runs/CapturedLogPanel.tsx | 112 ++++++++++++++---- .../packages/ui-core/src/runs/LogsRow.tsx | 3 + .../ui-core/src/runs/RunMetadataProvider.tsx | 9 ++ .../src/runs/types/LogsProvider.types.ts | 13 +- .../ui-core/src/runs/types/LogsRow.types.ts | 3 + ...LogsScrollingTableMessageFragment.types.ts | 3 + .../src/runs/types/RunFragments.types.ts | 3 + .../runs/types/RunMetadataProvider.types.ts | 3 + 11 files changed, 144 insertions(+), 27 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/client.json b/js_modules/dagster-ui/packages/ui-core/client.json index 0f117f0460896..b6de886010f7a 100644 --- a/js_modules/dagster-ui/packages/ui-core/client.json +++ b/js_modules/dagster-ui/packages/ui-core/client.json @@ -118,8 +118,8 @@ "CapturedLogsSubscription": "fa5e55b59e9d8632ae71a8387c54230ba71e6f57849a974225ba039808acfa93", "CapturedLogsMetadataQuery": "b59ada7585593473002a7b044f09daa85f160445cbc9a4e8ffe0b46d51875cb1", "CapturedLogsQuery": "872b617b4f33ee5f6feeba9a4c76ec986fca357695a114e3d7b63172e4600b57", - "PipelineRunLogsSubscription": "def2c2dc20d6b8640de7f4104ea03a58c8721cb5a632282f8e2d7489ab205280", - "RunLogsQuery": "0f1a38047ec63b668879f68aff67dc13d7a2b241c2f506d0109968897e01f385", + "PipelineRunLogsSubscription": "2f30c164760561ac620a80e7150088f0f5df364e89aa32648c1ecd9cd6698b8d", + "RunLogsQuery": "fc247c26adf353841ebe6e395922586491da0657d7f1f828cc4c066c1eec90d9", "QueuedRunCriteriaQuery": "da19aeed8a0a7e6f47619c6ba9efd721345481d8f08223282ea774e468400f21", "QueueDaemonStatusQuery": "aa51c596ee907346e60e2fe173bba10ae2ead067d45109225a2cd400a2278841", "PipelineEnvironmentQuery": "3b668b028997fb35b17b4d8a90a18b78dd8a70910f2c12aac63065c0584e3a10", diff --git a/js_modules/dagster-ui/packages/ui-core/src/graphql/schema.graphql b/js_modules/dagster-ui/packages/ui-core/src/graphql/schema.graphql index 2ee398fb3a6f7..f017768052fc6 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/graphql/schema.graphql +++ b/js_modules/dagster-ui/packages/ui-core/src/graphql/schema.graphql @@ -1240,6 +1240,9 @@ type LogsCapturedEvent implements MessageEvent { externalUrl: String externalStdoutUrl: String externalStderrUrl: String + logManagerMetadata: String + stderrUriOrPath: String + stdoutUriOrPath: String pid: Int logKey: String! } diff --git a/js_modules/dagster-ui/packages/ui-core/src/graphql/types.ts b/js_modules/dagster-ui/packages/ui-core/src/graphql/types.ts index 74ad1106c7aee..6cf41dd609633 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/graphql/types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/graphql/types.ts @@ -2432,10 +2432,13 @@ export type LogsCapturedEvent = MessageEvent & { fileKey: Scalars['String']['output']; level: LogLevel; logKey: Scalars['String']['output']; + logManagerMetadata: Maybe; message: Scalars['String']['output']; pid: Maybe; runId: Scalars['String']['output']; solidHandleID: Maybe; + stderrUriOrPath: Maybe; + stdoutUriOrPath: Maybe; stepKey: Maybe; stepKeys: Maybe>; timestamp: Scalars['String']['output']; @@ -9839,6 +9842,10 @@ export const buildLogsCapturedEvent = ( fileKey: overrides && overrides.hasOwnProperty('fileKey') ? overrides.fileKey! : 'et', level: overrides && overrides.hasOwnProperty('level') ? overrides.level! : LogLevel.CRITICAL, logKey: overrides && overrides.hasOwnProperty('logKey') ? overrides.logKey! : 'fuga', + logManagerMetadata: + overrides && overrides.hasOwnProperty('logManagerMetadata') + ? overrides.logManagerMetadata! + : 'distinctio', message: overrides && overrides.hasOwnProperty('message') ? overrides.message! : 'ex', pid: overrides && overrides.hasOwnProperty('pid') ? overrides.pid! : 7623, runId: overrides && overrides.hasOwnProperty('runId') ? overrides.runId! : 'modi', @@ -9846,6 +9853,14 @@ export const buildLogsCapturedEvent = ( overrides && overrides.hasOwnProperty('solidHandleID') ? overrides.solidHandleID! : 'assumenda', + stderrUriOrPath: + overrides && overrides.hasOwnProperty('stderrUriOrPath') + ? overrides.stderrUriOrPath! + : 'amet', + stdoutUriOrPath: + overrides && overrides.hasOwnProperty('stdoutUriOrPath') + ? overrides.stdoutUriOrPath! + : 'recusandae', stepKey: overrides && overrides.hasOwnProperty('stepKey') ? overrides.stepKey! : 'quia', stepKeys: overrides && overrides.hasOwnProperty('stepKeys') ? overrides.stepKeys! : [], timestamp: overrides && overrides.hasOwnProperty('timestamp') ? overrides.timestamp! : 'et', diff --git a/js_modules/dagster-ui/packages/ui-core/src/runs/CapturedLogPanel.tsx b/js_modules/dagster-ui/packages/ui-core/src/runs/CapturedLogPanel.tsx index 4655da40ef8bc..13344d0297350 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/runs/CapturedLogPanel.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/runs/CapturedLogPanel.tsx @@ -1,4 +1,4 @@ -import {Box, Colors, Icon} from '@dagster-io/ui-components'; +import {Box, Icon, Mono, Table, Tooltip, UnstyledButton} from '@dagster-io/ui-components'; import * as React from 'react'; import {RawLogContent} from './RawLogContent'; @@ -14,7 +14,9 @@ import { CapturedLogsSubscriptionVariables, } from './types/CapturedLogPanel.types'; import {AppContext} from '../app/AppContext'; +import {showSharedToaster} from '../app/DomUtils'; import {WebSocketContext} from '../app/WebSocketProvider'; +import {useCopyToClipboard} from '../app/browser'; interface CapturedLogProps { logKey: string[]; @@ -28,34 +30,98 @@ interface CapturedOrExternalLogPanelProps extends CapturedLogProps { export const CapturedOrExternalLogPanel = React.memo( ({logCaptureInfo, ...props}: CapturedOrExternalLogPanelProps) => { + const getShellCmd = (ioType: string, logCaptureInfo: ILogCaptureInfo | undefined) => { + if (logCaptureInfo?.logManagerMetadata) { + const path = + ioType === 'stdout' ? logCaptureInfo.stdoutUriOrPath : logCaptureInfo.stderrUriOrPath; + + try { + const metadata = JSON.parse(logCaptureInfo.logManagerMetadata); + switch (metadata.type) { + case 'AzureBlobComputeLogManager': + if (metadata.storage_account && metadata.container) { + return `az storage blob download --account-name ${metadata.storage_account} --container-name ${metadata.container} --name ${path}`; + } + } + } catch { + return undefined; + } + } + return undefined; + }; + const externalUrl = logCaptureInfo && (props.visibleIOType === 'stdout' ? logCaptureInfo.externalStdoutUrl : logCaptureInfo.externalStderrUrl); - if (externalUrl) { + const uriOrPath = + logCaptureInfo && + (props.visibleIOType === 'stdout' + ? logCaptureInfo.stdoutUriOrPath + : logCaptureInfo.stderrUriOrPath); + const shellCmd = getShellCmd(props.visibleIOType, logCaptureInfo); + + const copy = useCopyToClipboard(); + const onClickFn = async (key: string, value: string | undefined) => { + if (!value) { + return; + } + copy(value); + await showSharedToaster({ + intent: 'success', + icon: 'done', + message: `${key} copied!`, + }); + }; + const onClickExternalUri = async () => onClickFn('Log artifact URI', uriOrPath); + const onClickShellCmd = async () => onClickFn('Shell command', shellCmd); + + if (externalUrl || uriOrPath || shellCmd) { return ( - - View logs at - - {externalUrl} - - - + + + {externalUrl ? ( + + + + + ) : undefined} + + {uriOrPath ? ( + + + + + ) : undefined} + + {shellCmd ? ( + + + + + ) : undefined} + +
View logs + + + {externalUrl} + + + +
URI or Path + + + {uriOrPath} + + +
Shell command + + + {shellCmd} + + +
); } return props.logKey.length ? : null; diff --git a/js_modules/dagster-ui/packages/ui-core/src/runs/LogsRow.tsx b/js_modules/dagster-ui/packages/ui-core/src/runs/LogsRow.tsx index 32e9bb48044da..9a3e4861e0869 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/runs/LogsRow.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/runs/LogsRow.tsx @@ -197,6 +197,9 @@ export const LOGS_ROW_STRUCTURED_FRAGMENT = gql` externalUrl externalStdoutUrl externalStderrUrl + logManagerMetadata + stdoutUriOrPath + stderrUriOrPath } ... on AssetCheckEvaluationEvent { evaluation { diff --git a/js_modules/dagster-ui/packages/ui-core/src/runs/RunMetadataProvider.tsx b/js_modules/dagster-ui/packages/ui-core/src/runs/RunMetadataProvider.tsx index a3d495d021e7e..cc07a2a8ca6d5 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/runs/RunMetadataProvider.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/runs/RunMetadataProvider.tsx @@ -73,6 +73,9 @@ export interface ILogCaptureInfo { pid?: string; externalStdoutUrl?: string; externalStderrUrl?: string; + logManagerMetadata?: string; + stdoutUriOrPath?: string; + stderrUriOrPath?: string; } export interface IRunMetadataDict { @@ -277,6 +280,9 @@ export function extractMetadataFromLogs( pid: String(log.pid), externalStdoutUrl: log.externalStdoutUrl || undefined, externalStderrUrl: log.externalStderrUrl || undefined, + logManagerMetadata: log.logManagerMetadata || undefined, + stdoutUriOrPath: log.stdoutUriOrPath || undefined, + stderrUriOrPath: log.stderrUriOrPath || undefined, }; } @@ -454,6 +460,9 @@ export const RUN_METADATA_PROVIDER_MESSAGE_FRAGMENT = gql` pid externalStdoutUrl externalStderrUrl + logManagerMetadata + stdoutUriOrPath + stderrUriOrPath } } diff --git a/js_modules/dagster-ui/packages/ui-core/src/runs/types/LogsProvider.types.ts b/js_modules/dagster-ui/packages/ui-core/src/runs/types/LogsProvider.types.ts index bd9e99d3b0464..7ee68233e62e8 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/runs/types/LogsProvider.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/runs/types/LogsProvider.types.ts @@ -1654,6 +1654,9 @@ export type PipelineRunLogsSubscription = { pid: number | null; externalStdoutUrl: string | null; externalStderrUrl: string | null; + logManagerMetadata: string | null; + stdoutUriOrPath: string | null; + stderrUriOrPath: string | null; eventType: Types.DagsterEventType | null; externalUrl: string | null; } @@ -4996,6 +4999,9 @@ export type RunLogsSubscriptionSuccessFragment = { pid: number | null; externalStdoutUrl: string | null; externalStderrUrl: string | null; + logManagerMetadata: string | null; + stdoutUriOrPath: string | null; + stderrUriOrPath: string | null; eventType: Types.DagsterEventType | null; externalUrl: string | null; } @@ -8347,6 +8353,9 @@ export type RunLogsQuery = { pid: number | null; externalStdoutUrl: string | null; externalStderrUrl: string | null; + logManagerMetadata: string | null; + stdoutUriOrPath: string | null; + stderrUriOrPath: string | null; eventType: Types.DagsterEventType | null; externalUrl: string | null; } @@ -10084,6 +10093,6 @@ export type RunLogsQuery = { | {__typename: 'RunNotFoundError'}; }; -export const PipelineRunLogsSubscriptionVersion = 'def2c2dc20d6b8640de7f4104ea03a58c8721cb5a632282f8e2d7489ab205280'; +export const PipelineRunLogsSubscriptionVersion = '2f30c164760561ac620a80e7150088f0f5df364e89aa32648c1ecd9cd6698b8d'; -export const RunLogsQueryVersion = '0f1a38047ec63b668879f68aff67dc13d7a2b241c2f506d0109968897e01f385'; +export const RunLogsQueryVersion = 'fc247c26adf353841ebe6e395922586491da0657d7f1f828cc4c066c1eec90d9'; diff --git a/js_modules/dagster-ui/packages/ui-core/src/runs/types/LogsRow.types.ts b/js_modules/dagster-ui/packages/ui-core/src/runs/types/LogsRow.types.ts index fa3ab85f02214..a965a910be967 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/runs/types/LogsRow.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/runs/types/LogsRow.types.ts @@ -1484,6 +1484,9 @@ export type LogsRowStructuredFragment_LogsCapturedEvent = { externalUrl: string | null; externalStdoutUrl: string | null; externalStderrUrl: string | null; + logManagerMetadata: string | null; + stdoutUriOrPath: string | null; + stderrUriOrPath: string | null; }; export type LogsRowStructuredFragment_MaterializationEvent = { diff --git a/js_modules/dagster-ui/packages/ui-core/src/runs/types/LogsScrollingTableMessageFragment.types.ts b/js_modules/dagster-ui/packages/ui-core/src/runs/types/LogsScrollingTableMessageFragment.types.ts index 87127d7ac63cb..9ba1cae4d579f 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/runs/types/LogsScrollingTableMessageFragment.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/runs/types/LogsScrollingTableMessageFragment.types.ts @@ -1484,6 +1484,9 @@ export type LogsScrollingTableMessageFragment_LogsCapturedEvent = { externalUrl: string | null; externalStdoutUrl: string | null; externalStderrUrl: string | null; + logManagerMetadata: string | null; + stdoutUriOrPath: string | null; + stderrUriOrPath: string | null; }; export type LogsScrollingTableMessageFragment_MaterializationEvent = { diff --git a/js_modules/dagster-ui/packages/ui-core/src/runs/types/RunFragments.types.ts b/js_modules/dagster-ui/packages/ui-core/src/runs/types/RunFragments.types.ts index e75aab9ccde18..845a3c848ff51 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/runs/types/RunFragments.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/runs/types/RunFragments.types.ts @@ -1532,6 +1532,9 @@ export type RunDagsterRunEventFragment_LogsCapturedEvent = { pid: number | null; externalStdoutUrl: string | null; externalStderrUrl: string | null; + logManagerMetadata: string | null; + stdoutUriOrPath: string | null; + stderrUriOrPath: string | null; eventType: Types.DagsterEventType | null; externalUrl: string | null; }; diff --git a/js_modules/dagster-ui/packages/ui-core/src/runs/types/RunMetadataProvider.types.ts b/js_modules/dagster-ui/packages/ui-core/src/runs/types/RunMetadataProvider.types.ts index 9c7d0454624ba..dfec67ff85f47 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/runs/types/RunMetadataProvider.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/runs/types/RunMetadataProvider.types.ts @@ -207,6 +207,9 @@ export type RunMetadataProviderMessageFragment_LogsCapturedEvent = { pid: number | null; externalStdoutUrl: string | null; externalStderrUrl: string | null; + logManagerMetadata: string | null; + stdoutUriOrPath: string | null; + stderrUriOrPath: string | null; }; export type RunMetadataProviderMessageFragment_MaterializationEvent = {