From a945a259c54ee05d57f41c9d1d41b4b73aa12b5a Mon Sep 17 00:00:00 2001 From: Anton Standrik Date: Mon, 17 Mar 2025 18:30:52 +0300 Subject: [PATCH 1/3] feat: add database hyperlink to logging service --- src/components/LogsButton/LogsButton.tsx | 17 ++++ .../TenantNameWrapper/TenantNameWrapper.tsx | 18 +++-- src/components/TenantNameWrapper/i18n/en.json | 1 + .../ExtendedCluster/ExtendedCluster.tsx | 24 +++++- .../ExtendedTenant/ExtendedTenant.tsx | 14 +++- .../TenantOverview/TenantOverview.tsx | 3 + src/types/additionalProps.ts | 1 + src/utils/monitoring.ts | 78 +++++++++++++++++++ 8 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 src/components/LogsButton/LogsButton.tsx diff --git a/src/components/LogsButton/LogsButton.tsx b/src/components/LogsButton/LogsButton.tsx new file mode 100644 index 0000000000..e206c74b6d --- /dev/null +++ b/src/components/LogsButton/LogsButton.tsx @@ -0,0 +1,17 @@ +import {FileText} from '@gravity-ui/icons'; +import type {ButtonSize} from '@gravity-ui/uikit'; +import {Button, Icon} from '@gravity-ui/uikit'; + +interface LogsButtonProps { + className?: string; + href: string; + size?: ButtonSize; +} + +export function LogsButton({href, className, size = 'xs'}: LogsButtonProps) { + return ( + + ); +} diff --git a/src/components/TenantNameWrapper/TenantNameWrapper.tsx b/src/components/TenantNameWrapper/TenantNameWrapper.tsx index 757bd13327..45d44bdd2c 100644 --- a/src/components/TenantNameWrapper/TenantNameWrapper.tsx +++ b/src/components/TenantNameWrapper/TenantNameWrapper.tsx @@ -39,19 +39,25 @@ export function TenantNameWrapper({tenant, additionalTenantsProps}: TenantNameWr const isExternalLink = Boolean(backend); const monitoringLink = additionalTenantsProps?.getMonitoringLink?.(tenant.Name, tenant.Type); + const logsLink = additionalTenantsProps?.getLogsLink?.(tenant.Name); return ( - + {monitoringLink && ( + + )} + {logsLink && ( + + )} ) : null diff --git a/src/components/TenantNameWrapper/i18n/en.json b/src/components/TenantNameWrapper/i18n/en.json index f3032a1b3b..5fdaeccafa 100644 --- a/src/components/TenantNameWrapper/i18n/en.json +++ b/src/components/TenantNameWrapper/i18n/en.json @@ -1,5 +1,6 @@ { "field_links": "Links", "field_monitoring-link": "Monitoring", + "field_logs-link": "Logs", "context_unknown": "unknown database" } diff --git a/src/containers/AppWithClusters/ExtendedCluster/ExtendedCluster.tsx b/src/containers/AppWithClusters/ExtendedCluster/ExtendedCluster.tsx index 5d99cc0495..46e2820f89 100644 --- a/src/containers/AppWithClusters/ExtendedCluster/ExtendedCluster.tsx +++ b/src/containers/AppWithClusters/ExtendedCluster/ExtendedCluster.tsx @@ -11,7 +11,11 @@ import {cn} from '../../../utils/cn'; import {USE_CLUSTER_BALANCER_AS_BACKEND_KEY} from '../../../utils/constants'; import {useSetting} from '../../../utils/hooks'; import {useAdditionalNodesProps} from '../../../utils/hooks/useAdditionalNodesProps'; -import type {GetMonitoringClusterLink, GetMonitoringLink} from '../../../utils/monitoring'; +import type { + GetLogsLink, + GetMonitoringClusterLink, + GetMonitoringLink, +} from '../../../utils/monitoring'; import {getCleanBalancerValue, removeViewerPathname} from '../../../utils/parseBalancer'; import {getBackendFromNodeHost, getBackendFromRawNodeData} from '../../../utils/prepareBackend'; import type {Cluster} from '../../Cluster/Cluster'; @@ -63,6 +67,7 @@ const getAdditionalTenantsProps = ( balancer: string | undefined, useClusterBalancerAsBackend: boolean | undefined, getMonitoringLink?: GetMonitoringLink, + getLogsLink?: GetLogsLink, ) => { const additionalTenantsProps: AdditionalTenantsProps = {}; @@ -99,6 +104,20 @@ const getAdditionalTenantsProps = ( }; } + if (monitoring && getLogsLink) { + additionalTenantsProps.getLogsLink = (dbName?: string) => { + if (dbName) { + return getLogsLink({ + dbName, + clusterName, + monitoring, + }); + } + + return null; + }; + } + return additionalTenantsProps; }; @@ -106,11 +125,13 @@ interface ExtendedClusterProps { component: typeof Cluster; getMonitoringLink?: GetMonitoringLink; getMonitoringClusterLink?: GetMonitoringClusterLink; + getLogsLink?: GetLogsLink; } export function ExtendedCluster({ component: ClusterComponent, getMonitoringLink, getMonitoringClusterLink, + getLogsLink, }: ExtendedClusterProps) { const additionalNodesProps = useAdditionalNodesProps(); const {name, balancer, monitoring} = useClusterBaseInfo(); @@ -132,6 +153,7 @@ export function ExtendedCluster({ balancer, useClusterBalancerAsBackend, getMonitoringLink, + getLogsLink, )} additionalNodesProps={additionalNodesProps} /> diff --git a/src/containers/AppWithClusters/ExtendedTenant/ExtendedTenant.tsx b/src/containers/AppWithClusters/ExtendedTenant/ExtendedTenant.tsx index e6a39d95be..2184ba1c4f 100644 --- a/src/containers/AppWithClusters/ExtendedTenant/ExtendedTenant.tsx +++ b/src/containers/AppWithClusters/ExtendedTenant/ExtendedTenant.tsx @@ -1,17 +1,19 @@ import {useClusterBaseInfo} from '../../../store/reducers/cluster/cluster'; import type {ETenantType} from '../../../types/api/tenant'; import {useAdditionalNodesProps} from '../../../utils/hooks/useAdditionalNodesProps'; -import type {GetMonitoringLink} from '../../../utils/monitoring'; +import type {GetLogsLink, GetMonitoringLink} from '../../../utils/monitoring'; import type {Tenant} from '../../Tenant/Tenant'; export interface ExtendedTenantProps { component: typeof Tenant; getMonitoringLink?: GetMonitoringLink; + getLogsLink?: GetLogsLink; } export function ExtendedTenant({ component: TenantComponent, getMonitoringLink, + getLogsLink, }: ExtendedTenantProps) { const {monitoring} = useClusterBaseInfo(); const additionalNodesProps = useAdditionalNodesProps(); @@ -26,6 +28,16 @@ export function ExtendedTenant({ }); } + return null; + }, + getLogsLink: (dbName?: string) => { + if (monitoring && dbName && getLogsLink) { + return getLogsLink({ + dbName, + monitoring, + }); + } + return null; }, }; diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx index 1a13040579..76b97bd922 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx @@ -1,6 +1,7 @@ import {Loader} from '@gravity-ui/uikit'; import {EntityStatus} from '../../../../components/EntityStatus/EntityStatus'; +import {LogsButton} from '../../../../components/LogsButton/LogsButton'; import {MonitoringButton} from '../../../../components/MonitoringButton/MonitoringButton'; import {overviewApi} from '../../../../store/reducers/overview/overview'; import {TENANT_METRICS_TABS_IDS} from '../../../../store/reducers/tenant/constants'; @@ -150,6 +151,7 @@ export function TenantOverview({ } const monitoringLink = additionalTenantProps?.getMonitoringLink?.(Name, Type); + const logsLink = additionalTenantProps?.getLogsLink?.(Name); return (
@@ -158,6 +160,7 @@ export function TenantOverview({
{renderName()} {monitoringLink && } + {logsLink && }
string | undefined; getMonitoringLink?: (name?: string, type?: ETenantType) => string | null; + getLogsLink?: (name?: string) => string | null; } export type NodeAddress = Pick; diff --git a/src/utils/monitoring.ts b/src/utils/monitoring.ts index 0a69f577d2..1cbf6280d3 100644 --- a/src/utils/monitoring.ts +++ b/src/utils/monitoring.ts @@ -99,3 +99,81 @@ export function parseMonitoringData(monitoring: string): ParsedMonitoringData | return undefined; } + +interface GetLogsLinkProps { + dbName: string; + clusterName?: string; + monitoring: string; + project?: string; + service?: string; + level?: string; + from?: string; + to?: string; + columns?: string[]; + groupByField?: string; + chartType?: string; + linesMode?: string; +} + +export type GetLogsLink = typeof getLogsLink; + +export function getLogsLink({ + dbName, + clusterName, + monitoring, + project = 'kikimr', + service = 'ydb', + level = 'ERROR', + from = 'now-1h', + to = 'now', + columns = ['level', 'time', 'message', 'host'], + groupByField = 'level', + chartType = 'line', + linesMode = 'single', +}: GetLogsLinkProps): string { + try { + const data = parseMonitoringData(monitoring); + + if (data) { + const finalClusterName = data.cluster_name || clusterName || ''; + + const url = new URL(data.monitoring_url); + + url.pathname += '/_______/'; + + const queryFilter = { + project, + service, + cluster: finalClusterName, + database: dbName, + level, + }; + + url.searchParams.set('from', from); + url.searchParams.set('to', to); + + const queryString = Object.entries(queryFilter) + .map(([key, value]) => `${key} = "${value}"`) + .join(', '); + url.searchParams.set('query', `{${queryString}}`); + + url.searchParams.set('columns', columns.join(',')); + + if (groupByField) { + url.searchParams.set('groupByField', groupByField); + } + + if (chartType) { + url.searchParams.set('chartType', chartType); + } + + if (linesMode) { + url.searchParams.set('linesMode', linesMode); + } + + return url.toString(); + } + } catch {} + + return ''; +} From da8afb8bd12bbbb77489d257b86be5a3bcea96e6 Mon Sep 17 00:00:00 2001 From: Anton Standrik Date: Mon, 17 Mar 2025 19:25:05 +0300 Subject: [PATCH 2/3] fix: gaps --- .../TenantNameWrapper/TenantNameWrapper.tsx | 22 +++--- .../AppWithClusters/AppWithClusters.tsx | 10 ++- .../ExtendedCluster/ExtendedCluster.tsx | 3 +- .../ExtendedTenant/ExtendedTenant.tsx | 6 +- .../TenantOverview/TenantOverview.scss | 4 - .../TenantOverview/TenantOverview.tsx | 12 +-- src/utils/monitoring.ts | 75 +------------------ 7 files changed, 34 insertions(+), 98 deletions(-) diff --git a/src/components/TenantNameWrapper/TenantNameWrapper.tsx b/src/components/TenantNameWrapper/TenantNameWrapper.tsx index 45d44bdd2c..65f1799c9f 100644 --- a/src/components/TenantNameWrapper/TenantNameWrapper.tsx +++ b/src/components/TenantNameWrapper/TenantNameWrapper.tsx @@ -1,4 +1,4 @@ -import {DefinitionList, PopoverBehavior} from '@gravity-ui/uikit'; +import {DefinitionList, Flex, PopoverBehavior} from '@gravity-ui/uikit'; import {getTenantPath} from '../../containers/Tenant/TenantPages'; import type {PreparedTenant} from '../../store/reducers/tenants/types'; @@ -49,15 +49,17 @@ export function TenantNameWrapper({tenant, additionalTenantsProps}: TenantNameWr monitoringLink || logsLink ? ( - {monitoringLink && ( - - )} - {logsLink && ( - - )} + + {monitoringLink && ( + + )} + {logsLink && ( + + )} + ) : null diff --git a/src/containers/AppWithClusters/AppWithClusters.tsx b/src/containers/AppWithClusters/AppWithClusters.tsx index 3dcafb028d..3275d8d575 100644 --- a/src/containers/AppWithClusters/AppWithClusters.tsx +++ b/src/containers/AppWithClusters/AppWithClusters.tsx @@ -3,7 +3,11 @@ import React from 'react'; import type {Store} from '@reduxjs/toolkit'; import type {History} from 'history'; -import type {GetMonitoringClusterLink, GetMonitoringLink} from '../../utils/monitoring'; +import type { + GetLogsLink, + GetMonitoringClusterLink, + GetMonitoringLink, +} from '../../utils/monitoring'; import { getMonitoringClusterLink as getMonitoringClusterLinkDefault, getMonitoringLink as getMonitoringLinkDefault, @@ -17,6 +21,7 @@ import {ExtendedTenant} from './ExtendedTenant/ExtendedTenant'; export interface AppWithClustersProps { store: Store; history: History; + getLogsLink?: GetLogsLink; getMonitoringLink?: GetMonitoringLink; getMonitoringClusterLink?: GetMonitoringClusterLink; userSettings?: YDBEmbeddedUISettings; @@ -26,6 +31,7 @@ export interface AppWithClustersProps { export function AppWithClusters({ store, history, + getLogsLink, getMonitoringLink = getMonitoringLinkDefault, getMonitoringClusterLink = getMonitoringClusterLinkDefault, userSettings, @@ -38,6 +44,7 @@ export function AppWithClusters({ return ( @@ -49,6 +56,7 @@ export function AppWithClusters({ return ( ); diff --git a/src/containers/AppWithClusters/ExtendedCluster/ExtendedCluster.tsx b/src/containers/AppWithClusters/ExtendedCluster/ExtendedCluster.tsx index 46e2820f89..b334066506 100644 --- a/src/containers/AppWithClusters/ExtendedCluster/ExtendedCluster.tsx +++ b/src/containers/AppWithClusters/ExtendedCluster/ExtendedCluster.tsx @@ -106,11 +106,10 @@ const getAdditionalTenantsProps = ( if (monitoring && getLogsLink) { additionalTenantsProps.getLogsLink = (dbName?: string) => { - if (dbName) { + if (dbName && clusterName) { return getLogsLink({ dbName, clusterName, - monitoring, }); } diff --git a/src/containers/AppWithClusters/ExtendedTenant/ExtendedTenant.tsx b/src/containers/AppWithClusters/ExtendedTenant/ExtendedTenant.tsx index 2184ba1c4f..0b8205ffe3 100644 --- a/src/containers/AppWithClusters/ExtendedTenant/ExtendedTenant.tsx +++ b/src/containers/AppWithClusters/ExtendedTenant/ExtendedTenant.tsx @@ -15,7 +15,7 @@ export function ExtendedTenant({ getMonitoringLink, getLogsLink, }: ExtendedTenantProps) { - const {monitoring} = useClusterBaseInfo(); + const {monitoring, name: clusterName} = useClusterBaseInfo(); const additionalNodesProps = useAdditionalNodesProps(); const additionalTenantProps = { @@ -31,10 +31,10 @@ export function ExtendedTenant({ return null; }, getLogsLink: (dbName?: string) => { - if (monitoring && dbName && getLogsLink) { + if (clusterName && dbName && getLogsLink) { return getLogsLink({ dbName, - monitoring, + clusterName, }); } diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss b/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss index dcc5d35992..c12c761f05 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss @@ -17,10 +17,6 @@ } &__top { - display: flex; - align-items: center; - gap: 4px; - margin-bottom: 10px; line-height: 24px; diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx index 76b97bd922..6c0a981fbb 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx @@ -1,4 +1,4 @@ -import {Loader} from '@gravity-ui/uikit'; +import {Flex, Loader} from '@gravity-ui/uikit'; import {EntityStatus} from '../../../../components/EntityStatus/EntityStatus'; import {LogsButton} from '../../../../components/LogsButton/LogsButton'; @@ -157,11 +157,13 @@ export function TenantOverview({
{tenantType}
-
+ {renderName()} - {monitoringLink && } - {logsLink && } -
+ + {monitoringLink && } + {logsLink && } + + `${key} = "${value}"`) - .join(', '); - url.searchParams.set('query', `{${queryString}}`); - - url.searchParams.set('columns', columns.join(',')); - - if (groupByField) { - url.searchParams.set('groupByField', groupByField); - } - - if (chartType) { - url.searchParams.set('chartType', chartType); - } - - if (linesMode) { - url.searchParams.set('linesMode', linesMode); - } - - return url.toString(); - } - } catch {} - - return ''; -} +export type GetLogsLink = (props: GetLogsLinkProps) => string; From 1b53b583b0fd9b774ad2e18aab2f5a0c4c1c6e1b Mon Sep 17 00:00:00 2001 From: Anton Standrik Date: Mon, 17 Mar 2025 19:34:01 +0300 Subject: [PATCH 3/3] fix: condition --- .../AppWithClusters/ExtendedCluster/ExtendedCluster.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/containers/AppWithClusters/ExtendedCluster/ExtendedCluster.tsx b/src/containers/AppWithClusters/ExtendedCluster/ExtendedCluster.tsx index b334066506..c7fdfa6179 100644 --- a/src/containers/AppWithClusters/ExtendedCluster/ExtendedCluster.tsx +++ b/src/containers/AppWithClusters/ExtendedCluster/ExtendedCluster.tsx @@ -104,9 +104,9 @@ const getAdditionalTenantsProps = ( }; } - if (monitoring && getLogsLink) { + if (clusterName && getLogsLink) { additionalTenantsProps.getLogsLink = (dbName?: string) => { - if (dbName && clusterName) { + if (dbName) { return getLogsLink({ dbName, clusterName,