From 6a8096b8d758ff8a5ca73131b4392200cb0f5140 Mon Sep 17 00:00:00 2001 From: Yunus M Date: Thu, 26 Oct 2023 01:58:24 +0530 Subject: [PATCH 01/28] feat: santize identity payload and pass source to identity and group calls (#3804) --- frontend/src/AppRoutes/index.tsx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/frontend/src/AppRoutes/index.tsx b/frontend/src/AppRoutes/index.tsx index 62ed0946be..deff831a36 100644 --- a/frontend/src/AppRoutes/index.tsx +++ b/frontend/src/AppRoutes/index.tsx @@ -13,6 +13,7 @@ import useLicense, { LICENSE_PLAN_KEY } from 'hooks/useLicense'; import { NotificationProvider } from 'hooks/useNotifications'; import { ResourceProvider } from 'hooks/useResourceAttribute'; import history from 'lib/history'; +import { identity, pickBy } from 'lodash-es'; import { DashboardProvider } from 'providers/Dashboard/Dashboard'; import { QueryBuilderProvider } from 'providers/QueryBuilder'; import { Suspense, useEffect, useState } from 'react'; @@ -90,13 +91,19 @@ function App(): JSX.Element { const orgName = org && Array.isArray(org) && org.length > 0 ? org[0].name : ''; + const { name, email } = user; + const identifyPayload = { - email: user?.email, - name: user?.name, + email, + name, company_name: orgName, role, + source: 'signoz-ui', }; - const domain = extractDomain(user?.email); + + const sanitizedIdentifyPayload = pickBy(identifyPayload, identity); + + const domain = extractDomain(email); const hostNameParts = hostname.split('.'); @@ -106,13 +113,14 @@ function App(): JSX.Element { data_region: hostNameParts[1], tenant_url: hostname, company_domain: domain, + source: 'signoz-ui', }; - window.analytics.identify(user?.email, identifyPayload); + window.analytics.identify(email, sanitizedIdentifyPayload); window.analytics.group(domain, groupTraits); - window.clarity('identify', user.email, user.name); + window.clarity('identify', email, name); }; useEffect(() => { From 856c04220f72d74ed631561396be62f6000d039f Mon Sep 17 00:00:00 2001 From: Ankit Nayan Date: Thu, 26 Oct 2023 13:46:26 +0530 Subject: [PATCH 02/28] fix: pkg/query-service/Dockerfile to reduce vulnerabilities (#3811) Co-authored-by: snyk-bot --- pkg/query-service/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/query-service/Dockerfile b/pkg/query-service/Dockerfile index 9d62c5cc62..b7af36ee84 100644 --- a/pkg/query-service/Dockerfile +++ b/pkg/query-service/Dockerfile @@ -1,5 +1,5 @@ # use a minimal alpine image -FROM alpine:3.17 +FROM alpine:3.18.3 # Add Maintainer Info LABEL maintainer="signoz" From 7de3cec477672e039d600b5c6de16c394ab6dd0e Mon Sep 17 00:00:00 2001 From: Yunus M Date: Thu, 26 Oct 2023 18:39:04 +0530 Subject: [PATCH 03/28] fix: update logic to conditionally show Get Started and Billing routes (#3807) --- frontend/src/AppRoutes/Private.tsx | 38 +++++--- frontend/src/AppRoutes/routes.ts | 2 +- frontend/src/container/SideNav/SideNav.tsx | 65 ++++++++----- frontend/src/hooks/useLicense/constant.ts | 2 +- .../src/mocks-server/__mockdata__/licenses.ts | 34 +++++++ .../WorkspaceLocked/WorkspaceLocked.test.tsx | 38 ++++++-- .../pages/WorkspaceLocked/WorkspaceLocked.tsx | 93 +++++++++++-------- frontend/src/types/roles.ts | 6 ++ 8 files changed, 193 insertions(+), 85 deletions(-) diff --git a/frontend/src/AppRoutes/Private.tsx b/frontend/src/AppRoutes/Private.tsx index 70f8cccf04..f559dc633f 100644 --- a/frontend/src/AppRoutes/Private.tsx +++ b/frontend/src/AppRoutes/Private.tsx @@ -39,10 +39,12 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element { [pathname], ); - const { data: licensesData } = useLicense(); + const { + data: licensesData, + isFetching: isFetchingLicensesData, + } = useLicense(); const { - user, isUserFetching, isUserFetchingError, isLoggedIn: isLoggedInState, @@ -116,7 +118,7 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element { if ( localStorageUserAuthToken && localStorageUserAuthToken.refreshJwt && - user?.userId === '' + isUserFetching ) { handleUserLoginIfTokenPresent(key); } else { @@ -131,28 +133,34 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element { if (path && path !== ROUTES.WORKSPACE_LOCKED) { history.push(ROUTES.WORKSPACE_LOCKED); - } - dispatch({ - type: UPDATE_USER_IS_FETCH, - payload: { - isUserFetching: false, - }, - }); + dispatch({ + type: UPDATE_USER_IS_FETCH, + payload: { + isUserFetching: false, + }, + }); + } }; + useEffect(() => { + if (!isFetchingLicensesData) { + const shouldBlockWorkspace = licensesData?.payload?.workSpaceBlock; + + if (shouldBlockWorkspace) { + navigateToWorkSpaceBlocked(currentRoute); + } + } + }, [isFetchingLicensesData]); + // eslint-disable-next-line sonarjs/cognitive-complexity useEffect(() => { (async (): Promise => { try { - const shouldBlockWorkspace = licensesData?.payload?.workSpaceBlock; - if (currentRoute) { const { isPrivate, key } = currentRoute; - if (shouldBlockWorkspace) { - navigateToWorkSpaceBlocked(currentRoute); - } else if (isPrivate) { + if (isPrivate && key !== ROUTES.WORKSPACE_LOCKED) { handlePrivateRoutes(key); } else { // no need to fetch the user and make user fetching false diff --git a/frontend/src/AppRoutes/routes.ts b/frontend/src/AppRoutes/routes.ts index b764d609b3..dda9d68e1d 100644 --- a/frontend/src/AppRoutes/routes.ts +++ b/frontend/src/AppRoutes/routes.ts @@ -299,7 +299,7 @@ const routes: AppRoutes[] = [ path: ROUTES.WORKSPACE_LOCKED, exact: true, component: WorkspaceBlocked, - isPrivate: false, + isPrivate: true, key: 'WORKSPACE_LOCKED', }, ]; diff --git a/frontend/src/container/SideNav/SideNav.tsx b/frontend/src/container/SideNav/SideNav.tsx index 008b64415e..0e0ff1795f 100644 --- a/frontend/src/container/SideNav/SideNav.tsx +++ b/frontend/src/container/SideNav/SideNav.tsx @@ -7,13 +7,20 @@ import ROUTES from 'constants/routes'; import useLicense, { LICENSE_PLAN_KEY } from 'hooks/useLicense'; import history from 'lib/history'; import { LifeBuoy } from 'lucide-react'; -import { useCallback, useLayoutEffect, useMemo, useState } from 'react'; +import { + useCallback, + useEffect, + useLayoutEffect, + useMemo, + useState, +} from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; import { useLocation } from 'react-router-dom'; import { sideBarCollapse } from 'store/actions/app'; import { AppState } from 'store/reducers'; import AppReducer from 'types/reducer/app'; +import { USER_ROLES } from 'types/roles'; import { checkVersionState, isCloudUser, isEECloudUser } from 'utils/app'; import { routeConfig, styles } from './config'; @@ -33,6 +40,7 @@ import { function SideNav(): JSX.Element { const dispatch = useDispatch(); + const [menuItems, setMenuItems] = useState(defaultMenuItems); const [collapsed, setCollapsed] = useState( getLocalStorageKey(IS_SIDEBAR_COLLAPSED) === 'true', ); @@ -44,36 +52,45 @@ function SideNav(): JSX.Element { featureResponse, } = useSelector((state) => state.app); - const { data } = useLicense(); + const { data, isFetching } = useLicense(); let secondaryMenuItems: MenuItem[] = []; - const isOnBasicPlan = - data?.payload?.licenses?.some( - (license) => - license.isCurrent && license.planKey === LICENSE_PLAN_KEY.BASIC_PLAN, - ) || data?.payload?.licenses === null; + useEffect((): void => { + const isOnboardingEnabled = + featureResponse.data?.find( + (feature) => feature.name === FeatureKeys.ONBOARDING, + )?.active || false; - const menuItems = useMemo( - () => - defaultMenuItems.filter((item) => { - const isOnboardingEnabled = - featureResponse.data?.find( - (feature) => feature.name === FeatureKeys.ONBOARDING, - )?.active || false; + if (!isOnboardingEnabled || !isCloudUser()) { + let items = [...menuItems]; - if (role !== 'ADMIN' || isOnBasicPlan) { - return item.key !== ROUTES.BILLING; - } + items = items.filter((item) => item.key !== ROUTES.GET_STARTED); - if (!isOnboardingEnabled || !isCloudUser()) { - return item.key !== ROUTES.GET_STARTED; - } + setMenuItems(items); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [featureResponse.data]); - return true; - }), - [featureResponse.data, isOnBasicPlan, role], - ); + // using a separate useEffect as the license fetching call takes few milliseconds + useEffect(() => { + if (!isFetching) { + let items = [...menuItems]; + + const isOnBasicPlan = + data?.payload?.licenses?.some( + (license) => + license.isCurrent && license.planKey === LICENSE_PLAN_KEY.BASIC_PLAN, + ) || data?.payload?.licenses === null; + + if (role !== USER_ROLES.ADMIN || isOnBasicPlan) { + items = items.filter((item) => item.key !== ROUTES.BILLING); + } + + setMenuItems(items); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [data?.payload?.licenses, isFetching, role]); const { pathname, search } = useLocation(); diff --git a/frontend/src/hooks/useLicense/constant.ts b/frontend/src/hooks/useLicense/constant.ts index 55f81dac46..71134fc08f 100644 --- a/frontend/src/hooks/useLicense/constant.ts +++ b/frontend/src/hooks/useLicense/constant.ts @@ -1,6 +1,6 @@ export const LICENSE_PLAN_KEY = { ENTERPRISE_PLAN: 'ENTERPRISE_PLAN', - BASIC_PLAN: 'BASIC_PLAN ', + BASIC_PLAN: 'BASIC_PLAN', }; export const LICENSE_PLAN_STATUS = { diff --git a/frontend/src/mocks-server/__mockdata__/licenses.ts b/frontend/src/mocks-server/__mockdata__/licenses.ts index f74e59079e..fca1a67ce6 100644 --- a/frontend/src/mocks-server/__mockdata__/licenses.ts +++ b/frontend/src/mocks-server/__mockdata__/licenses.ts @@ -7,6 +7,40 @@ export const licensesSuccessResponse = { workSpaceBlock: false, trialConvertedToSubscription: false, gracePeriodEnd: -1, + licenses: [ + { + key: 'testKeyId1', + activationId: 'testActivationId1', + ValidationMessage: '', + isCurrent: false, + planKey: 'ENTERPRISE_PLAN', + ValidFrom: '2022-10-13T13:58:51Z', + ValidUntil: '2023-10-13T19:57:37Z', + status: 'VALID', + }, + { + key: 'testKeyId2', + activationId: 'testActivationId2', + ValidationMessage: '', + isCurrent: true, + planKey: 'ENTERPRISE_PLAN', + ValidFrom: '2023-09-12T11:55:43Z', + ValidUntil: '2024-09-11T17:34:29Z', + status: 'VALID', + }, + ], + }, +}; + +export const licensesSuccessWorkspaceLockedResponse = { + status: 'success', + data: { + trialStart: 1695992049, + trialEnd: 1697806449, + onTrial: false, + workSpaceBlock: true, + trialConvertedToSubscription: false, + gracePeriodEnd: -1, licenses: [ { key: 'testKeyId1', diff --git a/frontend/src/pages/WorkspaceLocked/WorkspaceLocked.test.tsx b/frontend/src/pages/WorkspaceLocked/WorkspaceLocked.test.tsx index d0c42b253c..bc6885ae65 100644 --- a/frontend/src/pages/WorkspaceLocked/WorkspaceLocked.test.tsx +++ b/frontend/src/pages/WorkspaceLocked/WorkspaceLocked.test.tsx @@ -1,46 +1,70 @@ +import { licensesSuccessWorkspaceLockedResponse } from 'mocks-server/__mockdata__/licenses'; +import { server } from 'mocks-server/server'; +import { rest } from 'msw'; import { act, render, screen } from 'tests/test-utils'; import WorkspaceLocked from '.'; describe('WorkspaceLocked', () => { + const apiURL = 'http://localhost/api/v2/licenses'; + test('Should render the component', async () => { + server.use( + rest.get(apiURL, (req, res, ctx) => + res(ctx.status(200), ctx.json(licensesSuccessWorkspaceLockedResponse)), + ), + ); + act(() => { render(); }); - const workspaceLocked = screen.getByRole('heading', { + + const workspaceLocked = await screen.findByRole('heading', { name: /workspace locked/i, }); expect(workspaceLocked).toBeInTheDocument(); - const gotQuestionText = screen.getByText(/got question?/i); + const gotQuestionText = await screen.findByText(/got question?/i); expect(gotQuestionText).toBeInTheDocument(); - const contactUsLink = screen.getByRole('link', { + const contactUsLink = await screen.findByRole('link', { name: /contact us/i, }); expect(contactUsLink).toBeInTheDocument(); }); test('Render for Admin', async () => { + server.use( + rest.get(apiURL, (req, res, ctx) => + res(ctx.status(200), ctx.json(licensesSuccessWorkspaceLockedResponse)), + ), + ); + render(); - const contactAdminMessage = screen.queryByText( + const contactAdminMessage = await screen.queryByText( /please contact your administrator for further help/i, ); expect(contactAdminMessage).not.toBeInTheDocument(); - const updateCreditCardBtn = screen.getByRole('button', { + const updateCreditCardBtn = await screen.findByRole('button', { name: /update credit card/i, }); expect(updateCreditCardBtn).toBeInTheDocument(); }); test('Render for non Admin', async () => { + server.use( + rest.get(apiURL, (req, res, ctx) => + res(ctx.status(200), ctx.json(licensesSuccessWorkspaceLockedResponse)), + ), + ); + render(, {}, 'VIEWER'); - const updateCreditCardBtn = screen.queryByRole('button', { + const updateCreditCardBtn = await screen.queryByRole('button', { name: /update credit card/i, }); expect(updateCreditCardBtn).not.toBeInTheDocument(); - const contactAdminMessage = screen.getByText( + const contactAdminMessage = await screen.findByText( /please contact your administrator for further help/i, ); expect(contactAdminMessage).toBeInTheDocument(); diff --git a/frontend/src/pages/WorkspaceLocked/WorkspaceLocked.tsx b/frontend/src/pages/WorkspaceLocked/WorkspaceLocked.tsx index 676c163729..924509de82 100644 --- a/frontend/src/pages/WorkspaceLocked/WorkspaceLocked.tsx +++ b/frontend/src/pages/WorkspaceLocked/WorkspaceLocked.tsx @@ -2,11 +2,13 @@ import './WorkspaceLocked.styles.scss'; import { CreditCardOutlined, LockOutlined } from '@ant-design/icons'; -import { Button, Card, Typography } from 'antd'; +import { Button, Card, Skeleton, Typography } from 'antd'; import updateCreditCardApi from 'api/billing/checkout'; import { SOMETHING_WENT_WRONG } from 'constants/api'; +import ROUTES from 'constants/routes'; import useLicense from 'hooks/useLicense'; import { useNotifications } from 'hooks/useNotifications'; +import history from 'lib/history'; import { useCallback, useEffect, useState } from 'react'; import { useMutation } from 'react-query'; import { useSelector } from 'react-redux'; @@ -22,16 +24,28 @@ export default function WorkspaceBlocked(): JSX.Element { const { notifications } = useNotifications(); - const { isFetching, data: licensesData } = useLicense(); + const { + isFetching: isFetchingLicenseData, + isLoading: isLoadingLicenseData, + data: licensesData, + } = useLicense(); useEffect(() => { - const activeValidLicense = - licensesData?.payload?.licenses?.find( - (license) => license.isCurrent === true, - ) || null; + if (!isFetchingLicenseData) { + const shouldBlockWorkspace = licensesData?.payload?.workSpaceBlock; - setActiveLicense(activeValidLicense); - }, [isFetching, licensesData]); + if (!shouldBlockWorkspace) { + history.push(ROUTES.APPLICATION); + } + + const activeValidLicense = + licensesData?.payload?.licenses?.find( + (license) => license.isCurrent === true, + ) || null; + + setActiveLicense(activeValidLicense); + } + }, [isFetchingLicenseData, licensesData]); const { mutate: updateCreditCard, isLoading } = useMutation( updateCreditCardApi, @@ -62,36 +76,41 @@ export default function WorkspaceBlocked(): JSX.Element { return ( - - Workspace Locked - - - You have been locked out of your workspace because your trial ended without - an upgrade to a paid plan. Your data will continue to be ingested till{' '} - {getFormattedDate(licensesData?.payload?.gracePeriodEnd || Date.now())} , at - which point we will drop all the ingested data and terminate the account. - {!isAdmin && 'Please contact your administrator for further help'} - - - {isAdmin && ( - + {isLoadingLicenseData || !licensesData?.payload?.workSpaceBlock ? ( + + ) : ( + <> + + Workspace Locked + + You have been locked out of your workspace because your trial ended + without an upgrade to a paid plan. Your data will continue to be ingested + till{' '} + {getFormattedDate(licensesData?.payload?.gracePeriodEnd || Date.now())} , + at which point we will drop all the ingested data and terminate the + account. + {!isAdmin && 'Please contact your administrator for further help'} + + {isAdmin && ( + + )} +
+ Got Questions? + + Contact Us + +
+ )} - -
- Got Questions? - - Contact Us - -
); } diff --git a/frontend/src/types/roles.ts b/frontend/src/types/roles.ts index 02216f6d74..0ac7deaf24 100644 --- a/frontend/src/types/roles.ts +++ b/frontend/src/types/roles.ts @@ -3,3 +3,9 @@ export type VIEWER = 'VIEWER'; export type EDITOR = 'EDITOR'; export type ROLES = ADMIN | VIEWER | EDITOR; + +export const USER_ROLES = { + ADMIN: 'ADMIN', + VIEWER: 'VIEWER', + EDITOR: 'EDITOR', +}; From f427bac99344cd0f9a6ccd24bdbbf84fe6778ee2 Mon Sep 17 00:00:00 2001 From: Raj Kamal Singh <1133322+rkssisodiya@users.noreply.github.com> Date: Thu, 26 Oct 2023 19:37:13 +0530 Subject: [PATCH 04/28] Fix: grok parser in pipeline previews (#3810) * chore: add test for previewing pipeline with grok parser * chore: import grok parser in logparsing preview to ensure its a registered logtransform op * chore: add dependencies for grok parsing operator --- go.mod | 12 ++-- go.sum | 18 ++++++ .../app/logparsingpipeline/preview.go | 1 + .../app/logparsingpipeline/preview_test.go | 61 +++++++++++++++++++ 4 files changed, 87 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 8cd7a896e3..308f5152b4 100644 --- a/go.mod +++ b/go.mod @@ -80,6 +80,7 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect github.com/ClickHouse/ch-go v0.58.2 // indirect github.com/DATA-DOG/go-sqlmock v1.5.0 // indirect + github.com/SigNoz/signoz-otel-collector v0.79.12 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/andybalholm/brotli v1.0.5 // indirect github.com/aws/aws-sdk-go v1.44.302 // indirect @@ -93,7 +94,7 @@ require ( github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect + github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect github.com/go-faster/city v1.0.1 // indirect github.com/go-faster/errors v0.6.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect @@ -147,17 +148,18 @@ require ( github.com/robfig/cron/v3 v3.0.1 // indirect github.com/segmentio/asm v1.2.0 // indirect github.com/segmentio/backo-go v1.0.1 // indirect - github.com/shirou/gopsutil/v3 v3.23.4 // indirect - github.com/shoenig/go-m1cpu v0.1.5 // indirect + github.com/shirou/gopsutil/v3 v3.23.5 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/shopspring/decimal v1.3.1 // indirect - github.com/sirupsen/logrus v1.9.0 // indirect + github.com/sirupsen/logrus v1.9.2 // indirect github.com/smarty/assertions v1.15.0 // indirect github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/numcpus v0.6.0 // indirect + github.com/vjeantet/grok v1.0.1 // indirect github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect - github.com/yusufpapurcu/wmi v1.2.2 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/collector/featuregate v1.0.0-rcv0012 // indirect go.opentelemetry.io/collector/semconv v0.81.0 // indirect diff --git a/go.sum b/go.sum index 5196c824b5..24415b2e12 100644 --- a/go.sum +++ b/go.sum @@ -99,6 +99,8 @@ github.com/SigNoz/govaluate v0.0.0-20220522085550-d19c08c206cb h1:bneLSKPf9YUSFm github.com/SigNoz/govaluate v0.0.0-20220522085550-d19c08c206cb/go.mod h1:JznGDNg9x1cujDKa22RaQOimOvvEfy3nxzDGd8XDgmA= github.com/SigNoz/prometheus v1.9.78 h1:bB3yuDrRzi/Mv00kWayR9DZbyjTuGfendSqISyDcXiY= github.com/SigNoz/prometheus v1.9.78/go.mod h1:MffmFu2qFILQrOHehx3D0XjYtaZMVfI+Ppeiv98x4Ww= +github.com/SigNoz/signoz-otel-collector v0.79.12 h1:0yDMhcN7Taa8WrFv8YrHRaDvRxHqLfp5c6w1TSEWk+I= +github.com/SigNoz/signoz-otel-collector v0.79.12/go.mod h1:MXjHt3atjTAF2Wrqu0W7Xx+oJ1yb8UfpsNu+A8Ssjtg= github.com/SigNoz/zap_otlp v0.1.0 h1:T7rRcFN87GavY8lDGZj0Z3Xv6OhJA6Pj3I9dNPmqvRc= github.com/SigNoz/zap_otlp v0.1.0/go.mod h1:lcHvbDbRgvDnPxo9lDlaL1JK2PyOyouP/C3ynnYIvyo= github.com/SigNoz/zap_otlp/zap_otlp_encoder v0.0.0-20230822164844-1b861a431974 h1:PKVgdf83Yw+lZJbFtNGBgqXiXNf3+kOXW2qZ7Ms7OaY= @@ -231,6 +233,8 @@ github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBd github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8= +github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= @@ -752,10 +756,16 @@ github.com/sethvargo/go-password v0.2.0 h1:BTDl4CC/gjf/axHMaDQtw507ogrXLci6XRiLc github.com/sethvargo/go-password v0.2.0/go.mod h1:Ym4Mr9JXLBycr02MFuVQ/0JHidNetSgbzutTr3zsYXE= github.com/shirou/gopsutil/v3 v3.23.4 h1:hZwmDxZs7Ewt75DV81r4pFMqbq+di2cbt9FsQBqLD2o= github.com/shirou/gopsutil/v3 v3.23.4/go.mod h1:ZcGxyfzAMRevhUR2+cfhXDH6gQdFYE/t8j1nsU4mPI8= +github.com/shirou/gopsutil/v3 v3.23.5 h1:5SgDCeQ0KW0S4N0znjeM/eFHXXOKyv2dVNgRq/c9P6Y= +github.com/shirou/gopsutil/v3 v3.23.5/go.mod h1:Ng3Maa27Q2KARVJ0SPZF5NdrQSC3XHKP8IIWrHgMeLY= github.com/shoenig/go-m1cpu v0.1.5 h1:LF57Z/Fpb/WdGLjt2HZilNnmZOxg/q2bSKTQhgbrLrQ= github.com/shoenig/go-m1cpu v0.1.5/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.3 h1:GVXWJFk9PiOjN0KoJ7VrJGH6uLPnqxR7/fe3HUPfE0c= github.com/shoenig/test v0.6.3/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -765,6 +775,8 @@ github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= +github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY= github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -800,6 +812,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= @@ -811,6 +824,8 @@ github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/vjeantet/grok v1.0.1 h1:2rhIR7J4gThTgcZ1m2JY4TrJZNgjn985U28kT2wQrJ4= +github.com/vjeantet/grok v1.0.1/go.mod h1:ax1aAchzC6/QMXMcyzHQGZWaW1l195+uMYIkCWPCNIo= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= @@ -827,6 +842,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= @@ -1137,6 +1154,7 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/pkg/query-service/app/logparsingpipeline/preview.go b/pkg/query-service/app/logparsingpipeline/preview.go index 9ce6839b00..f25a1d6922 100644 --- a/pkg/query-service/app/logparsingpipeline/preview.go +++ b/pkg/query-service/app/logparsingpipeline/preview.go @@ -7,6 +7,7 @@ import ( "strings" "time" + _ "github.com/SigNoz/signoz-otel-collector/pkg/parser/grok" "github.com/open-telemetry/opentelemetry-collector-contrib/processor/logstransformprocessor" "github.com/pkg/errors" "go.opentelemetry.io/collector/pdata/pcommon" diff --git a/pkg/query-service/app/logparsingpipeline/preview_test.go b/pkg/query-service/app/logparsingpipeline/preview_test.go index c453cb1445..b6cfb855f3 100644 --- a/pkg/query-service/app/logparsingpipeline/preview_test.go +++ b/pkg/query-service/app/logparsingpipeline/preview_test.go @@ -141,6 +141,67 @@ func TestPipelinePreview(t *testing.T) { } +func TestGrokParsingPreview(t *testing.T) { + require := require.New(t) + + testPipelines := []Pipeline{ + { + OrderId: 1, + Name: "pipeline1", + Alias: "pipeline1", + Enabled: true, + Filter: &v3.FilterSet{ + Operator: "AND", + Items: []v3.FilterItem{ + { + Key: v3.AttributeKey{ + Key: "method", + DataType: v3.AttributeKeyDataTypeString, + Type: v3.AttributeKeyTypeTag, + }, + Operator: "=", + Value: "GET", + }, + }, + }, + Config: []PipelineOperator{ + { + OrderId: 1, + ID: "grok", + Type: "grok_parser", + Enabled: true, + Name: "test grok parser", + OnError: "send", + ParseFrom: "body", + ParseTo: "attributes", + Pattern: "%{TIMESTAMP_ISO8601:timestamp}%{SPACE}%{WORD:log_level}%{SPACE}%{NOTSPACE:location}%{SPACE}%{GREEDYDATA:message}", + }, + }, + }, + } + + testLog := makeTestLogEntry( + "2023-10-26T04:38:00.602Z INFO route/server.go:71 HTTP request received", + map[string]string{ + "method": "GET", + }, + ) + result, err := SimulatePipelinesProcessing( + context.Background(), + testPipelines, + []model.SignozLog{ + testLog, + }, + ) + + require.Nil(err) + require.Equal(1, len(result)) + processed := result[0] + + require.Equal("INFO", processed.Attributes_string["log_level"]) + require.Equal("route/server.go:71", processed.Attributes_string["location"]) +} + func makeTestLogEntry( body string, attributes map[string]string, From ed4ba1aa24da0b5b6af18fc26144d362ebbff6a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Oct 2023 23:58:35 +0530 Subject: [PATCH 05/28] chore(deps): bump google.golang.org/grpc from 1.57.0 to 1.57.1 (#3808) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.57.0 to 1.57.1. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.57.0...v1.57.1) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 54 +++++++++++++++++++++++------------------------------- 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index 308f5152b4..a739c36aa9 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.21 require ( github.com/ClickHouse/clickhouse-go/v2 v2.14.0 github.com/SigNoz/govaluate v0.0.0-20220522085550-d19c08c206cb + github.com/SigNoz/signoz-otel-collector v0.79.12 github.com/SigNoz/zap_otlp/zap_otlp_encoder v0.0.0-20230822164844-1b861a431974 github.com/SigNoz/zap_otlp/zap_otlp_sync v0.0.0-20230822164844-1b861a431974 github.com/antonmedv/expr v1.12.5 @@ -64,7 +65,7 @@ require ( golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 golang.org/x/net v0.17.0 golang.org/x/oauth2 v0.10.0 - google.golang.org/grpc v1.57.0 + google.golang.org/grpc v1.57.1 google.golang.org/protobuf v1.31.0 gopkg.in/segmentio/analytics-go.v3 v3.1.0 gopkg.in/yaml.v2 v2.4.0 @@ -80,7 +81,6 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect github.com/ClickHouse/ch-go v0.58.2 // indirect github.com/DATA-DOG/go-sqlmock v1.5.0 // indirect - github.com/SigNoz/signoz-otel-collector v0.79.12 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/andybalholm/brotli v1.0.5 // indirect github.com/aws/aws-sdk-go v1.44.302 // indirect diff --git a/go.sum b/go.sum index 24415b2e12..acbb05913c 100644 --- a/go.sum +++ b/go.sum @@ -198,8 +198,8 @@ github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m3 github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY= github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-connections v0.4.1-0.20210727194412-58542c764a11 h1:IPrmumsT9t5BS7XcPhgsCTlkWbYg80SEXUzDpReaU6Y= +github.com/docker/go-connections v0.4.1-0.20210727194412-58542c764a11/go.mod h1:a6bNUGTbQBsY6VRHTr4h/rkOXjl244DyRD0tx3fgq4Q= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -207,8 +207,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= -github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= -github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= +github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -231,7 +231,6 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8= github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= @@ -274,8 +273,8 @@ github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= -github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= @@ -284,8 +283,9 @@ github.com/go-redis/redismock/v8 v8.11.5 h1:RJFIiua58hrBrSpXhnGX3on79AU3S271H4Zh github.com/go-redis/redismock/v8 v8.11.5/go.mod h1:UaAU9dEe1C+eGr+FHV5prCWIt0hafyPWbGMEWE0UWdA= github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= -github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= @@ -341,8 +341,8 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= -github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= +github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -362,8 +362,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -447,8 +447,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= -github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= +github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= @@ -476,6 +476,7 @@ github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoI github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hetznercloud/hcloud-go v1.41.0 h1:KJGFRRc68QiVu4PrEP5BmCQVveCP2CM26UGQUKGpIUs= github.com/hetznercloud/hcloud-go/v2 v2.0.0 h1:Sg1DJ+MAKvbYAqaBaq9tPbwXBS2ckPIaMtVdUjKu+4g= github.com/hetznercloud/hcloud-go/v2 v2.0.0/go.mod h1:4iUG2NG8b61IAwNx6UsMWQ6IfIf/i1RsG0BbsKAyR5Q= github.com/hjson/hjson-go/v4 v4.0.0 h1:wlm6IYYqHjOdXH1gHev4VoXCaW20HdQAGCxdOEEg2cs= @@ -483,8 +484,8 @@ github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEF github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/ionos-cloud/sdk-go/v6 v6.1.8 h1:493wE/BkZxJf7x79UCE0cYGPZoqQcPiEBALvt7uVGY0= @@ -541,8 +542,9 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/linode/linodego v1.19.0 h1:n4WJrcr9+30e9JGZ6DI0nZbm5SdAj1kSwvvt/998YUw= github.com/linode/linodego v1.19.0/go.mod h1:XZFR+yJ9mm2kwf6itZ6SCpu+6w3KnIevV0Uu5HNWJgQ= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= @@ -754,16 +756,10 @@ github.com/segmentio/backo-go v1.0.1 h1:68RQccglxZeyURy93ASB/2kc9QudzgIDexJ927N+ github.com/segmentio/backo-go v1.0.1/go.mod h1:9/Rh6yILuLysoQnZ2oNooD2g7aBnvM7r/fNVxRNWfBc= github.com/sethvargo/go-password v0.2.0 h1:BTDl4CC/gjf/axHMaDQtw507ogrXLci6XRiLc7i/UHI= github.com/sethvargo/go-password v0.2.0/go.mod h1:Ym4Mr9JXLBycr02MFuVQ/0JHidNetSgbzutTr3zsYXE= -github.com/shirou/gopsutil/v3 v3.23.4 h1:hZwmDxZs7Ewt75DV81r4pFMqbq+di2cbt9FsQBqLD2o= -github.com/shirou/gopsutil/v3 v3.23.4/go.mod h1:ZcGxyfzAMRevhUR2+cfhXDH6gQdFYE/t8j1nsU4mPI8= github.com/shirou/gopsutil/v3 v3.23.5 h1:5SgDCeQ0KW0S4N0znjeM/eFHXXOKyv2dVNgRq/c9P6Y= github.com/shirou/gopsutil/v3 v3.23.5/go.mod h1:Ng3Maa27Q2KARVJ0SPZF5NdrQSC3XHKP8IIWrHgMeLY= -github.com/shoenig/go-m1cpu v0.1.5 h1:LF57Z/Fpb/WdGLjt2HZilNnmZOxg/q2bSKTQhgbrLrQ= -github.com/shoenig/go-m1cpu v0.1.5/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= -github.com/shoenig/test v0.6.3 h1:GVXWJFk9PiOjN0KoJ7VrJGH6uLPnqxR7/fe3HUPfE0c= -github.com/shoenig/test v0.6.3/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= @@ -773,8 +769,6 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY= @@ -789,8 +783,9 @@ github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sS github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -840,8 +835,6 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= -github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= @@ -1153,7 +1146,6 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1413,8 +1405,8 @@ google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11 google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc v1.57.1 h1:upNTNqv0ES+2ZOOqACwVtS3Il8M12/+Hz41RCPzAjQg= +google.golang.org/grpc v1.57.1/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From b34eafcab1f3012e42df4d7244f263df235db3f0 Mon Sep 17 00:00:00 2001 From: Yunus M Date: Fri, 27 Oct 2023 00:09:19 +0530 Subject: [PATCH 06/28] fix: ee/query-service/Dockerfile to reduce vulnerabilities (#3805) Co-authored-by: snyk-bot Co-authored-by: Srikanth Chekuri --- ee/query-service/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ee/query-service/Dockerfile b/ee/query-service/Dockerfile index 46b2186ec4..dad09b3cbd 100644 --- a/ee/query-service/Dockerfile +++ b/ee/query-service/Dockerfile @@ -1,5 +1,5 @@ # use a minimal alpine image -FROM alpine:3.17 +FROM alpine:3.18.3 # Add Maintainer Info LABEL maintainer="signoz" From fc49833c9fceda3f2d77c146121f1ff975cefc09 Mon Sep 17 00:00:00 2001 From: Rajat Dabade Date: Fri, 27 Oct 2023 21:09:23 +0530 Subject: [PATCH 07/28] [Feat]: Dynamic columns in tables (#3809) * feat: added dropdown in alert list table * refactor: done with combining actions * feat: done with label and dynamic table * feat: dynamic column in table * chore: show all label on hover * refactor: create to created timestamp - highlighted action * refactor: storing the column data in localstorage --- .../components/DropDown/DropDown.styles.scss | 7 ++ frontend/src/components/DropDown/DropDown.tsx | 29 +++++ .../ResizeTable/DynamicColumnTable.syles.scss | 17 +++ .../ResizeTable/DynamicColumnTable.tsx | 116 ++++++++++++++++++ .../ResizeTable/TableComponent/Date.tsx | 23 ++++ .../src/components/ResizeTable/contants.ts | 11 ++ frontend/src/components/ResizeTable/types.ts | 28 ++++- frontend/src/components/ResizeTable/unit.ts | 57 +++++++++ .../TableRenderer/LabelColumn.styles.scss | 9 ++ .../components/TableRenderer/LabelColumn.tsx | 67 ++++++++++ .../TableRenderer/TableRenderer.types.ts | 5 + .../src/components/TableRenderer/utils.ts | 22 ++++ .../container/ListAlertRules/ListAlert.tsx | 110 +++++++++++++---- .../src/container/ListAlertRules/styles.ts | 8 +- .../SearchFilter/__tests__/utils.test.ts | 6 + .../ListOfDashboard/TableComponents/Date.tsx | 17 --- .../TableComponents/DeleteButton.tsx | 16 ++- .../src/container/ListOfDashboard/index.tsx | 97 ++++++++++----- frontend/src/types/api/alerts/get.ts | 4 + frontend/src/types/api/dashboard/getAll.ts | 2 + 20 files changed, 567 insertions(+), 84 deletions(-) create mode 100644 frontend/src/components/DropDown/DropDown.styles.scss create mode 100644 frontend/src/components/DropDown/DropDown.tsx create mode 100644 frontend/src/components/ResizeTable/DynamicColumnTable.syles.scss create mode 100644 frontend/src/components/ResizeTable/DynamicColumnTable.tsx create mode 100644 frontend/src/components/ResizeTable/TableComponent/Date.tsx create mode 100644 frontend/src/components/ResizeTable/contants.ts create mode 100644 frontend/src/components/ResizeTable/unit.ts create mode 100644 frontend/src/components/TableRenderer/LabelColumn.styles.scss create mode 100644 frontend/src/components/TableRenderer/LabelColumn.tsx create mode 100644 frontend/src/components/TableRenderer/TableRenderer.types.ts delete mode 100644 frontend/src/container/ListOfDashboard/TableComponents/Date.tsx diff --git a/frontend/src/components/DropDown/DropDown.styles.scss b/frontend/src/components/DropDown/DropDown.styles.scss new file mode 100644 index 0000000000..6042acd07c --- /dev/null +++ b/frontend/src/components/DropDown/DropDown.styles.scss @@ -0,0 +1,7 @@ +.Dropdown-button { + color: #fff; +} + +.Dropdown-icon { + font-size: 1.2rem; +} \ No newline at end of file diff --git a/frontend/src/components/DropDown/DropDown.tsx b/frontend/src/components/DropDown/DropDown.tsx new file mode 100644 index 0000000000..2f45a6a1a7 --- /dev/null +++ b/frontend/src/components/DropDown/DropDown.tsx @@ -0,0 +1,29 @@ +import './DropDown.styles.scss'; + +import { EllipsisOutlined } from '@ant-design/icons'; +import { Button, Dropdown, MenuProps, Space } from 'antd'; + +function DropDown({ element }: { element: JSX.Element[] }): JSX.Element { + const items: MenuProps['items'] = element.map( + (e: JSX.Element, index: number) => ({ + label: e, + key: index, + }), + ); + + return ( + + + + ); +} + +export default DropDown; diff --git a/frontend/src/components/ResizeTable/DynamicColumnTable.syles.scss b/frontend/src/components/ResizeTable/DynamicColumnTable.syles.scss new file mode 100644 index 0000000000..30bccd87e3 --- /dev/null +++ b/frontend/src/components/ResizeTable/DynamicColumnTable.syles.scss @@ -0,0 +1,17 @@ +.DynamicColumnTable { + display: flex; + flex-direction: column; + width: 100%; + + .dynamicColumnTable-button { + align-self: flex-end; + margin: 10px 0; + } +} + +.dynamicColumnsTable-items { + display: flex; + width: 10.625rem; + justify-content: space-between; + align-items: center; +} \ No newline at end of file diff --git a/frontend/src/components/ResizeTable/DynamicColumnTable.tsx b/frontend/src/components/ResizeTable/DynamicColumnTable.tsx new file mode 100644 index 0000000000..93e3673743 --- /dev/null +++ b/frontend/src/components/ResizeTable/DynamicColumnTable.tsx @@ -0,0 +1,116 @@ +/* eslint-disable react/jsx-props-no-spreading */ +import './DynamicColumnTable.syles.scss'; + +import { SettingOutlined } from '@ant-design/icons'; +import { Button, Dropdown, MenuProps, Switch } from 'antd'; +import { ColumnsType } from 'antd/lib/table'; +import { memo, useEffect, useState } from 'react'; +import { popupContainer } from 'utils/selectPopupContainer'; + +import ResizeTable from './ResizeTable'; +import { DynamicColumnTableProps } from './types'; +import { getVisibleColumns, setVisibleColumns } from './unit'; + +function DynamicColumnTable({ + tablesource, + columns, + dynamicColumns, + onDragColumn, + ...restProps +}: DynamicColumnTableProps): JSX.Element { + const [columnsData, setColumnsData] = useState( + columns, + ); + + useEffect(() => { + const visibleColumns = getVisibleColumns({ + tablesource, + columnsData: columns, + dynamicColumns, + }); + setColumnsData((prevColumns) => + prevColumns + ? [ + ...prevColumns.slice(0, prevColumns.length - 1), + ...visibleColumns, + prevColumns[prevColumns.length - 1], + ] + : undefined, + ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const onToggleHandler = (index: number) => ( + checked: boolean, + event: React.MouseEvent, + ): void => { + event.stopPropagation(); + setVisibleColumns({ + tablesource, + dynamicColumns, + index, + checked, + }); + setColumnsData((prevColumns) => { + if (checked && dynamicColumns) { + return prevColumns + ? [ + ...prevColumns.slice(0, prevColumns.length - 1), + dynamicColumns[index], + prevColumns[prevColumns.length - 1], + ] + : undefined; + } + return prevColumns && dynamicColumns + ? prevColumns.filter( + (column) => dynamicColumns[index].title !== column.title, + ) + : undefined; + }); + }; + + const items: MenuProps['items'] = + dynamicColumns?.map((column, index) => ({ + label: ( +
+
{column.title?.toString()}
+ c.key === column.key) !== -1} + onChange={onToggleHandler(index)} + /> +
+ ), + key: index, + type: 'checkbox', + })) || []; + + return ( +
+ {dynamicColumns && ( + +
+ ); +} + +DynamicColumnTable.defaultProps = { + onDragColumn: undefined, +}; + +export default memo(DynamicColumnTable); diff --git a/frontend/src/components/ResizeTable/TableComponent/Date.tsx b/frontend/src/components/ResizeTable/TableComponent/Date.tsx new file mode 100644 index 0000000000..d14c2b6b53 --- /dev/null +++ b/frontend/src/components/ResizeTable/TableComponent/Date.tsx @@ -0,0 +1,23 @@ +import { Typography } from 'antd'; +import convertDateToAmAndPm from 'lib/convertDateToAmAndPm'; +import getFormattedDate from 'lib/getFormatedDate'; + +function DateComponent( + CreatedOrUpdateTime: string | number | Date, +): JSX.Element { + const time = new Date(CreatedOrUpdateTime); + + const date = getFormattedDate(time); + + const timeString = `${date} ${convertDateToAmAndPm(time)}`; + + if (CreatedOrUpdateTime === null) { + return - ; + } + + return ( + {timeString} + ); +} + +export default DateComponent; diff --git a/frontend/src/components/ResizeTable/contants.ts b/frontend/src/components/ResizeTable/contants.ts new file mode 100644 index 0000000000..0944f9aa12 --- /dev/null +++ b/frontend/src/components/ResizeTable/contants.ts @@ -0,0 +1,11 @@ +export const TableDataSource = { + Alert: 'alert', + Dashboard: 'dashboard', +} as const; + +export const DynamicColumnsKey = { + CreatedAt: 'createdAt', + CreatedBy: 'createdBy', + UpdatedAt: 'updatedAt', + UpdatedBy: 'updatedBy', +}; diff --git a/frontend/src/components/ResizeTable/types.ts b/frontend/src/components/ResizeTable/types.ts index 6390a25ba6..c212bfa505 100644 --- a/frontend/src/components/ResizeTable/types.ts +++ b/frontend/src/components/ResizeTable/types.ts @@ -1,6 +1,32 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { TableProps } from 'antd'; +import { ColumnsType } from 'antd/es/table'; +import { ColumnGroupType, ColumnType } from 'antd/lib/table'; + +import { TableDataSource } from './contants'; -// eslint-disable-next-line @typescript-eslint/no-explicit-any export interface ResizeTableProps extends TableProps { onDragColumn?: (fromIndex: number, toIndex: number) => void; } +export interface DynamicColumnTableProps extends TableProps { + tablesource: typeof TableDataSource[keyof typeof TableDataSource]; + dynamicColumns: TableProps['columns']; + onDragColumn?: (fromIndex: number, toIndex: number) => void; +} + +export type GetVisibleColumnsFunction = ( + props: GetVisibleColumnProps, +) => (ColumnGroupType | ColumnType)[]; + +export type GetVisibleColumnProps = { + tablesource: typeof TableDataSource[keyof typeof TableDataSource]; + dynamicColumns?: ColumnsType; + columnsData?: ColumnsType; +}; + +export type SetVisibleColumnsProps = { + checked: boolean; + index: number; + tablesource: typeof TableDataSource[keyof typeof TableDataSource]; + dynamicColumns?: ColumnsType; +}; diff --git a/frontend/src/components/ResizeTable/unit.ts b/frontend/src/components/ResizeTable/unit.ts new file mode 100644 index 0000000000..0bd4b3bb1f --- /dev/null +++ b/frontend/src/components/ResizeTable/unit.ts @@ -0,0 +1,57 @@ +import { DynamicColumnsKey } from './contants'; +import { + GetVisibleColumnProps, + GetVisibleColumnsFunction, + SetVisibleColumnsProps, +} from './types'; + +export const getVisibleColumns: GetVisibleColumnsFunction = ({ + tablesource, + dynamicColumns, + columnsData, +}: GetVisibleColumnProps) => { + let columnVisibilityData: { [key: string]: boolean }; + try { + const storedData = localStorage.getItem(tablesource); + if (typeof storedData === 'string' && dynamicColumns) { + columnVisibilityData = JSON.parse(storedData); + return dynamicColumns.filter((column) => { + if (column.key && !columnsData?.find((c) => c.key === column.key)) { + return columnVisibilityData[column.key]; + } + return false; + }); + } + + const initialColumnVisibility: Record = {}; + Object.values(DynamicColumnsKey).forEach((key) => { + initialColumnVisibility[key] = false; + }); + + localStorage.setItem(tablesource, JSON.stringify(initialColumnVisibility)); + } catch (error) { + console.error(error); + } + return []; +}; + +export const setVisibleColumns = ({ + checked, + index, + tablesource, + dynamicColumns, +}: SetVisibleColumnsProps): void => { + try { + const storedData = localStorage.getItem(tablesource); + if (typeof storedData === 'string' && dynamicColumns) { + const columnVisibilityData = JSON.parse(storedData); + const { key } = dynamicColumns[index]; + if (key) { + columnVisibilityData[key] = checked; + } + localStorage.setItem(tablesource, JSON.stringify(columnVisibilityData)); + } + } catch (error) { + console.error(error); + } +}; diff --git a/frontend/src/components/TableRenderer/LabelColumn.styles.scss b/frontend/src/components/TableRenderer/LabelColumn.styles.scss new file mode 100644 index 0000000000..617dad5e7b --- /dev/null +++ b/frontend/src/components/TableRenderer/LabelColumn.styles.scss @@ -0,0 +1,9 @@ +.LabelColumn { + .LabelColumn-label-tag { + white-space: normal; + } + +} +.labelColumn-popover { + margin: 0.5rem 0; +} \ No newline at end of file diff --git a/frontend/src/components/TableRenderer/LabelColumn.tsx b/frontend/src/components/TableRenderer/LabelColumn.tsx new file mode 100644 index 0000000000..05bc4eb072 --- /dev/null +++ b/frontend/src/components/TableRenderer/LabelColumn.tsx @@ -0,0 +1,67 @@ +import './LabelColumn.styles.scss'; + +import { Popover, Tag, Tooltip } from 'antd'; +import { popupContainer } from 'utils/selectPopupContainer'; + +import { LabelColumnProps } from './TableRenderer.types'; +import { getLabelRenderingValue } from './utils'; + +function LabelColumn({ labels, value, color }: LabelColumnProps): JSX.Element { + const newLabels = labels.length > 3 ? labels.slice(0, 3) : labels; + const remainingLabels = labels.length > 3 ? labels.slice(3) : []; + + return ( +
+ {newLabels.map( + (label: string): JSX.Element => { + const tooltipTitle = + value && value[label] ? `${label}: ${value[label]}` : label; + return ( + + + {getLabelRenderingValue(label, value && value[label])} + + + ); + }, + )} + {remainingLabels.length > 0 && ( + + {labels.map( + (label: string): JSX.Element => { + const tooltipTitle = + value && value[label] ? `${label}: ${value[label]}` : label; + return ( +
+ + + {getLabelRenderingValue(label, value && value[label])} + + +
+ ); + }, + )} +
+ } + trigger="hover" + > + + +{remainingLabels.length} + + + )} + + ); +} + +LabelColumn.defaultProps = { + value: {}, +}; + +export default LabelColumn; diff --git a/frontend/src/components/TableRenderer/TableRenderer.types.ts b/frontend/src/components/TableRenderer/TableRenderer.types.ts new file mode 100644 index 0000000000..52aa40dd3f --- /dev/null +++ b/frontend/src/components/TableRenderer/TableRenderer.types.ts @@ -0,0 +1,5 @@ +export type LabelColumnProps = { + labels: string[]; + color?: string; + value?: { [key: string]: string }; +}; diff --git a/frontend/src/components/TableRenderer/utils.ts b/frontend/src/components/TableRenderer/utils.ts index 1e3ccc3cd2..ebceffe436 100644 --- a/frontend/src/components/TableRenderer/utils.ts +++ b/frontend/src/components/TableRenderer/utils.ts @@ -16,6 +16,28 @@ export const generatorResizeTableColumns = ({ }; }); +export const getLabelRenderingValue = ( + label: string, + value?: string, +): string => { + const maxLength = 20; + + if (label.length > maxLength) { + return `${label.slice(0, maxLength)}...`; + } + + if (value) { + const remainingSpace = maxLength - label.length; + let newValue = value; + if (value.length > remainingSpace) { + newValue = `${value.slice(0, remainingSpace)}...`; + } + return `${label}: ${newValue}`; + } + + return label; +}; + interface GeneratorResizeTableColumnsProp { baseColumnOptions: ColumnsType; dynamicColumnOption: { key: string; columnOption: ColumnType }[]; diff --git a/frontend/src/container/ListAlertRules/ListAlert.tsx b/frontend/src/container/ListAlertRules/ListAlert.tsx index 7dd1052a67..0429174de5 100644 --- a/frontend/src/container/ListAlertRules/ListAlert.tsx +++ b/frontend/src/container/ListAlertRules/ListAlert.tsx @@ -3,7 +3,14 @@ import { PlusOutlined } from '@ant-design/icons'; import { Typography } from 'antd'; import { ColumnsType } from 'antd/lib/table'; import saveAlertApi from 'api/alerts/save'; -import { ResizeTable } from 'components/ResizeTable'; +import DropDown from 'components/DropDown/DropDown'; +import { + DynamicColumnsKey, + TableDataSource, +} from 'components/ResizeTable/contants'; +import DynamicColumnTable from 'components/ResizeTable/DynamicColumnTable'; +import DateComponent from 'components/ResizeTable/TableComponent/Date'; +import LabelColumn from 'components/TableRenderer/LabelColumn'; import TextToolTip from 'components/TextToolTip'; import { QueryParams } from 'constants/query'; import ROUTES from 'constants/routes'; @@ -22,7 +29,7 @@ import { GettableAlert } from 'types/api/alerts/get'; import AppReducer from 'types/reducer/app'; import DeleteAlert from './DeleteAlert'; -import { Button, ButtonContainer, ColumnButton, StyledTag } from './styles'; +import { Button, ButtonContainer, ColumnButton } from './styles'; import Status from './TableComponents/Status'; import ToggleAlertState from './ToggleAlertState'; @@ -121,6 +128,53 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element { } }; + const dynamicColumns: ColumnsType = [ + { + title: 'Created At', + dataIndex: 'createAt', + width: 80, + key: DynamicColumnsKey.CreatedAt, + align: 'center', + sorter: (a: GettableAlert, b: GettableAlert): number => { + const prev = new Date(a.createAt).getTime(); + const next = new Date(b.createAt).getTime(); + + return prev - next; + }, + render: DateComponent, + }, + { + title: 'Created By', + dataIndex: 'createBy', + width: 80, + key: DynamicColumnsKey.CreatedBy, + align: 'center', + render: (value): JSX.Element =>
{value}
, + }, + { + title: 'Updated At', + dataIndex: 'updateAt', + width: 80, + key: DynamicColumnsKey.UpdatedAt, + align: 'center', + sorter: (a: GettableAlert, b: GettableAlert): number => { + const prev = new Date(a.updateAt).getTime(); + const next = new Date(b.updateAt).getTime(); + + return prev - next; + }, + render: DateComponent, + }, + { + title: 'Updated By', + dataIndex: 'updateBy', + width: 80, + key: DynamicColumnsKey.UpdatedBy, + align: 'center', + render: (value): JSX.Element =>
{value}
, + }, + ]; + const columns: ColumnsType = [ { title: 'Status', @@ -178,13 +232,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element { } return ( - <> - {withOutSeverityKeys.map((e) => ( - - {e}: {value[e]} - - ))} - + ); }, }, @@ -195,20 +243,30 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element { title: 'Action', dataIndex: 'id', key: 'action', - width: 120, + width: 10, render: (id: GettableAlert['id'], record): JSX.Element => ( - <> - - - - Edit - - - Clone - - - - + , + + Edit + , + + Clone + , + , + ]} + /> ), }); } @@ -229,7 +287,13 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element { )} - + ); } diff --git a/frontend/src/container/ListAlertRules/styles.ts b/frontend/src/container/ListAlertRules/styles.ts index 67748b21c0..f2d0937950 100644 --- a/frontend/src/container/ListAlertRules/styles.ts +++ b/frontend/src/container/ListAlertRules/styles.ts @@ -1,4 +1,4 @@ -import { Button as ButtonComponent, Tag } from 'antd'; +import { Button as ButtonComponent } from 'antd'; import styled from 'styled-components'; export const ButtonContainer = styled.div` @@ -23,9 +23,3 @@ export const ColumnButton = styled(ButtonComponent)` margin-right: 1.5em; } `; - -export const StyledTag = styled(Tag)` - &&& { - white-space: normal; - } -`; diff --git a/frontend/src/container/ListOfDashboard/SearchFilter/__tests__/utils.test.ts b/frontend/src/container/ListOfDashboard/SearchFilter/__tests__/utils.test.ts index 369a0dffa3..b215d205a5 100644 --- a/frontend/src/container/ListOfDashboard/SearchFilter/__tests__/utils.test.ts +++ b/frontend/src/container/ListOfDashboard/SearchFilter/__tests__/utils.test.ts @@ -10,6 +10,8 @@ describe('executeSearchQueries', () => { uuid: uuid(), created_at: '', updated_at: '', + created_by: '', + updated_by: '', data: { title: 'first dashboard', variables: {}, @@ -20,6 +22,8 @@ describe('executeSearchQueries', () => { uuid: uuid(), created_at: '', updated_at: '', + created_by: '', + updated_by: '', data: { title: 'second dashboard', variables: {}, @@ -30,6 +34,8 @@ describe('executeSearchQueries', () => { uuid: uuid(), created_at: '', updated_at: '', + created_by: '', + updated_by: '', data: { title: 'third dashboard (with special characters +?\\)', variables: {}, diff --git a/frontend/src/container/ListOfDashboard/TableComponents/Date.tsx b/frontend/src/container/ListOfDashboard/TableComponents/Date.tsx deleted file mode 100644 index c96ac1ebf1..0000000000 --- a/frontend/src/container/ListOfDashboard/TableComponents/Date.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { Typography } from 'antd'; -import convertDateToAmAndPm from 'lib/convertDateToAmAndPm'; -import getFormattedDate from 'lib/getFormatedDate'; - -import { Data } from '..'; - -function DateComponent(lastUpdatedTime: Data['lastUpdatedTime']): JSX.Element { - const time = new Date(lastUpdatedTime); - - const date = getFormattedDate(time); - - const timeString = `${date} ${convertDateToAmAndPm(time)}`; - - return {timeString}; -} - -export default DateComponent; diff --git a/frontend/src/container/ListOfDashboard/TableComponents/DeleteButton.tsx b/frontend/src/container/ListOfDashboard/TableComponents/DeleteButton.tsx index 03c0ac9912..c68b0c2617 100644 --- a/frontend/src/container/ListOfDashboard/TableComponents/DeleteButton.tsx +++ b/frontend/src/container/ListOfDashboard/TableComponents/DeleteButton.tsx @@ -45,18 +45,30 @@ function DeleteButton({ id }: Data): JSX.Element { // This is to avoid the type collision function Wrapper(props: Data): JSX.Element { - const { createdBy, description, id, key, lastUpdatedTime, name, tags } = props; + const { + createdAt, + description, + id, + key, + lastUpdatedTime, + name, + tags, + createdBy, + lastUpdatedBy, + } = props; return ( ); diff --git a/frontend/src/container/ListOfDashboard/index.tsx b/frontend/src/container/ListOfDashboard/index.tsx index 87f47e54af..bb47b15579 100644 --- a/frontend/src/container/ListOfDashboard/index.tsx +++ b/frontend/src/container/ListOfDashboard/index.tsx @@ -10,7 +10,12 @@ import { import { ItemType } from 'antd/es/menu/hooks/useItems'; import createDashboard from 'api/dashboard/create'; import { AxiosError } from 'axios'; -import { ResizeTable } from 'components/ResizeTable'; +import { + DynamicColumnsKey, + TableDataSource, +} from 'components/ResizeTable/contants'; +import DynamicColumnTable from 'components/ResizeTable/DynamicColumnTable'; +import LabelColumn from 'components/TableRenderer/LabelColumn'; import TextToolTip from 'components/TextToolTip'; import ROUTES from 'constants/routes'; import SearchFilter from 'container/ListOfDashboard/SearchFilter'; @@ -26,13 +31,11 @@ import { Dashboard } from 'types/api/dashboard/getAll'; import AppReducer from 'types/reducer/app'; import { popupContainer } from 'utils/selectPopupContainer'; +import DateComponent from '../../components/ResizeTable/TableComponent/Date'; import ImportJSON from './ImportJSON'; import { ButtonContainer, NewDashboardButton, TableContainer } from './styles'; -import Createdby from './TableComponents/CreatedBy'; -import DateComponent from './TableComponents/Date'; import DeleteButton from './TableComponents/DeleteButton'; import Name from './TableComponents/Name'; -import Tags from './TableComponents/Tags'; function ListOfAllDashboard(): JSX.Element { const { @@ -71,48 +74,68 @@ function ListOfAllDashboard(): JSX.Element { errorMessage: '', }); + const dynamicColumns: TableColumnProps[] = [ + { + title: 'Created At', + dataIndex: 'createdAt', + width: 30, + key: DynamicColumnsKey.CreatedAt, + sorter: (a: Data, b: Data): number => { + console.log({ a }); + const prev = new Date(a.createdAt).getTime(); + const next = new Date(b.createdAt).getTime(); + + return prev - next; + }, + render: DateComponent, + }, + { + title: 'Created By', + dataIndex: 'createdBy', + width: 30, + key: DynamicColumnsKey.CreatedBy, + render: (value): JSX.Element =>
{value}
, + }, + { + title: 'Last Updated Time', + width: 30, + dataIndex: 'lastUpdatedTime', + key: DynamicColumnsKey.UpdatedAt, + sorter: (a: Data, b: Data): number => { + const prev = new Date(a.lastUpdatedTime).getTime(); + const next = new Date(b.lastUpdatedTime).getTime(); + + return prev - next; + }, + render: DateComponent, + }, + { + title: 'Last Updated By', + dataIndex: 'lastUpdatedBy', + width: 30, + key: DynamicColumnsKey.UpdatedBy, + render: (value): JSX.Element =>
{value}
, + }, + ]; + const columns = useMemo(() => { const tableColumns: TableColumnProps[] = [ { title: 'Name', dataIndex: 'name', - width: 100, + width: 40, render: Name, }, { title: 'Description', - width: 100, + width: 50, dataIndex: 'description', }, { title: 'Tags (can be multiple)', dataIndex: 'tags', - width: 80, - render: Tags, - }, - { - title: 'Created At', - dataIndex: 'createdBy', - width: 80, - sorter: (a: Data, b: Data): number => { - const prev = new Date(a.createdBy).getTime(); - const next = new Date(b.createdBy).getTime(); - - return prev - next; - }, - render: Createdby, - }, - { - title: 'Last Updated Time', - width: 90, - dataIndex: 'lastUpdatedTime', - sorter: (a: Data, b: Data): number => { - const prev = new Date(a.lastUpdatedTime).getTime(); - const next = new Date(b.lastUpdatedTime).getTime(); - - return prev - next; - }, - render: DateComponent, + width: 50, + render: (value): JSX.Element => , }, ]; @@ -130,13 +153,15 @@ function ListOfAllDashboard(): JSX.Element { const data: Data[] = filteredDashboards?.map((e) => ({ - createdBy: e.created_at, + createdAt: e.created_at, description: e.data.description || '', id: e.uuid, lastUpdatedTime: e.updated_at, name: e.data.title, tags: e.data.tags || [], key: e.uuid, + createdBy: e.created_by, + lastUpdatedBy: e.updated_by, refetchDashboardList, })) || []; @@ -290,7 +315,9 @@ function ListOfAllDashboard(): JSX.Element { uploadedGrafana={uploadedGrafana} onModalHandler={(): void => onModalHandler(false)} /> - Date: Sun, 29 Oct 2023 16:58:31 +0530 Subject: [PATCH 08/28] Fix: Query Service: get trace parser working in log parsing pipelines (#3820) * chore: add test for ensuring pipeline previews work for trace parser processors * chore: updates to trace parser validation in postable pipelines * chore: extract auth.randomHex into utils.RandomHex for reuse * chore: get trace parser preview test passing * chore: start with JSON serialized trace parser in test to cover deserialization * chore: address PR feedback --- .../app/logparsingpipeline/model.go | 28 +++--- .../logparsingpipeline/postablePipeline.go | 23 ++++- .../postablePipeline_test.go | 25 +++++ .../app/logparsingpipeline/preview_test.go | 95 +++++++++++++++++++ pkg/query-service/auth/auth.go | 4 +- pkg/query-service/auth/utils.go | 11 --- pkg/query-service/utils/random.go | 14 +++ 7 files changed, 169 insertions(+), 31 deletions(-) create mode 100644 pkg/query-service/utils/random.go diff --git a/pkg/query-service/app/logparsingpipeline/model.go b/pkg/query-service/app/logparsingpipeline/model.go index 21493115bd..eb0a9c66d1 100644 --- a/pkg/query-service/app/logparsingpipeline/model.go +++ b/pkg/query-service/app/logparsingpipeline/model.go @@ -48,20 +48,20 @@ type PipelineOperator struct { Name string `json:"name,omitempty" yaml:"-"` // optional keys depending on the type - ParseTo string `json:"parse_to,omitempty" yaml:"parse_to,omitempty"` - Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"` - Regex string `json:"regex,omitempty" yaml:"regex,omitempty"` - ParseFrom string `json:"parse_from,omitempty" yaml:"parse_from,omitempty"` - Timestamp *TimestampParser `json:"timestamp,omitempty" yaml:"timestamp,omitempty"` - TraceParser *TraceParser `json:"trace_parser,omitempty" yaml:"trace_parser,omitempty"` - Field string `json:"field,omitempty" yaml:"field,omitempty"` - Value string `json:"value,omitempty" yaml:"value,omitempty"` - From string `json:"from,omitempty" yaml:"from,omitempty"` - To string `json:"to,omitempty" yaml:"to,omitempty"` - Expr string `json:"expr,omitempty" yaml:"expr,omitempty"` - Routes *[]Route `json:"routes,omitempty" yaml:"routes,omitempty"` - Fields []string `json:"fields,omitempty" yaml:"fields,omitempty"` - Default string `json:"default,omitempty" yaml:"default,omitempty"` + ParseTo string `json:"parse_to,omitempty" yaml:"parse_to,omitempty"` + Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"` + Regex string `json:"regex,omitempty" yaml:"regex,omitempty"` + ParseFrom string `json:"parse_from,omitempty" yaml:"parse_from,omitempty"` + Timestamp *TimestampParser `json:"timestamp,omitempty" yaml:"timestamp,omitempty"` + *TraceParser `yaml:",inline,omitempty"` + Field string `json:"field,omitempty" yaml:"field,omitempty"` + Value string `json:"value,omitempty" yaml:"value,omitempty"` + From string `json:"from,omitempty" yaml:"from,omitempty"` + To string `json:"to,omitempty" yaml:"to,omitempty"` + Expr string `json:"expr,omitempty" yaml:"expr,omitempty"` + Routes *[]Route `json:"routes,omitempty" yaml:"routes,omitempty"` + Fields []string `json:"fields,omitempty" yaml:"fields,omitempty"` + Default string `json:"default,omitempty" yaml:"default,omitempty"` } type TimestampParser struct { diff --git a/pkg/query-service/app/logparsingpipeline/postablePipeline.go b/pkg/query-service/app/logparsingpipeline/postablePipeline.go index d11fb5b952..472303b527 100644 --- a/pkg/query-service/app/logparsingpipeline/postablePipeline.go +++ b/pkg/query-service/app/logparsingpipeline/postablePipeline.go @@ -137,20 +137,35 @@ func isValidOperator(op PipelineOperator) error { if op.Field == "" { return fmt.Errorf(fmt.Sprintf("field of %s remove operator cannot be empty", op.ID)) } - case "traceParser": + case "trace_parser": if op.TraceParser == nil { return fmt.Errorf(fmt.Sprintf("field of %s remove operator cannot be empty", op.ID)) } - if op.TraceParser.SpanId.ParseFrom == "" && op.TraceParser.TraceId.ParseFrom == "" && op.TraceParser.TraceFlags.ParseFrom == "" { - return fmt.Errorf(fmt.Sprintf("one of trace_id,span_id,parse_from of %s traceParser operator must be present", op.ID)) + hasTraceIdParseFrom := (op.TraceParser.TraceId != nil && op.TraceParser.TraceId.ParseFrom != "") + hasSpanIdParseFrom := (op.TraceParser.SpanId != nil && op.TraceParser.SpanId.ParseFrom != "") + hasTraceFlagsParseFrom := (op.TraceParser.TraceFlags != nil && op.TraceParser.TraceFlags.ParseFrom != "") + + if !(hasTraceIdParseFrom || hasSpanIdParseFrom || hasTraceFlagsParseFrom) { + return fmt.Errorf(fmt.Sprintf("one of trace_id, span_id, trace_flags of %s trace_parser operator must be present", op.ID)) } + + if hasTraceIdParseFrom && !isValidOtelValue(op.TraceParser.TraceId.ParseFrom) { + return fmt.Errorf("trace id can't be parsed from %s", op.TraceParser.TraceId.ParseFrom) + } + if hasSpanIdParseFrom && !isValidOtelValue(op.TraceParser.SpanId.ParseFrom) { + return fmt.Errorf("span id can't be parsed from %s", op.TraceParser.SpanId.ParseFrom) + } + if hasTraceFlagsParseFrom && !isValidOtelValue(op.TraceParser.TraceFlags.ParseFrom) { + return fmt.Errorf("trace flags can't be parsed from %s", op.TraceParser.TraceFlags.ParseFrom) + } + case "retain": if len(op.Fields) == 0 { return fmt.Errorf(fmt.Sprintf("fields of %s retain operator cannot be empty", op.ID)) } default: - return fmt.Errorf(fmt.Sprintf("operator type %s not supported for %s, use one of (grok_parser, regex_parser, copy, move, add, remove, traceParser, retain)", op.Type, op.ID)) + return fmt.Errorf(fmt.Sprintf("operator type %s not supported for %s, use one of (grok_parser, regex_parser, copy, move, add, remove, trace_parser, retain)", op.Type, op.ID)) } if !isValidOtelValue(op.ParseFrom) || diff --git a/pkg/query-service/app/logparsingpipeline/postablePipeline_test.go b/pkg/query-service/app/logparsingpipeline/postablePipeline_test.go index dd2c61e748..d2f9ec9b09 100644 --- a/pkg/query-service/app/logparsingpipeline/postablePipeline_test.go +++ b/pkg/query-service/app/logparsingpipeline/postablePipeline_test.go @@ -250,6 +250,31 @@ var operatorTest = []struct { ParseTo: "attributes", }, IsValid: false, + }, { + Name: "Trace Parser - invalid - no trace_parser spec", + Operator: PipelineOperator{ + ID: "trace", + Type: "trace_parser", + }, + IsValid: false, + }, { + Name: "Trace Parser - invalid - no ParseFrom specified", + Operator: PipelineOperator{ + ID: "trace", + Type: "trace_parser", + TraceParser: &TraceParser{}, + }, + IsValid: false, + }, { + Name: "Trace Parser - invalid - bad parsefrom attribute", + Operator: PipelineOperator{ + ID: "trace", + Type: "trace_parser", + TraceParser: &TraceParser{ + TraceId: &ParseFrom{ParseFrom: "trace_id"}, + }, + }, + IsValid: false, }, } diff --git a/pkg/query-service/app/logparsingpipeline/preview_test.go b/pkg/query-service/app/logparsingpipeline/preview_test.go index b6cfb855f3..67f77a8e40 100644 --- a/pkg/query-service/app/logparsingpipeline/preview_test.go +++ b/pkg/query-service/app/logparsingpipeline/preview_test.go @@ -2,6 +2,8 @@ package logparsingpipeline import ( "context" + "encoding/json" + "strconv" "testing" "time" @@ -10,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "go.signoz.io/signoz/pkg/query-service/model" v3 "go.signoz.io/signoz/pkg/query-service/model/v3" + "go.signoz.io/signoz/pkg/query-service/utils" ) func TestPipelinePreview(t *testing.T) { @@ -202,6 +205,98 @@ func TestGrokParsingPreview(t *testing.T) { require.Equal("route/server.go:71", processed.Attributes_string["location"]) } +func TestTraceParsingPreview(t *testing.T) { + require := require.New(t) + + testPipelines := []Pipeline{ + { + OrderId: 1, + Name: "pipeline1", + Alias: "pipeline1", + Enabled: true, + Filter: &v3.FilterSet{ + Operator: "AND", + Items: []v3.FilterItem{ + { + Key: v3.AttributeKey{ + Key: "method", + DataType: v3.AttributeKeyDataTypeString, + Type: v3.AttributeKeyTypeTag, + }, + Operator: "=", + Value: "GET", + }, + }, + }, + Config: []PipelineOperator{}, + }, + } + + // Start with JSON serialized trace parser to validate deserialization too + var traceParserOp PipelineOperator + err := json.Unmarshal([]byte(` + { + "orderId": 1, + "enabled": true, + "type": "trace_parser", + "name": "Test trace parser", + "id": "test-trace-parser", + "trace_id": { + "parse_from": "attributes.test_trace_id" + }, + "span_id": { + "parse_from": "attributes.test_span_id" + }, + "trace_flags": { + "parse_from": "attributes.test_trace_flags" + } + } + `), &traceParserOp) + require.Nil(err) + testPipelines[0].Config = append(testPipelines[0].Config, traceParserOp) + + testTraceId, err := utils.RandomHex(16) + require.Nil(err) + + testSpanId, err := utils.RandomHex(8) + require.Nil(err) + + testTraceFlags, err := utils.RandomHex(1) + require.Nil(err) + + testLog := model.SignozLog{ + Timestamp: uint64(time.Now().UnixNano()), + Body: "test log", + Attributes_string: map[string]string{ + "method": "GET", + "test_trace_id": testTraceId, + "test_span_id": testSpanId, + "test_trace_flags": testTraceFlags, + }, + SpanID: "", + TraceID: "", + TraceFlags: 0, + } + + result, err := SimulatePipelinesProcessing( + context.Background(), + testPipelines, + []model.SignozLog{ + testLog, + }, + ) + require.Nil(err) + require.Equal(1, len(result)) + processed := result[0] + + require.Equal(testTraceId, processed.TraceID) + require.Equal(testSpanId, processed.SpanID) + + expectedTraceFlags, err := strconv.ParseUint(testTraceFlags, 16, 16) + require.Nil(err) + require.Equal(uint32(expectedTraceFlags), processed.TraceFlags) +} + func makeTestLogEntry( body string, attributes map[string]string, diff --git a/pkg/query-service/auth/auth.go b/pkg/query-service/auth/auth.go index 7f78fa3660..6190e87826 100644 --- a/pkg/query-service/auth/auth.go +++ b/pkg/query-service/auth/auth.go @@ -31,7 +31,7 @@ var ( func Invite(ctx context.Context, req *model.InviteRequest) (*model.InviteResponse, error) { zap.S().Debugf("Got an invite request for email: %s\n", req.Email) - token, err := randomHex(opaqueTokenSize) + token, err := utils.RandomHex(opaqueTokenSize) if err != nil { return nil, errors.Wrap(err, "failed to generate invite token") } @@ -140,7 +140,7 @@ func ValidateInvite(ctx context.Context, req *RegisterRequest) (*model.Invitatio } func CreateResetPasswordToken(ctx context.Context, userId string) (*model.ResetPasswordEntry, error) { - token, err := randomHex(opaqueTokenSize) + token, err := utils.RandomHex(opaqueTokenSize) if err != nil { return nil, errors.Wrap(err, "failed to generate reset password token") } diff --git a/pkg/query-service/auth/utils.go b/pkg/query-service/auth/utils.go index d76beca5c4..a6a639c710 100644 --- a/pkg/query-service/auth/utils.go +++ b/pkg/query-service/auth/utils.go @@ -1,9 +1,6 @@ package auth import ( - "crypto/rand" - "encoding/hex" - "github.com/pkg/errors" "go.signoz.io/signoz/pkg/query-service/constants" "go.signoz.io/signoz/pkg/query-service/model" @@ -18,14 +15,6 @@ var ( ErrorAskAdmin = errors.New("An invitation is needed to create an account. Please ask your admin (the person who has first installed SIgNoz) to send an invite.") ) -func randomHex(sz int) (string, error) { - bytes := make([]byte, sz) - if _, err := rand.Read(bytes); err != nil { - return "", err - } - return hex.EncodeToString(bytes), nil -} - func isValidRole(role string) bool { switch role { case constants.AdminGroup, constants.EditorGroup, constants.ViewerGroup: diff --git a/pkg/query-service/utils/random.go b/pkg/query-service/utils/random.go new file mode 100644 index 0000000000..10a3680e7a --- /dev/null +++ b/pkg/query-service/utils/random.go @@ -0,0 +1,14 @@ +package utils + +import ( + "crypto/rand" + "encoding/hex" +) + +func RandomHex(sz int) (string, error) { + bytes := make([]byte, sz) + if _, err := rand.Read(bytes); err != nil { + return "", err + } + return hex.EncodeToString(bytes), nil +} From 45ead71359de8a715c582b88b19f2f874744af21 Mon Sep 17 00:00:00 2001 From: Raj Kamal Singh <1133322+rkssisodiya@users.noreply.github.com> Date: Sun, 29 Oct 2023 17:46:08 +0530 Subject: [PATCH 09/28] Fix: get log pipelines trace parser working (#3822) * chore: add trace parser fields to log pipeline ProcessorData interface * chore: update trace parsing processor form field configs * chore: logs pipeline preview: better display of sample logs when too few logs in sample * fix: log pipelines: get tests passing: remove name prop passed to antd input --- .../FormFields/DescriptionTextArea.tsx | 6 +----- .../AddNewPipeline/FormFields/NameInput.tsx | 2 +- .../AddNewProcessor/FormFields/NameInput.tsx | 2 +- .../FormFields/ParsingRulesTextArea.tsx | 6 +----- .../PipelineListsView/AddNewProcessor/config.ts | 14 +++++++------- .../Preview/components/LogsList/styles.scss | 4 ++-- frontend/src/types/api/pipeline/def.ts | 11 +++++++++++ 7 files changed, 24 insertions(+), 21 deletions(-) diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewPipeline/FormFields/DescriptionTextArea.tsx b/frontend/src/container/PipelinePage/PipelineListsView/AddNewPipeline/FormFields/DescriptionTextArea.tsx index 6bd456e7f1..5914114d84 100644 --- a/frontend/src/container/PipelinePage/PipelineListsView/AddNewPipeline/FormFields/DescriptionTextArea.tsx +++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewPipeline/FormFields/DescriptionTextArea.tsx @@ -16,11 +16,7 @@ function DescriptionTextArea({ label={{fieldData.fieldName}} key={fieldData.id} > - + ); } diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewPipeline/FormFields/NameInput.tsx b/frontend/src/container/PipelinePage/PipelineListsView/AddNewPipeline/FormFields/NameInput.tsx index 21e25118af..ab96a6c689 100644 --- a/frontend/src/container/PipelinePage/PipelineListsView/AddNewPipeline/FormFields/NameInput.tsx +++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewPipeline/FormFields/NameInput.tsx @@ -16,7 +16,7 @@ function NameInput({ fieldData }: NameInputProps): JSX.Element { rules={formValidationRules} name={fieldData.name} > - + ); } diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/NameInput.tsx b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/NameInput.tsx index 3991715f63..bcc41e9677 100644 --- a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/NameInput.tsx +++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/NameInput.tsx @@ -23,7 +23,7 @@ function NameInput({ fieldData }: NameInputProps): JSX.Element { initialValue={fieldData.initialValue} rules={fieldData.rules ? fieldData.rules : formValidationRules} > - + diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/ParsingRulesTextArea.tsx b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/ParsingRulesTextArea.tsx index 4d7f8b2ec0..ef0338eec0 100644 --- a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/ParsingRulesTextArea.tsx +++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/ParsingRulesTextArea.tsx @@ -20,11 +20,7 @@ function ParsingRulesTextArea({ name={fieldData.name} label={{fieldData.fieldName}} > - + diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/config.ts b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/config.ts index e7e5677cd8..46171c030a 100644 --- a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/config.ts +++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/config.ts @@ -24,7 +24,7 @@ export type ProcessorFormField = { id: number; fieldName: string; placeholder: string; - name: string; + name: string | Array; rules?: Array<{ [key: string]: boolean }>; initialValue?: string; }; @@ -152,21 +152,21 @@ export const processorFields: { [key: string]: Array } = { }, { id: 2, - fieldName: 'Trace Id Parce From', + fieldName: 'Parse Trace Id From', placeholder: 'processor_trace_id_placeholder', - name: 'traceId', + name: ['trace_id', 'parse_from'], }, { id: 3, - fieldName: 'Span id Parse From', + fieldName: 'Parse Span Id From', placeholder: 'processor_span_id_placeholder', - name: 'spanId', + name: ['span_id', 'parse_from'], }, { id: 4, - fieldName: 'Trace flags parse from', + fieldName: 'Parse Trace flags From', placeholder: 'processor_trace_flags_placeholder', - name: 'traceFlags', + name: ['trace_flags', 'parse_from'], }, ], retain: [ diff --git a/frontend/src/container/PipelinePage/PipelineListsView/Preview/components/LogsList/styles.scss b/frontend/src/container/PipelinePage/PipelineListsView/Preview/components/LogsList/styles.scss index 80cec9ef28..13d62e17cc 100644 --- a/frontend/src/container/PipelinePage/PipelineListsView/Preview/components/LogsList/styles.scss +++ b/frontend/src/container/PipelinePage/PipelineListsView/Preview/components/LogsList/styles.scss @@ -3,7 +3,6 @@ height: 100%; display: flex; flex-direction: column; - justify-content: space-between; align-items: stretch; box-sizing: border-box; @@ -11,8 +10,9 @@ } .logs-preview-list-item { - width: 100%; position: relative; + width: 100%; + max-height: 2rem; display: flex; justify-content: space-between; diff --git a/frontend/src/types/api/pipeline/def.ts b/frontend/src/types/api/pipeline/def.ts index 808aecf658..5462dfe611 100644 --- a/frontend/src/types/api/pipeline/def.ts +++ b/frontend/src/types/api/pipeline/def.ts @@ -16,6 +16,17 @@ export interface ProcessorData { on_error?: string; field?: string; value?: string; + + // trace parser fields. + trace_id?: { + parse_from: string; + }; + span_id?: { + parse_from: string; + }; + trace_flags?: { + parse_from: string; + }; } export interface PipelineData { From bbfaad15c2c7cbe521716ae06538a84047dc7954 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 29 Oct 2023 18:20:13 +0530 Subject: [PATCH 10/28] chore(deps): bump @babel/traverse from 7.21.4 to 7.23.2 in /frontend (#3756) Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.21.4 to 7.23.2. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse) --- updated-dependencies: - dependency-name: "@babel/traverse" dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- frontend/yarn.lock | 92 +++++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/frontend/yarn.lock b/frontend/yarn.lock index aa115a0895..c0da947052 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -218,6 +218,16 @@ "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" +"@babel/generator@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420" + integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g== + dependencies: + "@babel/types" "^7.23.0" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + "@babel/helper-annotate-as-pure@^7.15.4", "@babel/helper-annotate-as-pure@^7.16.0", "@babel/helper-annotate-as-pure@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz" @@ -354,6 +364,11 @@ resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz" integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + "@babel/helper-environment-visitor@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" @@ -382,6 +397,14 @@ "@babel/template" "^7.22.5" "@babel/types" "^7.22.5" +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" + "@babel/helper-hoist-variables@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" @@ -593,6 +616,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz#601fa28e4cc06786c18912dca138cec73b882044" integrity sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ== +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + "@babel/helper-validator-identifier@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" @@ -692,6 +720,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.15.tgz#d34592bfe288a32e741aa0663dbc4829fcd55160" integrity sha512-RWmQ/sklUN9BvGGpCDgSubhHWfAx24XDTDObup4ffvxaYsptOg2P3KG0j+1eWKLxpkX0j0uHxmpq2Z1SP/VhxA== +"@babel/parser@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" + integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz" @@ -2047,51 +2080,19 @@ "@babel/parser" "^7.22.5" "@babel/types" "^7.22.5" -"@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.21.4", "@babel/traverse@^7.4.5", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2": - version "7.21.4" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz" - integrity sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q== - dependencies: - "@babel/code-frame" "^7.21.4" - "@babel/generator" "^7.21.4" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.21.0" - "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.21.4" - "@babel/types" "^7.21.4" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/traverse@^7.22.11": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.11.tgz#71ebb3af7a05ff97280b83f05f8865ac94b2027c" - integrity sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ== - dependencies: - "@babel/code-frame" "^7.22.10" - "@babel/generator" "^7.22.10" - "@babel/helper-environment-visitor" "^7.22.5" - "@babel/helper-function-name" "^7.22.5" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.22.11" - "@babel/types" "^7.22.11" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/traverse@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.15.tgz#75be4d2d6e216e880e93017f4e2389aeb77ef2d9" - integrity sha512-DdHPwvJY0sEeN4xJU5uRLmZjgMMDIvMPniLuYzUVXj/GGzysPl0/fwt44JBkyUIzGJPV8QgHMcQdQ34XFuKTYQ== +"@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.21.4", "@babel/traverse@^7.22.11", "@babel/traverse@^7.22.15", "@babel/traverse@^7.4.5", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" + integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== dependencies: "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.22.15" - "@babel/helper-environment-visitor" "^7.22.5" - "@babel/helper-function-name" "^7.22.5" + "@babel/generator" "^7.23.0" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" "@babel/helper-hoist-variables" "^7.22.5" "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.22.15" - "@babel/types" "^7.22.15" + "@babel/parser" "^7.23.0" + "@babel/types" "^7.23.0" debug "^4.1.0" globals "^11.1.0" @@ -2122,6 +2123,15 @@ "@babel/helper-validator-identifier" "^7.22.15" to-fast-properties "^2.0.0" +"@babel/types@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb" + integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" From 4ef973ceb6fb3cafea35ab220242ea2d4090dd41 Mon Sep 17 00:00:00 2001 From: Nityananda Gohain Date: Mon, 30 Oct 2023 21:28:21 +0530 Subject: [PATCH 11/28] feat: default trace_parser updated (#3782) * feat: default trace_parser updated * fix: regex updated --- .../otel-collector-config.yaml | 53 +++++++++---------- .../otel-collector-config.yaml | 53 +++++++++---------- 2 files changed, 48 insertions(+), 58 deletions(-) diff --git a/deploy/docker-swarm/clickhouse-setup/otel-collector-config.yaml b/deploy/docker-swarm/clickhouse-setup/otel-collector-config.yaml index 74df932c0f..bc4fa3d3a8 100644 --- a/deploy/docker-swarm/clickhouse-setup/otel-collector-config.yaml +++ b/deploy/docker-swarm/clickhouse-setup/otel-collector-config.yaml @@ -63,38 +63,33 @@ receivers: processors: logstransform/internal: operators: + - type: regex_parser + id: traceid + # https://regex101.com/r/MMfNjk/1 + regex: '(?i)(trace(-|_||)id("|=| |-|:)*)(?P[A-Fa-f0-9]+)' + parse_from: body + parse_to: attributes.temp_trace + if: 'body matches "(?i)(trace(-|_||)id(\"|=| |-|:)*)(?P[A-Fa-f0-9]+)"' + output: spanid + - type: regex_parser + id: spanid + # https://regex101.com/r/uXSwLc/1 + regex: '(?i)(span(-|_||)id("|=| |-|:)*)(?P[A-Fa-f0-9]+)' + parse_from: body + parse_to: attributes.temp_trace + if: 'body matches "(?i)(span(-|_||)id(\"|=| |-|:)*)(?P[A-Fa-f0-9]+)"' + output: trace_parser - type: trace_parser - if: '"trace_id" in attributes or "span_id" in attributes' + id: trace_parser trace_id: - parse_from: attributes.trace_id + parse_from: attributes.temp_trace.trace_id span_id: - parse_from: attributes.span_id - output: remove_trace_id - - type: trace_parser - if: '"traceId" in attributes or "spanId" in attributes' - trace_id: - parse_from: attributes.traceId - span_id: - parse_from: attributes.spanId - output: remove_traceId - - id: remove_traceId - type: remove - if: '"traceId" in attributes' - field: attributes.traceId - output: remove_spanId - - id: remove_spanId - type: remove - if: '"spanId" in attributes' - field: attributes.spanId - - id: remove_trace_id - type: remove - if: '"trace_id" in attributes' - field: attributes.trace_id - output: remove_span_id - - id: remove_span_id - type: remove - if: '"span_id" in attributes' - field: attributes.span_id + parse_from: attributes.temp_trace.span_id + output: remove_temp + - type: remove + id: remove_temp + field: attributes.temp_trace + if: '"temp_trace" in attributes' batch: send_batch_size: 10000 send_batch_max_size: 11000 diff --git a/deploy/docker/clickhouse-setup/otel-collector-config.yaml b/deploy/docker/clickhouse-setup/otel-collector-config.yaml index 1604ae38a1..fe6da5f126 100644 --- a/deploy/docker/clickhouse-setup/otel-collector-config.yaml +++ b/deploy/docker/clickhouse-setup/otel-collector-config.yaml @@ -64,38 +64,33 @@ receivers: processors: logstransform/internal: operators: + - type: regex_parser + id: traceid + # https://regex101.com/r/MMfNjk/1 + regex: '(?i)(trace(-|_||)id("|=| |-|:)*)(?P[A-Fa-f0-9]+)' + parse_from: body + parse_to: attributes.temp_trace + if: 'body matches "(?i)(trace(-|_||)id(\"|=| |-|:)*)(?P[A-Fa-f0-9]+)"' + output: spanid + - type: regex_parser + id: spanid + # https://regex101.com/r/uXSwLc/1 + regex: '(?i)(span(-|_||)id("|=| |-|:)*)(?P[A-Fa-f0-9]+)' + parse_from: body + parse_to: attributes.temp_trace + if: 'body matches "(?i)(span(-|_||)id(\"|=| |-|:)*)(?P[A-Fa-f0-9]+)"' + output: trace_parser - type: trace_parser - if: '"trace_id" in attributes or "span_id" in attributes' + id: trace_parser trace_id: - parse_from: attributes.trace_id + parse_from: attributes.temp_trace.trace_id span_id: - parse_from: attributes.span_id - output: remove_trace_id - - type: trace_parser - if: '"traceId" in attributes or "spanId" in attributes' - trace_id: - parse_from: attributes.traceId - span_id: - parse_from: attributes.spanId - output: remove_traceId - - id: remove_traceId - type: remove - if: '"traceId" in attributes' - field: attributes.traceId - output: remove_spanId - - id: remove_spanId - type: remove - if: '"spanId" in attributes' - field: attributes.spanId - - id: remove_trace_id - type: remove - if: '"trace_id" in attributes' - field: attributes.trace_id - output: remove_span_id - - id: remove_span_id - type: remove - if: '"span_id" in attributes' - field: attributes.span_id + parse_from: attributes.temp_trace.span_id + output: remove_temp + - type: remove + id: remove_temp + field: attributes.temp_trace + if: '"temp_trace" in attributes' batch: send_batch_size: 10000 send_batch_max_size: 11000 From 658a9cc11bc343ba0ef1d0651a9c2f4e38d1e005 Mon Sep 17 00:00:00 2001 From: Raj Kamal Singh <1133322+rkssisodiya@users.noreply.github.com> Date: Tue, 31 Oct 2023 10:36:25 +0530 Subject: [PATCH 12/28] fix: only latest agent config versions can have a pending deployment (#3836) --- pkg/query-service/agentConf/db.go | 8 +++ pkg/query-service/agentConf/version.go | 11 +-- .../integration/logparsingpipeline_test.go | 71 +++++++++++++++++++ 3 files changed, 85 insertions(+), 5 deletions(-) diff --git a/pkg/query-service/agentConf/db.go b/pkg/query-service/agentConf/db.go index afb59123f4..3369dbe23f 100644 --- a/pkg/query-service/agentConf/db.go +++ b/pkg/query-service/agentConf/db.go @@ -12,6 +12,7 @@ import ( "go.signoz.io/signoz/pkg/query-service/agentConf/sqlite" "go.signoz.io/signoz/pkg/query-service/model" "go.uber.org/zap" + "golang.org/x/exp/slices" ) func init() { @@ -61,6 +62,13 @@ func (r *Repo) GetConfigHistory( return nil, model.InternalError(err) } + incompleteStatuses := []DeployStatus{DeployInitiated, Deploying} + for idx := 1; idx < len(c); idx++ { + if slices.Contains(incompleteStatuses, c[idx].DeployStatus) { + c[idx].DeployStatus = DeployStatusUnknown + } + } + return c, nil } diff --git a/pkg/query-service/agentConf/version.go b/pkg/query-service/agentConf/version.go index c6b8c01ee4..13be5f7cd2 100644 --- a/pkg/query-service/agentConf/version.go +++ b/pkg/query-service/agentConf/version.go @@ -18,11 +18,12 @@ const ( type DeployStatus string const ( - PendingDeploy DeployStatus = "DIRTY" - Deploying DeployStatus = "DEPLOYING" - Deployed DeployStatus = "DEPLOYED" - DeployInitiated DeployStatus = "IN_PROGRESS" - DeployFailed DeployStatus = "FAILED" + PendingDeploy DeployStatus = "DIRTY" + Deploying DeployStatus = "DEPLOYING" + Deployed DeployStatus = "DEPLOYED" + DeployInitiated DeployStatus = "IN_PROGRESS" + DeployFailed DeployStatus = "FAILED" + DeployStatusUnknown DeployStatus = "UNKNOWN" ) type ConfigVersion struct { diff --git a/pkg/query-service/tests/integration/logparsingpipeline_test.go b/pkg/query-service/tests/integration/logparsingpipeline_test.go index 2e1b70c1db..1b370e7804 100644 --- a/pkg/query-service/tests/integration/logparsingpipeline_test.go +++ b/pkg/query-service/tests/integration/logparsingpipeline_test.go @@ -172,6 +172,77 @@ func TestLogPipelinesLifecycle(t *testing.T) { ) } +func TestLogPipelinesHistory(t *testing.T) { + require := require.New(t) + testbed := NewLogPipelinesTestBed(t) + + // Only the latest config version can be "IN_PROGRESS", + // other incomplete deployments should have status "UNKNOWN" + getPipelinesResp := testbed.GetPipelinesFromQS() + require.Equal(0, len(getPipelinesResp.History)) + + postablePipelines := logparsingpipeline.PostablePipelines{ + Pipelines: []logparsingpipeline.PostablePipeline{ + { + OrderId: 1, + Name: "pipeline1", + Alias: "pipeline1", + Enabled: true, + Filter: &v3.FilterSet{ + Operator: "AND", + Items: []v3.FilterItem{ + { + Key: v3.AttributeKey{ + Key: "method", + DataType: v3.AttributeKeyDataTypeString, + Type: v3.AttributeKeyTypeTag, + }, + Operator: "=", + Value: "GET", + }, + }, + }, + Config: []logparsingpipeline.PipelineOperator{ + { + OrderId: 1, + ID: "add", + Type: "add", + Field: "attributes.test", + Value: "val", + Enabled: true, + Name: "test add", + }, + }, + }, + }, + } + + testbed.PostPipelinesToQS(postablePipelines) + getPipelinesResp = testbed.GetPipelinesFromQS() + require.Equal(1, len(getPipelinesResp.History)) + require.Equal(agentConf.DeployInitiated, getPipelinesResp.History[0].DeployStatus) + + postablePipelines.Pipelines[0].Config = append( + postablePipelines.Pipelines[0].Config, + logparsingpipeline.PipelineOperator{ + OrderId: 2, + ID: "remove", + Type: "remove", + Field: "attributes.test", + Enabled: true, + Name: "test remove", + }, + ) + postablePipelines.Pipelines[0].Config[0].Output = "remove" + + testbed.PostPipelinesToQS(postablePipelines) + getPipelinesResp = testbed.GetPipelinesFromQS() + + require.Equal(2, len(getPipelinesResp.History)) + require.Equal(agentConf.DeployInitiated, getPipelinesResp.History[0].DeployStatus) + require.Equal(agentConf.DeployStatusUnknown, getPipelinesResp.History[1].DeployStatus) +} + func TestLogPipelinesValidation(t *testing.T) { validPipelineFilterSet := &v3.FilterSet{ Operator: "AND", From 4ca1e3437812f2468b0990b8c576870c5dce0cfd Mon Sep 17 00:00:00 2001 From: Raj Kamal Singh <1133322+rkssisodiya@users.noreply.github.com> Date: Tue, 31 Oct 2023 11:25:41 +0530 Subject: [PATCH 13/28] Fix: Log pipelines deployment status unknown (#3838) * fix: fe: log pipelines: label and icon for deploy status 'UNKNOWN' * fix: handle scenarios when response.payload?.pipelines is undefined (eg: post delete all) --- .../PipelinePage/Layouts/ChangeHistory/utils.tsx | 5 +++++ .../PipelinePage/PipelineListsView/index.tsx | 12 ++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/frontend/src/container/PipelinePage/Layouts/ChangeHistory/utils.tsx b/frontend/src/container/PipelinePage/Layouts/ChangeHistory/utils.tsx index ff3161f7d4..705796ffbb 100644 --- a/frontend/src/container/PipelinePage/Layouts/ChangeHistory/utils.tsx +++ b/frontend/src/container/PipelinePage/Layouts/ChangeHistory/utils.tsx @@ -3,6 +3,7 @@ import { CloseCircleFilled, ExclamationCircleFilled, LoadingOutlined, + MinusCircleFilled, } from '@ant-design/icons'; import { Spin } from 'antd'; @@ -16,6 +17,8 @@ export function getDeploymentStage(value: string): string { return 'Dirty'; case 'FAILED': return 'Failed'; + case 'UNKNOWN': + return 'Unknown'; default: return ''; } @@ -33,6 +36,8 @@ export function getDeploymentStageIcon(value: string): JSX.Element { return ; case 'FAILED': return ; + case 'UNKNOWN': + return ; default: return ; } diff --git a/frontend/src/container/PipelinePage/PipelineListsView/index.tsx b/frontend/src/container/PipelinePage/PipelineListsView/index.tsx index d602004a68..e7211c059c 100644 --- a/frontend/src/container/PipelinePage/PipelineListsView/index.tsx +++ b/frontend/src/container/PipelinePage/PipelineListsView/index.tsx @@ -56,23 +56,23 @@ function PipelineListsView({ const [modal, contextHolder] = Modal.useModal(); const { notifications } = useNotifications(); const [prevPipelineData, setPrevPipelineData] = useState>( - cloneDeep(pipelineData?.pipelines), + cloneDeep(pipelineData?.pipelines || []), ); const [currPipelineData, setCurrPipelineData] = useState>( - cloneDeep(pipelineData?.pipelines), + cloneDeep(pipelineData?.pipelines || []), ); const [expandedPipelineId, setExpandedPipelineId] = useState< string | undefined >(undefined); const expandedPipelineData = useCallback( - () => currPipelineData.find((p) => p.id === expandedPipelineId), + () => currPipelineData?.find((p) => p.id === expandedPipelineId), [currPipelineData, expandedPipelineId], ); const setExpandedPipelineData = useCallback( (newData: PipelineData): void => { if (expandedPipelineId) { - const pipelineIdx = currPipelineData.findIndex( + const pipelineIdx = currPipelineData?.findIndex( (p) => p.id === expandedPipelineId, ); if (pipelineIdx >= 0) { @@ -359,8 +359,8 @@ function PipelineListsView({ refetchPipelineLists(); setActionMode(ActionMode.Viewing); setShowSaveButton(undefined); - setCurrPipelineData(response.payload?.pipelines); - setPrevPipelineData(response.payload?.pipelines); + setCurrPipelineData(response.payload?.pipelines || []); + setPrevPipelineData(response.payload?.pipelines || []); } else { modifiedPipelineData.forEach((item: PipelineData) => { const pipelineData = item; From 3341cb7396808c5e2f4199518ec0d18adc1a0b7a Mon Sep 17 00:00:00 2001 From: Nityananda Gohain Date: Tue, 31 Oct 2023 15:06:07 +0530 Subject: [PATCH 14/28] feat: boolean attribute support (#3816) * feat: boolean attribute support * fix: comment updated --------- Co-authored-by: Srikanth Chekuri --- .../app/clickhouseReader/reader.go | 8 +++++++- pkg/query-service/app/logs/v3/query_builder.go | 4 +++- .../app/logs/v3/query_builder_test.go | 17 ++++++++++------- pkg/query-service/constants/constants.go | 1 + pkg/query-service/model/response.go | 1 + 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/pkg/query-service/app/clickhouseReader/reader.go b/pkg/query-service/app/clickhouseReader/reader.go index 2c24b4b8c1..7b32fbff45 100644 --- a/pkg/query-service/app/clickhouseReader/reader.go +++ b/pkg/query-service/app/clickhouseReader/reader.go @@ -3493,10 +3493,16 @@ func (r *ClickHouseReader) UpdateLogField(ctx context.Context, field *model.Upda return &model.ApiError{Err: err, Typ: model.ErrorInternal} } - query = fmt.Sprintf("ALTER TABLE %s.%s ON CLUSTER %s ADD COLUMN IF NOT EXISTS %s %s MATERIALIZED -1", + defaultValueDistributed := "-1" + if strings.ToLower(field.DataType) == "bool" { + defaultValueDistributed = "false" + field.IndexType = "set(2)" + } + query = fmt.Sprintf("ALTER TABLE %s.%s ON CLUSTER %s ADD COLUMN IF NOT EXISTS %s %s MATERIALIZED %s", r.logsDB, r.logsTable, r.cluster, colname, field.DataType, + defaultValueDistributed, ) err = r.db.Exec(ctx, query) if err != nil { diff --git a/pkg/query-service/app/logs/v3/query_builder.go b/pkg/query-service/app/logs/v3/query_builder.go index ff989fa61d..32e4bb29f4 100644 --- a/pkg/query-service/app/logs/v3/query_builder.go +++ b/pkg/query-service/app/logs/v3/query_builder.go @@ -65,7 +65,9 @@ func getClickhouseLogsColumnDataType(columnDataType v3.AttributeKeyDataType) str if columnDataType == v3.AttributeKeyDataTypeInt64 { return "int64" } - // for bool also we are returning string as we store bool data as string. + if columnDataType == v3.AttributeKeyDataTypeBool { + return "bool" + } return "string" } diff --git a/pkg/query-service/app/logs/v3/query_builder_test.go b/pkg/query-service/app/logs/v3/query_builder_test.go index 8ae90e2e0f..88d98847c8 100644 --- a/pkg/query-service/app/logs/v3/query_builder_test.go +++ b/pkg/query-service/app/logs/v3/query_builder_test.go @@ -683,6 +683,7 @@ var testBuildLogsQueryData = []struct { }, ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string," + "CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64," + + "CAST((attributes_bool_key, attributes_bool_value), 'Map(String, Bool)') as attributes_bool," + "CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string " + "from signoz_logs.distributed_logs where (timestamp >= 1680066360726210000 AND timestamp <= 1680066458000000000) order by timestamp DESC", }, @@ -701,6 +702,7 @@ var testBuildLogsQueryData = []struct { }, ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string," + "CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64," + + "CAST((attributes_bool_key, attributes_bool_value), 'Map(String, Bool)') as attributes_bool," + "CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string " + "from signoz_logs.distributed_logs where (timestamp >= 1680066360726210000 AND timestamp <= 1680066458000000000) order by method ASC", }, @@ -720,6 +722,7 @@ var testBuildLogsQueryData = []struct { }, ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string," + "CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64," + + "CAST((attributes_bool_key, attributes_bool_value), 'Map(String, Bool)') as attributes_bool," + "CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string " + "from signoz_logs.distributed_logs where (timestamp >= 1680066360726210000 AND timestamp <= 1680066458000000000) AND severity_number != 0 order by timestamp DESC", }, @@ -1236,7 +1239,7 @@ var testPrepLogsQueryData = []struct { }, }, TableName: "logs", - ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string,CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64,CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string from signoz_logs.distributed_logs where attributes_string_value[indexOf(attributes_string_key, 'method')] = 'GET' AND ", + ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string,CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64,CAST((attributes_bool_key, attributes_bool_value), 'Map(String, Bool)') as attributes_bool,CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string from signoz_logs.distributed_logs where attributes_string_value[indexOf(attributes_string_key, 'method')] = 'GET' AND ", Options: Options{IsLivetailQuery: true}, }, { @@ -1255,7 +1258,7 @@ var testPrepLogsQueryData = []struct { }, }, TableName: "logs", - ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string,CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64,CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string from signoz_logs.distributed_logs where attributes_string_value[indexOf(attributes_string_key, 'method')] ILIKE '%GET%' AND ", + ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string,CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64,CAST((attributes_bool_key, attributes_bool_value), 'Map(String, Bool)') as attributes_bool,CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string from signoz_logs.distributed_logs where attributes_string_value[indexOf(attributes_string_key, 'method')] ILIKE '%GET%' AND ", Options: Options{IsLivetailQuery: true}, }, { @@ -1271,7 +1274,7 @@ var testPrepLogsQueryData = []struct { Filters: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{}}, }, TableName: "logs", - ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string,CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64,CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string from signoz_logs.distributed_logs where ", + ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string,CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64,CAST((attributes_bool_key, attributes_bool_value), 'Map(String, Bool)') as attributes_bool,CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string from signoz_logs.distributed_logs where ", Options: Options{IsLivetailQuery: true}, }, { @@ -1350,7 +1353,7 @@ var testPrepLogsQueryLimitOffsetData = []struct { PageSize: 5, }, TableName: "logs", - ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string,CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64,CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string from signoz_logs.distributed_logs where (timestamp >= 1680066360000000000 AND timestamp <= 1680066420000000000) order by timestamp desc LIMIT 1", + ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string,CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64,CAST((attributes_bool_key, attributes_bool_value), 'Map(String, Bool)') as attributes_bool,CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string from signoz_logs.distributed_logs where (timestamp >= 1680066360000000000 AND timestamp <= 1680066420000000000) order by timestamp desc LIMIT 1", }, { Name: "Test limit greater than pageSize - order by ts", @@ -1371,7 +1374,7 @@ var testPrepLogsQueryLimitOffsetData = []struct { PageSize: 10, }, TableName: "logs", - ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string,CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64,CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string from signoz_logs.distributed_logs where (timestamp >= 1680066360000000000 AND timestamp <= 1680066420000000000) AND id < '2TNh4vp2TpiWyLt3SzuadLJF2s4' order by timestamp desc LIMIT 10", + ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string,CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64,CAST((attributes_bool_key, attributes_bool_value), 'Map(String, Bool)') as attributes_bool,CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string from signoz_logs.distributed_logs where (timestamp >= 1680066360000000000 AND timestamp <= 1680066420000000000) AND id < '2TNh4vp2TpiWyLt3SzuadLJF2s4' order by timestamp desc LIMIT 10", }, { Name: "Test limit less than pageSize - order by custom", @@ -1390,7 +1393,7 @@ var testPrepLogsQueryLimitOffsetData = []struct { PageSize: 5, }, TableName: "logs", - ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string,CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64,CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string from signoz_logs.distributed_logs where (timestamp >= 1680066360000000000 AND timestamp <= 1680066420000000000) order by attributes_string_value[indexOf(attributes_string_key, 'method')] desc LIMIT 1 OFFSET 0", + ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string,CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64,CAST((attributes_bool_key, attributes_bool_value), 'Map(String, Bool)') as attributes_bool,CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string from signoz_logs.distributed_logs where (timestamp >= 1680066360000000000 AND timestamp <= 1680066420000000000) order by attributes_string_value[indexOf(attributes_string_key, 'method')] desc LIMIT 1 OFFSET 0", }, { Name: "Test limit greater than pageSize - order by custom", @@ -1411,7 +1414,7 @@ var testPrepLogsQueryLimitOffsetData = []struct { PageSize: 50, }, TableName: "logs", - ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string,CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64,CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string from signoz_logs.distributed_logs where (timestamp >= 1680066360000000000 AND timestamp <= 1680066420000000000) AND id < '2TNh4vp2TpiWyLt3SzuadLJF2s4' order by attributes_string_value[indexOf(attributes_string_key, 'method')] desc LIMIT 50 OFFSET 50", + ExpectedQuery: "SELECT timestamp, id, trace_id, span_id, trace_flags, severity_text, severity_number, body,CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string,CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64,CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64,CAST((attributes_bool_key, attributes_bool_value), 'Map(String, Bool)') as attributes_bool,CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string from signoz_logs.distributed_logs where (timestamp >= 1680066360000000000 AND timestamp <= 1680066420000000000) AND id < '2TNh4vp2TpiWyLt3SzuadLJF2s4' order by attributes_string_value[indexOf(attributes_string_key, 'method')] desc LIMIT 50 OFFSET 50", }, } diff --git a/pkg/query-service/constants/constants.go b/pkg/query-service/constants/constants.go index 3027ecaee2..b27a85306c 100644 --- a/pkg/query-service/constants/constants.go +++ b/pkg/query-service/constants/constants.go @@ -269,6 +269,7 @@ const ( "CAST((attributes_string_key, attributes_string_value), 'Map(String, String)') as attributes_string," + "CAST((attributes_int64_key, attributes_int64_value), 'Map(String, Int64)') as attributes_int64," + "CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64," + + "CAST((attributes_bool_key, attributes_bool_value), 'Map(String, Bool)') as attributes_bool," + "CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string " TracesExplorerViewSQLSelectWithSubQuery = "WITH subQuery AS (SELECT distinct on (traceID) traceID, durationNano, " + "serviceName, name FROM %s.%s WHERE parentSpanID = '' AND %s %s ORDER BY durationNano DESC " diff --git a/pkg/query-service/model/response.go b/pkg/query-service/model/response.go index c80f223163..9bb1d985c0 100644 --- a/pkg/query-service/model/response.go +++ b/pkg/query-service/model/response.go @@ -552,6 +552,7 @@ type SignozLog struct { Attributes_string map[string]string `json:"attributes_string" ch:"attributes_string"` Attributes_int64 map[string]int64 `json:"attributes_int" ch:"attributes_int64"` Attributes_float64 map[string]float64 `json:"attributes_float" ch:"attributes_float64"` + Attributes_bool map[string]bool `json:"attributes_bool" ch:"attributes_bool"` } type LogsTailClient struct { From eddb607c9cbb5206c409191910e3d4590a4b62e6 Mon Sep 17 00:00:00 2001 From: Rajat Dabade Date: Wed, 1 Nov 2023 00:43:22 +0530 Subject: [PATCH 15/28] [Fix]: added the darktheme support for Action Column in Alerts Listing Table. (#3844) * refactor: added the darktheme support * fix: typo --------- Co-authored-by: Ankit Nayan --- frontend/src/components/DropDown/DropDown.styles.scss | 4 ++++ frontend/src/components/DropDown/DropDown.tsx | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/DropDown/DropDown.styles.scss b/frontend/src/components/DropDown/DropDown.styles.scss index 6042acd07c..3527c1385a 100644 --- a/frontend/src/components/DropDown/DropDown.styles.scss +++ b/frontend/src/components/DropDown/DropDown.styles.scss @@ -2,6 +2,10 @@ color: #fff; } +.Dropdown-button--dark { + color: #000; +} + .Dropdown-icon { font-size: 1.2rem; } \ No newline at end of file diff --git a/frontend/src/components/DropDown/DropDown.tsx b/frontend/src/components/DropDown/DropDown.tsx index 2f45a6a1a7..c76ff8daec 100644 --- a/frontend/src/components/DropDown/DropDown.tsx +++ b/frontend/src/components/DropDown/DropDown.tsx @@ -2,8 +2,11 @@ import './DropDown.styles.scss'; import { EllipsisOutlined } from '@ant-design/icons'; import { Button, Dropdown, MenuProps, Space } from 'antd'; +import { useIsDarkMode } from 'hooks/useDarkMode'; function DropDown({ element }: { element: JSX.Element[] }): JSX.Element { + const isDarkMode = useIsDarkMode(); + const items: MenuProps['items'] = element.map( (e: JSX.Element, index: number) => ({ label: e, @@ -15,7 +18,7 @@ function DropDown({ element }: { element: JSX.Element[] }): JSX.Element { + + ); +} + +Download.defaultProps = { + isLoading: undefined, +}; + +export default Download; diff --git a/frontend/src/container/Download/Download.types.ts b/frontend/src/container/Download/Download.types.ts new file mode 100644 index 0000000000..0757ed62fd --- /dev/null +++ b/frontend/src/container/Download/Download.types.ts @@ -0,0 +1,10 @@ +export type DownloadOptions = { + isDownloadEnabled: boolean; + fileName: string; +}; + +export type DownloadProps = { + data: Record[]; + isLoading?: boolean; + fileName: string; +}; diff --git a/frontend/src/container/LogControls/index.tsx b/frontend/src/container/LogControls/index.tsx index 01fe12e808..eda7f89c33 100644 --- a/frontend/src/container/LogControls/index.tsx +++ b/frontend/src/container/LogControls/index.tsx @@ -1,15 +1,14 @@ -import { CloudDownloadOutlined, FastBackwardOutlined } from '@ant-design/icons'; -import { Button, Divider, Dropdown, MenuProps } from 'antd'; -import { Excel } from 'antd-table-saveas-excel'; +import { FastBackwardOutlined } from '@ant-design/icons'; +import { Button, Divider } from 'antd'; import Controls from 'container/Controls'; +import Download from 'container/Download/Download'; import { getGlobalTime } from 'container/LogsSearchFilter/utils'; import { getMinMax } from 'container/TopNav/AutoRefresh/config'; import dayjs from 'dayjs'; import { Pagination } from 'hooks/queryPagination'; import { FlatLogData } from 'lib/logs/flatLogData'; import { OrderPreferenceItems } from 'pages/Logs/config'; -import { unparse } from 'papaparse'; -import { memo, useCallback, useMemo } from 'react'; +import { memo, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { Dispatch } from 'redux'; import { AppState } from 'store/reducers'; @@ -23,7 +22,7 @@ import { import { GlobalReducer } from 'types/reducer/globalTime'; import { ILogsReducer } from 'types/reducer/logs'; -import { Container, DownloadLogButton } from './styles'; +import { Container } from './styles'; function LogControls(): JSX.Element | null { const { @@ -97,58 +96,6 @@ function LogControls(): JSX.Element | null { [logs], ); - const downloadExcelFile = useCallback((): void => { - const headers = Object.keys(Object.assign({}, ...flattenLogData)).map( - (item) => { - const updatedTitle = item - .split('_') - .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) - .join(' '); - return { - title: updatedTitle, - dataIndex: item, - }; - }, - ); - const excel = new Excel(); - excel - .addSheet('log_data') - .addColumns(headers) - .addDataSource(flattenLogData, { - str2Percent: true, - }) - .saveAs('log_data.xlsx'); - }, [flattenLogData]); - - const downloadCsvFile = useCallback((): void => { - const csv = unparse(flattenLogData); - const csvBlob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); - const csvUrl = URL.createObjectURL(csvBlob); - const downloadLink = document.createElement('a'); - downloadLink.href = csvUrl; - downloadLink.download = 'log_data.csv'; - downloadLink.click(); - downloadLink.remove(); - }, [flattenLogData]); - - const menu: MenuProps = useMemo( - () => ({ - items: [ - { - key: 'download-as-excel', - label: 'Excel', - onClick: downloadExcelFile, - }, - { - key: 'download-as-csv', - label: 'CSV', - onClick: downloadCsvFile, - }, - ], - }), - [downloadCsvFile, downloadExcelFile], - ); - const isLoading = isLogsLoading || isLoadingAggregate; if (liveTail !== 'STOPPED') { @@ -157,12 +104,7 @@ function LogControls(): JSX.Element | null { return ( - - - - Download - - +
); diff --git a/frontend/src/components/ResizeTable/DynamicColumnTable.syles.scss b/frontend/src/components/ResizeTable/DynamicColumnTable.syles.scss index 30bccd87e3..2bd0606abd 100644 --- a/frontend/src/components/ResizeTable/DynamicColumnTable.syles.scss +++ b/frontend/src/components/ResizeTable/DynamicColumnTable.syles.scss @@ -14,4 +14,12 @@ width: 10.625rem; justify-content: space-between; align-items: center; +} + +@media (max-width: 768px) { + .dynamicColumnsTable-items { + flex-direction: column; + width: auto; + text-align: center; + } } \ No newline at end of file diff --git a/frontend/src/components/ResizeTable/DynamicColumnTable.tsx b/frontend/src/components/ResizeTable/DynamicColumnTable.tsx index 93e3673743..385734f11d 100644 --- a/frontend/src/components/ResizeTable/DynamicColumnTable.tsx +++ b/frontend/src/components/ResizeTable/DynamicColumnTable.tsx @@ -9,7 +9,11 @@ import { popupContainer } from 'utils/selectPopupContainer'; import ResizeTable from './ResizeTable'; import { DynamicColumnTableProps } from './types'; -import { getVisibleColumns, setVisibleColumns } from './unit'; +import { + getNewColumnData, + getVisibleColumns, + setVisibleColumns, +} from './utils'; function DynamicColumnTable({ tablesource, @@ -51,22 +55,14 @@ function DynamicColumnTable({ index, checked, }); - setColumnsData((prevColumns) => { - if (checked && dynamicColumns) { - return prevColumns - ? [ - ...prevColumns.slice(0, prevColumns.length - 1), - dynamicColumns[index], - prevColumns[prevColumns.length - 1], - ] - : undefined; - } - return prevColumns && dynamicColumns - ? prevColumns.filter( - (column) => dynamicColumns[index].title !== column.title, - ) - : undefined; - }); + setColumnsData((prevColumns) => + getNewColumnData({ + checked, + index, + prevColumns, + dynamicColumns, + }), + ); }; const items: MenuProps['items'] = diff --git a/frontend/src/components/ResizeTable/TableComponent/DateComponent.tsx b/frontend/src/components/ResizeTable/TableComponent/DateComponent.tsx new file mode 100644 index 0000000000..87c5c57420 --- /dev/null +++ b/frontend/src/components/ResizeTable/TableComponent/DateComponent.tsx @@ -0,0 +1,15 @@ +import { Typography } from 'antd'; + +import Time from './Time'; + +function DateComponent( + CreatedOrUpdateTime: string | number | Date, +): JSX.Element { + if (CreatedOrUpdateTime === null) { + return - ; + } + + return