From 1770e6a15788b8f39a4cbfdcfc9e85708e75dcf7 Mon Sep 17 00:00:00 2001 From: Yevhen Shevchenko <90138953+yeshev@users.noreply.github.com> Date: Wed, 7 Jun 2023 15:27:33 +0300 Subject: [PATCH 01/37] refactor: query data field for widgets (#2839) * refactor: query data field for widgets * fix: query key index * fix: remove queryData fields * fix: remove rest queryData field * fix: remove queryData from services * fix: remove queryData in another places --------- Co-authored-by: Palash Gupta --- frontend/src/constants/reactQueryKeys.ts | 1 + .../FormAlertRules/ChartPreview/index.tsx | 60 +++++----- .../Graph/FullView/index.metricsBuilder.tsx | 33 +++--- .../container/GridGraphLayout/Graph/index.tsx | 34 +++--- .../src/container/GridGraphLayout/utils.ts | 8 -- .../ListOfDashboard/ImportJSON/index.tsx | 17 +-- .../MetricsApplication.factory.ts | 6 - .../DescriptionOfDashboard/ShareModal.tsx | 23 +--- .../DescriptionOfDashboard/util.ts | 17 --- .../LeftContainer/QuerySection/index.tsx | 39 +++---- .../LeftContainer/WidgetGraph/WidgetGraph.tsx | 27 +++-- .../LeftContainer/WidgetGraph/index.tsx | 40 +++---- .../NewWidget/LeftContainer/index.tsx | 13 ++- frontend/src/container/NewWidget/index.tsx | 72 +++--------- frontend/src/container/NewWidget/types.ts | 13 +++ .../hooks/queryBuilder/useGetQueryRange.ts | 18 +++ .../queryBuilder/useGetWidgetQueryRange.ts | 51 +++++++++ frontend/src/lib/getChartData.ts | 8 +- .../store/actions/dashboard/getDashboard.ts | 10 -- .../actions/dashboard/getQueryResults.ts | 80 +------------- .../store/actions/dashboard/saveDashboard.ts | 11 +- .../store/actions/dashboard/updateQuery.ts | 3 - frontend/src/store/reducers/dashboard.ts | 103 +----------------- frontend/src/types/actions/dashboard.ts | 21 ---- frontend/src/types/api/dashboard/getAll.ts | 12 -- frontend/src/types/reducer/dashboards.ts | 2 - 26 files changed, 248 insertions(+), 474 deletions(-) create mode 100644 frontend/src/container/NewWidget/types.ts create mode 100644 frontend/src/hooks/queryBuilder/useGetQueryRange.ts create mode 100644 frontend/src/hooks/queryBuilder/useGetWidgetQueryRange.ts diff --git a/frontend/src/constants/reactQueryKeys.ts b/frontend/src/constants/reactQueryKeys.ts index 7cc38c153e..920bba6e7b 100644 --- a/frontend/src/constants/reactQueryKeys.ts +++ b/frontend/src/constants/reactQueryKeys.ts @@ -1,3 +1,4 @@ export const REACT_QUERY_KEY = { GET_ALL_LICENCES: 'GET_ALL_LICENCES', + GET_QUERY_RANGE: 'GET_QUERY_RANGE', }; diff --git a/frontend/src/container/FormAlertRules/ChartPreview/index.tsx b/frontend/src/container/FormAlertRules/ChartPreview/index.tsx index e1d2dcf220..2b10756266 100644 --- a/frontend/src/container/FormAlertRules/ChartPreview/index.tsx +++ b/frontend/src/container/FormAlertRules/ChartPreview/index.tsx @@ -6,11 +6,10 @@ import GridGraphComponent from 'container/GridGraphComponent'; import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems'; import { Time } from 'container/TopNav/DateTimeSelection/config'; +import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange'; import getChartData from 'lib/getChartData'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { useQuery } from 'react-query'; -import { GetMetricQueryRange } from 'store/actions/dashboard/getQueryResults'; import { Query } from 'types/api/queryBuilder/queryBuilderData'; import { EQueryType } from 'types/common/dashboard'; @@ -26,9 +25,6 @@ export interface ChartPreviewProps { threshold?: number | undefined; userQueryKey?: string; } -interface QueryResponseError { - message?: string; -} function ChartPreview({ name, @@ -76,39 +72,38 @@ function ChartPreview({ } }, [query]); - const queryResponse = useQuery({ - queryKey: [ - 'chartPreview', - userQueryKey || JSON.stringify(query), - selectedInterval, - ], - queryFn: () => - GetMetricQueryRange({ - query: query || { - queryType: EQueryType.QUERY_BUILDER, - promql: [], - builder: { - queryFormulas: [], - queryData: [], - }, - clickhouse_sql: [], + const queryResponse = useGetQueryRange( + { + query: query || { + queryType: EQueryType.QUERY_BUILDER, + promql: [], + builder: { + queryFormulas: [], + queryData: [], }, - globalSelectedInterval: selectedInterval, - graphType, - selectedTime, - }), - retry: false, - enabled: canQuery, - }); + clickhouse_sql: [], + }, + globalSelectedInterval: selectedInterval, + graphType, + selectedTime, + }, + { + queryKey: [ + 'chartPreview', + userQueryKey || JSON.stringify(query), + selectedInterval, + ], + retry: false, + enabled: canQuery, + }, + ); const chartDataSet = queryResponse.isError ? null : getChartData({ queryData: [ { - queryData: queryResponse?.data?.payload?.data?.result - ? queryResponse?.data?.payload?.data?.result - : [], + queryData: queryResponse?.data?.payload?.data?.result ?? [], }, ], }); @@ -119,8 +114,7 @@ function ChartPreview({ {(queryResponse?.isError || queryResponse?.error) && ( {' '} - {(queryResponse?.error as QueryResponseError).message || - t('preview_chart_unexpected_error')} + {queryResponse.error.message || t('preview_chart_unexpected_error')} )} {queryResponse.isLoading && } diff --git a/frontend/src/container/GridGraphLayout/Graph/FullView/index.metricsBuilder.tsx b/frontend/src/container/GridGraphLayout/Graph/FullView/index.metricsBuilder.tsx index 04b35ee83b..1f5759f34b 100644 --- a/frontend/src/container/GridGraphLayout/Graph/FullView/index.metricsBuilder.tsx +++ b/frontend/src/container/GridGraphLayout/Graph/FullView/index.metricsBuilder.tsx @@ -7,16 +7,13 @@ import { timeItems, timePreferance, } from 'container/NewWidget/RightContainer/timeItems'; +import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange'; import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables'; import getChartData from 'lib/getChartData'; import { useCallback, useMemo, useState } from 'react'; -import { useQuery } from 'react-query'; import { useSelector } from 'react-redux'; -import { GetMetricQueryRange } from 'store/actions/dashboard/getQueryResults'; import { AppState } from 'store/reducers'; -import { ErrorResponse, SuccessResponse } from 'types/api'; import { Widgets } from 'types/api/dashboard/getAll'; -import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; import { GlobalReducer } from 'types/reducer/globalTime'; import { TimeContainer } from './styles'; @@ -44,18 +41,24 @@ function FullView({ name: getSelectedTime()?.name || '', enum: widget?.timePreferance || 'GLOBAL_TIME', }); - const response = useQuery< - SuccessResponse | ErrorResponse - >( - `FullViewGetMetricsQueryRange-${selectedTime.enum}-${globalSelectedTime}-${widget.id}`, + + const queryKey = useMemo( () => - GetMetricQueryRange({ - selectedTime: selectedTime.enum, - graphType: widget.panelTypes, - query: widget.query, - globalSelectedInterval: globalSelectedTime, - variables: getDashboardVariables(), - }), + `FullViewGetMetricsQueryRange-${selectedTime.enum}-${globalSelectedTime}-${widget.id}`, + [selectedTime, globalSelectedTime, widget], + ); + + const response = useGetQueryRange( + { + selectedTime: selectedTime.enum, + graphType: widget.panelTypes, + query: widget.query, + globalSelectedInterval: globalSelectedTime, + variables: getDashboardVariables(), + }, + { + queryKey, + }, ); const chartDataSet = useMemo( diff --git a/frontend/src/container/GridGraphLayout/Graph/index.tsx b/frontend/src/container/GridGraphLayout/Graph/index.tsx index c581f7f917..29390c7036 100644 --- a/frontend/src/container/GridGraphLayout/Graph/index.tsx +++ b/frontend/src/container/GridGraphLayout/Graph/index.tsx @@ -3,6 +3,7 @@ import { ChartData } from 'chart.js'; import Spinner from 'components/Spinner'; import GridGraphComponent from 'container/GridGraphComponent'; import { UpdateDashboard } from 'container/GridGraphLayout/utils'; +import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange'; import { useNotifications } from 'hooks/useNotifications'; import usePreviousValue from 'hooks/usePreviousValue'; import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables'; @@ -20,7 +21,6 @@ import { import { Layout } from 'react-grid-layout'; import { useTranslation } from 'react-i18next'; import { useInView } from 'react-intersection-observer'; -import { useQuery } from 'react-query'; import { connect, useSelector } from 'react-redux'; import { bindActionCreators } from 'redux'; import { ThunkDispatch } from 'redux-thunk'; @@ -28,7 +28,6 @@ import { DeleteWidget, DeleteWidgetProps, } from 'store/actions/dashboard/deleteWidget'; -import { GetMetricQueryRange } from 'store/actions/dashboard/getQueryResults'; import { AppState } from 'store/reducers'; import AppActions from 'types/actions'; import { Widgets } from 'types/api/dashboard/getAll'; @@ -81,33 +80,28 @@ function GridCardGraph({ const selectedData = selectedDashboard?.data; const { variables } = selectedData; - const queryResponse = useQuery( - [ - `GetMetricsQueryRange-${widget?.timePreferance}-${globalSelectedInterval}-${widget.id}`, - { + const queryResponse = useGetQueryRange( + { + selectedTime: widget?.timePreferance, + graphType: widget.panelTypes, + query: widget.query, + globalSelectedInterval, + variables: getDashboardVariables(), + }, + { + queryKey: [ + `GetMetricsQueryRange-${widget?.timePreferance}-${globalSelectedInterval}-${widget.id}`, widget, maxTime, minTime, globalSelectedInterval, variables, - }, - ], - () => - GetMetricQueryRange({ - selectedTime: widget?.timePreferance, - graphType: widget.panelTypes, - query: widget.query, - globalSelectedInterval, - variables: getDashboardVariables(), - }), - { + ], keepPreviousData: true, enabled: isGraphVisible, refetchOnMount: false, onError: (error) => { - if (error instanceof Error) { - setErrorMessage(error.message); - } + setErrorMessage(error.message); }, }, ); diff --git a/frontend/src/container/GridGraphLayout/utils.ts b/frontend/src/container/GridGraphLayout/utils.ts index 625557173f..1cef8eed7c 100644 --- a/frontend/src/container/GridGraphLayout/utils.ts +++ b/frontend/src/container/GridGraphLayout/utils.ts @@ -50,14 +50,6 @@ export const UpdateDashboard = async ( queryData: [initialQueryBuilderFormValues], }, }, - queryData: { - data: { - queryData: widgetData?.queryData.data.queryData || [], - }, - error: false, - errorMessage: '', - loading: false, - }, timePreferance: widgetData?.timePreferance || 'GLOBAL_TIME', title: widgetData ? copyTitle : '', }, diff --git a/frontend/src/container/ListOfDashboard/ImportJSON/index.tsx b/frontend/src/container/ListOfDashboard/ImportJSON/index.tsx index b737f7d0f9..3a7f406b4e 100644 --- a/frontend/src/container/ListOfDashboard/ImportJSON/index.tsx +++ b/frontend/src/container/ListOfDashboard/ImportJSON/index.tsx @@ -71,23 +71,8 @@ function ImportJSON({ setDashboardCreating(true); const dashboardData = JSON.parse(editorValue) as DashboardData; - // removing the queryData - const parsedWidgets: DashboardData = { - ...dashboardData, - widgets: dashboardData.widgets?.map((e) => ({ - ...e, - queryData: { - ...e.queryData, - data: e.queryData.data, - error: false, - errorMessage: '', - loading: false, - }, - })), - }; - const response = await createDashboard({ - ...parsedWidgets, + ...dashboardData, uploadedGrafana, }); diff --git a/frontend/src/container/MetricsApplication/MetricsApplication.factory.ts b/frontend/src/container/MetricsApplication/MetricsApplication.factory.ts index 82b3856f98..366dc864a6 100644 --- a/frontend/src/container/MetricsApplication/MetricsApplication.factory.ts +++ b/frontend/src/container/MetricsApplication/MetricsApplication.factory.ts @@ -10,12 +10,6 @@ export const getWidgetQueryBuilder = (query: Widgets['query']): Widgets => ({ opacity: '0', panelTypes: PANEL_TYPES.TIME_SERIES, query, - queryData: { - data: { queryData: [] }, - error: false, - errorMessage: '', - loading: false, - }, timePreferance: 'GLOBAL_TIME', title: '', }); diff --git a/frontend/src/container/NewDashboard/DescriptionOfDashboard/ShareModal.tsx b/frontend/src/container/NewDashboard/DescriptionOfDashboard/ShareModal.tsx index 51d83b23a3..d7ccd451e4 100644 --- a/frontend/src/container/NewDashboard/DescriptionOfDashboard/ShareModal.tsx +++ b/frontend/src/container/NewDashboard/DescriptionOfDashboard/ShareModal.tsx @@ -6,28 +6,14 @@ import { useTranslation } from 'react-i18next'; import { useCopyToClipboard } from 'react-use'; import { DashboardData } from 'types/api/dashboard/getAll'; -import { cleardQueryData, downloadObjectAsJson } from './util'; +import { downloadObjectAsJson } from './util'; function ShareModal({ isJSONModalVisible, onToggleHandler, selectedData, }: ShareModalProps): JSX.Element { - const getParsedValue = (): string => { - const updatedData: DashboardData = { - ...selectedData, - widgets: selectedData.widgets?.map((widget) => ({ - ...widget, - queryData: { - ...widget.queryData, - loading: false, - error: false, - errorMessage: '', - }, - })), - }; - return JSON.stringify(updatedData, null, 2); - }; + const getParsedValue = (): string => JSON.stringify(selectedData, null, 2); const [jsonValue, setJSONValue] = useState(getParsedValue()); const [isViewJSON, setIsViewJSON] = useState(false); @@ -53,7 +39,6 @@ function ShareModal({ } }, [state.error, state.value, t, notifications]); - const selectedDataCleaned = cleardQueryData(selectedData); const GetFooterComponent = useMemo(() => { if (!isViewJSON) { return ( @@ -69,7 +54,7 @@ function ShareModal({ ); - }, [isViewJSON, jsonValue, selectedData, selectedDataCleaned, setCopy, t]); + }, [isViewJSON, jsonValue, selectedData, setCopy, t]); return ( ({ - ...widget, - queryData: { - ...widget.queryData, - data: { - queryData: [], - }, - }, - })), - }; -} diff --git a/frontend/src/container/NewWidget/LeftContainer/QuerySection/index.tsx b/frontend/src/container/NewWidget/LeftContainer/QuerySection/index.tsx index 1d8cbd763b..655ecaaee7 100644 --- a/frontend/src/container/NewWidget/LeftContainer/QuerySection/index.tsx +++ b/frontend/src/container/NewWidget/LeftContainer/QuerySection/index.tsx @@ -1,11 +1,13 @@ import { Button, Tabs, Typography } from 'antd'; import TextToolTip from 'components/TextToolTip'; import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; +import { WidgetGraphProps } from 'container/NewWidget/types'; import { QueryBuilder } from 'container/QueryBuilder'; +import { useGetWidgetQueryRange } from 'hooks/queryBuilder/useGetWidgetQueryRange'; import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl'; import useUrlQuery from 'hooks/useUrlQuery'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback } from 'react'; import { connect, useSelector } from 'react-redux'; import { bindActionCreators, Dispatch } from 'redux'; import { ThunkDispatch } from 'redux-thunk'; @@ -23,16 +25,22 @@ import DashboardReducer from 'types/reducer/dashboards'; import ClickHouseQueryContainer from './QueryBuilder/clickHouse'; import PromQLQueryContainer from './QueryBuilder/promQL'; -function QuerySection({ updateQuery, selectedGraph }: QueryProps): JSX.Element { +function QuerySection({ + updateQuery, + selectedGraph, + selectedTime, +}: QueryProps): JSX.Element { const { currentQuery, redirectWithQueryBuilderData } = useQueryBuilder(); const urlQuery = useUrlQuery(); - const [isInit, setIsInit] = useState(false); + const { dashboards } = useSelector( + (state) => state.dashboards, + ); - const { dashboards, isLoadingQueryResult } = useSelector< - AppState, - DashboardReducer - >((state) => state.dashboards); + const getWidgetQueryRange = useGetWidgetQueryRange({ + graphType: selectedGraph, + selectedTime: selectedTime.enum, + }); const [selectedDashboards] = dashboards; const { widgets } = selectedDashboards.data; @@ -46,23 +54,11 @@ function QuerySection({ updateQuery, selectedGraph }: QueryProps): JSX.Element { const { query } = selectedWidget; - const { compositeQuery } = useShareBuilderUrl({ defaultValue: query }); - - useEffect(() => { - if (!isInit && compositeQuery) { - setIsInit(true); - updateQuery({ - updatedQuery: compositeQuery, - widgetId: urlQuery.get('widgetId') || '', - yAxisUnit: selectedWidget.yAxisUnit, - }); - } - }, [isInit, compositeQuery, selectedWidget, urlQuery, updateQuery]); + useShareBuilderUrl({ defaultValue: query }); const handleStageQuery = useCallback( (updatedQuery: Query): void => { updateQuery({ - updatedQuery, widgetId: urlQuery.get('widgetId') || '', yAxisUnit: selectedWidget.yAxisUnit, }); @@ -115,7 +111,7 @@ function QuerySection({ updateQuery, selectedGraph }: QueryProps): JSX.Element { @@ -95,7 +91,7 @@ function QuerySection({ onChange={handleQueryCategoryChange} tabBarExtraContent={ - @@ -132,7 +128,7 @@ interface QuerySectionProps { queryCategory: EQueryType; setQueryCategory: (n: EQueryType) => void; alertType: AlertTypes; - runQuery: () => void; + runQuery: VoidFunction; } export default QuerySection; diff --git a/frontend/src/hooks/queryBuilder/useGetQueryRange.ts b/frontend/src/hooks/queryBuilder/useGetQueryRange.ts index dbd35d5ede..7091ffb15b 100644 --- a/frontend/src/hooks/queryBuilder/useGetQueryRange.ts +++ b/frontend/src/hooks/queryBuilder/useGetQueryRange.ts @@ -1,5 +1,7 @@ import { REACT_QUERY_KEY } from 'constants/reactQueryKeys'; +import { useMemo } from 'react'; import { useQuery, UseQueryOptions, UseQueryResult } from 'react-query'; +import { useLocation } from 'react-router-dom'; import { GetMetricQueryRange, GetQueryResultsProps, @@ -10,9 +12,19 @@ import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; export const useGetQueryRange = ( requestData: GetQueryResultsProps, options?: UseQueryOptions, Error>, -): UseQueryResult, Error> => - useQuery, Error>({ - queryKey: [REACT_QUERY_KEY.GET_QUERY_RANGE, requestData], +): UseQueryResult, Error> => { + const { key } = useLocation(); + + const queryKey = useMemo(() => { + if (options?.queryKey) { + return [...options.queryKey, key]; + } + return [REACT_QUERY_KEY.GET_QUERY_RANGE, key, requestData]; + }, [key, options?.queryKey, requestData]); + + return useQuery, Error>({ queryFn: async () => GetMetricQueryRange(requestData), ...options, + queryKey, }); +}; From 8433d81dc04572b87f019fcab09132e28a033098 Mon Sep 17 00:00:00 2001 From: Chintan Sudani <46838508+techchintan@users.noreply.github.com> Date: Wed, 14 Jun 2023 12:53:50 +0530 Subject: [PATCH 17/37] fix: alert name required message & button disabled (#2896) * fix: alert name required message & button disabled * fix: tooltip message issue * fix: button disabled issue while create alert * chore: requiredMessage is updated --------- Co-authored-by: Palash Gupta --- .../container/FormAlertRules/BasicInfo.tsx | 15 ++++++++++--- .../src/container/FormAlertRules/index.tsx | 21 +++++-------------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/frontend/src/container/FormAlertRules/BasicInfo.tsx b/frontend/src/container/FormAlertRules/BasicInfo.tsx index f4d99126ec..595e6facd6 100644 --- a/frontend/src/container/FormAlertRules/BasicInfo.tsx +++ b/frontend/src/container/FormAlertRules/BasicInfo.tsx @@ -1,6 +1,7 @@ import { Form, Select } from 'antd'; import { useTranslation } from 'react-i18next'; import { AlertDef, Labels } from 'types/api/alerts/def'; +import { requireErrorMessage } from 'utils/form/requireErrorMessage'; import ChannelSelect from './ChannelSelect'; import LabelSelect from './labels'; @@ -54,7 +55,15 @@ function BasicInfo({ alertDef, setAlertDef }: BasicInfoProps): JSX.Element { - + { setAlertDef({ @@ -97,10 +106,10 @@ function BasicInfo({ alertDef, setAlertDef }: BasicInfoProps): JSX.Element { { + onSelectChannels={(preferredChannels): void => { setAlertDef({ ...alertDef, - preferredChannels: s, + preferredChannels, }); }} /> diff --git a/frontend/src/container/FormAlertRules/index.tsx b/frontend/src/container/FormAlertRules/index.tsx index f131fe60ba..9eec5ad9d0 100644 --- a/frontend/src/container/FormAlertRules/index.tsx +++ b/frontend/src/container/FormAlertRules/index.tsx @@ -201,10 +201,6 @@ function FormAlertRules({ const isFormValid = useCallback((): boolean => { if (!alertDef.alert || alertDef.alert === '') { - notifications.error({ - message: 'Error', - description: t('alertname_required'), - }); return false; } @@ -217,14 +213,7 @@ function FormAlertRules({ } return validateQBParams(); - }, [ - t, - validateQBParams, - validateChQueryParams, - alertDef, - validatePromParams, - notifications, - ]); + }, [validateQBParams, validateChQueryParams, alertDef, validatePromParams]); const preparePostData = (): AlertDef => { const postableAlert: AlertDef = { @@ -328,9 +317,7 @@ function FormAlertRules({ title: t('confirm_save_title'), centered: true, content, - onOk() { - saveRule(); - }, + onOk: saveRule, }); }, [t, saveRule, currentQuery]); @@ -407,6 +394,8 @@ function FormAlertRules({ const isNewRule = ruleId === 0; + const isAlertNameMissing = !formInstance.getFieldValue('alert'); + const isAlertAvialableToSave = isAlertAvialable && isNewRule && @@ -448,7 +437,7 @@ function FormAlertRules({ type="primary" onClick={onSaveHandler} icon={} - disabled={isAlertAvialableToSave} + disabled={isAlertNameMissing || isAlertAvialableToSave} > {isNewRule ? t('button_createrule') : t('button_savechanges')} From 52a222e87a204500b62cb906254c1e5954f0c31a Mon Sep 17 00:00:00 2001 From: Palash Gupta Date: Wed, 14 Jun 2023 20:11:40 +0530 Subject: [PATCH 18/37] feat: added the contribution guidelines (#2850) --- frontend/CONTRIBUTIONS.md | 56 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 frontend/CONTRIBUTIONS.md diff --git a/frontend/CONTRIBUTIONS.md b/frontend/CONTRIBUTIONS.md new file mode 100644 index 0000000000..0b3d76219c --- /dev/null +++ b/frontend/CONTRIBUTIONS.md @@ -0,0 +1,56 @@ +# **Frontend Guidelines** + +Embrace the spirit of collaboration and contribute to the success of our open-source project by adhering to these frontend development guidelines with precision and passion. + +### React and Components + +- Strive to create small and modular components, ensuring they are divided into individual pieces for improved maintainability and reusability. +- Avoid passing inline objects or functions as props to React components, as they are recreated with each render cycle. + Utilize careful memoization of functions and variables, balancing optimization efforts to prevent potential performance issues. [When to useMemo and useCallback](https://kentcdodds.com/blog/usememo-and-usecallback) by Kent C. Dodds is quite helpful for this scenario. +- Minimize the use of inline functions whenever possible to enhance code readability and improve overall comprehension. +- Employ the appropriate usage of useMemo and useCallback hooks for effective memoization of values and functions. +- Determine the appropriate placement of components: + - Pages should contain an aggregation of all components and containers. + - Commonly used components should reside in the 'components' directory. + - Parent components responsible for data manipulation should be placed in the 'container' directory. +- Strategically decide where to store data, either in global state or local components: + - Begin by storing data in local components and gradually transition to global state as necessary. +- Avoid importing default namespace `React` as the project is using `v18` and `import React from 'react'` is not needed anymore. +- When a function requires more than three arguments (except when memoized), encapsulate them within an object to enhance readability and reduce potential parameter complexity. + +### API and Services + +- Avoid incorporating business logic within API/Service files to maintain flexibility for consumers to handle it according to their specific needs. +- Employ the use of the useQuery hook for fetching data and the useMutation hook for updating data, ensuring a consistent and efficient approach. +- Utilize the useQueryClient hook when updating the cache, facilitating smooth and effective management of data within the application. + +**Note -** In our project, we are utilizing React Query v3. To gain a comprehensive understanding of its features and implementation, we recommend referring to the [official documentation](https://tanstack.com/query/v3/docs/react/overview) as a valuable resource. + +### Styling + +- Refrain from using inline styling within React components to maintain separation of concerns and promote a more maintainable codebase. +- Opt for using the rem unit instead of px values to ensure better scalability and responsiveness across different devices and screen sizes. + +### Linting and Setup + +- It is crucial to refrain from disabling ESLint and TypeScript errors within the project. If there is a specific rule that needs to be disabled, provide a clear and justified explanation for doing so. Maintaining the integrity of the linting and type-checking processes ensures code quality and consistency throughout the codebase. +- In our project, we rely on several essential ESLint plugins, namely: + - [plugin:@typescript-eslint](https://typescript-eslint.io/rules/) + - [airbnb styleguide](https://github.com/airbnb/javascript) + - [plugin:sonarjs](https://github.com/SonarSource/eslint-plugin-sonarjs) + + To ensure compliance with our coding standards and best practices, we encourage you to refer to the documentation of these plugins. Familiarizing yourself with the ESLint rules they provide will help maintain code quality and consistency throughout the project. + +### Naming Conventions + +- Ensure that component names are written in Capital Case, while the folder names should be in lowercase. +- Keep all other elements, such as variables, functions, and file names, in lowercase. + +### Miscellaneous + +- Ensure that functions are modularized and follow the Single Responsibility Principle (SRP). The function's name should accurately convey its purpose and functionality. +- Semantic division of functions into smaller units should be prioritized for improved readability and maintainability. + Aim to keep functions concise and avoid exceeding a maximum length of 40 lines to enhance code understandability and ease of maintenance. +- Eliminate the use of hard-coded strings or enums, favoring a more flexible and maintainable approach. +- Strive to internationalize all strings within the codebase to support localization and improve accessibility for users across different languages. +- Minimize the usage of multiple if statements or switch cases within a function. Consider creating a mapper and separating logic into multiple functions for better code organization. From 9ad17c2d60380ec38ff0e6f571f3ac0f3d50466e Mon Sep 17 00:00:00 2001 From: Palash Gupta Date: Thu, 15 Jun 2023 11:15:25 +0530 Subject: [PATCH 19/37] fix: handling of 404 in dashboard is updated (#2908) --- frontend/src/api/ErrorResponseHandler.ts | 2 +- frontend/src/pages/NewDashboard/index.tsx | 14 +++++++++++++- frontend/src/types/common/index.ts | 4 ++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/frontend/src/api/ErrorResponseHandler.ts b/frontend/src/api/ErrorResponseHandler.ts index 060b93493f..2c42f0951b 100644 --- a/frontend/src/api/ErrorResponseHandler.ts +++ b/frontend/src/api/ErrorResponseHandler.ts @@ -16,7 +16,7 @@ export function ErrorResponseHandler(error: AxiosError): ErrorResponse { return { statusCode, payload: null, - error: 'Not Found', + error: data.errorType, message: null, }; } diff --git a/frontend/src/pages/NewDashboard/index.tsx b/frontend/src/pages/NewDashboard/index.tsx index 2183531f63..6d64ca500f 100644 --- a/frontend/src/pages/NewDashboard/index.tsx +++ b/frontend/src/pages/NewDashboard/index.tsx @@ -1,3 +1,5 @@ +import { Typography } from 'antd'; +import NotFound from 'components/NotFound'; import Spinner from 'components/Spinner'; import NewDashboard from 'container/NewDashboard'; import { useEffect } from 'react'; @@ -8,6 +10,7 @@ import { ThunkDispatch } from 'redux-thunk'; import { GetDashboard, GetDashboardProps } from 'store/actions/dashboard'; import { AppState } from 'store/reducers'; import AppActions from 'types/actions'; +import { ErrorType } from 'types/common'; import DashboardReducer from 'types/reducer/dashboards'; function NewDashboardPage({ getDashboard }: NewDashboardProps): JSX.Element { @@ -26,8 +29,17 @@ function NewDashboardPage({ getDashboard }: NewDashboardProps): JSX.Element { } }, [getDashboard, dashboardId, dashboards.length]); + if ( + error && + !loading && + dashboards.length === 0 && + errorMessage === ErrorType.NotFound + ) { + return ; + } + if (error && !loading && dashboards.length === 0) { - return
{errorMessage}
; + return {errorMessage}; } // when user comes from dashboard page. dashboard array is populated with some dashboard as dashboard is populated diff --git a/frontend/src/types/common/index.ts b/frontend/src/types/common/index.ts index c32bc6f44b..9e68e1173e 100644 --- a/frontend/src/types/common/index.ts +++ b/frontend/src/types/common/index.ts @@ -25,4 +25,8 @@ export type ErrorStatusCode = | BadRequest | Conflict; +export enum ErrorType { + NotFound = 'not_found', +} + export type StatusCode = SuccessStatusCode | ErrorStatusCode; From 389385324fdc53ec134a4920a375361c7eed6e6d Mon Sep 17 00:00:00 2001 From: Palash Gupta Date: Thu, 15 Jun 2023 12:52:31 +0530 Subject: [PATCH 20/37] fix: clone panel permission is updated (#2915) --- frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx b/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx index 10628aee7a..30390c2824 100644 --- a/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx +++ b/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx @@ -126,7 +126,7 @@ function WidgetHeader({ { key: keyMethodMapping.clone.key, icon: , - disabled: false, + disabled: !editWidget, label: 'Clone', }, { From 3792f137fa748c9c964b5b20988efb9c1dbf4f56 Mon Sep 17 00:00:00 2001 From: Palash Gupta Date: Thu, 15 Jun 2023 14:13:58 +0530 Subject: [PATCH 21/37] fix: new widget condition is fixed and handling of undefined is done (#2906) --- .../container/GridGraphLayout/Graph/index.tsx | 16 ++++++++-------- frontend/src/container/GridGraphLayout/index.tsx | 3 +-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/frontend/src/container/GridGraphLayout/Graph/index.tsx b/frontend/src/container/GridGraphLayout/Graph/index.tsx index 29390c7036..53d8ad4180 100644 --- a/frontend/src/container/GridGraphLayout/Graph/index.tsx +++ b/frontend/src/container/GridGraphLayout/Graph/index.tsx @@ -83,14 +83,14 @@ function GridCardGraph({ const queryResponse = useGetQueryRange( { selectedTime: widget?.timePreferance, - graphType: widget.panelTypes, - query: widget.query, + graphType: widget?.panelTypes, + query: widget?.query, globalSelectedInterval, variables: getDashboardVariables(), }, { queryKey: [ - `GetMetricsQueryRange-${widget?.timePreferance}-${globalSelectedInterval}-${widget.id}`, + `GetMetricsQueryRange-${widget?.timePreferance}-${globalSelectedInterval}-${widget?.id}`, widget, maxTime, minTime, @@ -173,7 +173,7 @@ function GridCardGraph({ { data: selectedDashboard.data, generateWidgetId: uuid, - graphType: widget.panelTypes, + graphType: widget?.panelTypes, selectedDashboard, layout, widgetData: widget, @@ -187,7 +187,7 @@ function GridCardGraph({ setTimeout(() => { history.push( - `${history.location.pathname}/new?graphType=${widget.panelTypes}&widgetId=${uuid}`, + `${history.location.pathname}/new?graphType=${widget?.panelTypes}&widgetId=${uuid}`, ); }, 1500); }); @@ -253,10 +253,10 @@ function GridCardGraph({ /> ( (state) => state.app, From 86c6c43f954dcd7c17d1ffa1e7ba249cafc503c2 Mon Sep 17 00:00:00 2001 From: Rajat Dabade Date: Thu, 15 Jun 2023 17:48:55 +0530 Subject: [PATCH 22/37] fix: updated redirect link for try signoz cloud button (#2919) Co-authored-by: Palash Gupta --- frontend/src/container/Header/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/container/Header/index.tsx b/frontend/src/container/Header/index.tsx index d3dcb52c99..93bb6c08f3 100644 --- a/frontend/src/container/Header/index.tsx +++ b/frontend/src/container/Header/index.tsx @@ -91,7 +91,7 @@ function HeaderContainer(): JSX.Element { const onClickSignozCloud = (): void => { window.open( - 'https://signoz.io/pricing/?utm_source=product_navbar&utm_medium=frontend', + 'https://signoz.io/teams/?utm_source=product_navbar&utm_medium=frontend', '_blank', ); }; From 9aa8148269765496c694acb9ac57785602a5f0ff Mon Sep 17 00:00:00 2001 From: Palash Gupta Date: Thu, 15 Jun 2023 19:46:08 +0530 Subject: [PATCH 23/37] fix: updating dashboard variables is not allowed for viewer role (#2910) Co-authored-by: Prashant Shahi --- .../DashboardVariablesSelection/index.tsx | 24 ++++++++++--------- .../types/api/dashboard/variables/query.ts | 4 +++- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/frontend/src/container/NewDashboard/DashboardVariablesSelection/index.tsx b/frontend/src/container/NewDashboard/DashboardVariablesSelection/index.tsx index 67d961f5c9..d318e684f8 100644 --- a/frontend/src/container/NewDashboard/DashboardVariablesSelection/index.tsx +++ b/frontend/src/container/NewDashboard/DashboardVariablesSelection/index.tsx @@ -10,6 +10,7 @@ import { UpdateDashboardVariables } from 'store/actions/dashboard/updatedDashboa import { AppState } from 'store/reducers'; import AppActions from 'types/actions'; import { IDashboardVariable } from 'types/api/dashboard/getAll'; +import AppReducer from 'types/reducer/app'; import DashboardReducer from 'types/reducer/dashboards'; import VariableItem from './VariableItem'; @@ -29,6 +30,8 @@ function DashboardVariableSelection({ const [lastUpdatedVar, setLastUpdatedVar] = useState(''); const { notifications } = useNotifications(); + const { role } = useSelector((state) => state.app); + const onVarChanged = (name: string): void => { setLastUpdatedVar(name); setUpdate(!update); @@ -36,19 +39,15 @@ function DashboardVariableSelection({ const onValueUpdate = ( name: string, - value: - | string - | string[] - | number - | number[] - | boolean - | boolean[] - | null - | undefined, + value: IDashboardVariable['selectedValue'], ): void => { const updatedVariablesData = { ...variables }; updatedVariablesData[name].selectedValue = value; - updateDashboardVariables(updatedVariablesData, notifications); + + if (role !== 'VIEWER') { + updateDashboardVariables(updatedVariablesData, notifications); + } + onVarChanged(name); }; const onAllSelectedUpdate = ( @@ -57,7 +56,10 @@ function DashboardVariableSelection({ ): void => { const updatedVariablesData = { ...variables }; updatedVariablesData[name].allSelected = value; - updateDashboardVariables(updatedVariablesData, notifications); + + if (role !== 'VIEWER') { + updateDashboardVariables(updatedVariablesData, notifications); + } onVarChanged(name); }; diff --git a/frontend/src/types/api/dashboard/variables/query.ts b/frontend/src/types/api/dashboard/variables/query.ts index 4fe305600e..c535ad72be 100644 --- a/frontend/src/types/api/dashboard/variables/query.ts +++ b/frontend/src/types/api/dashboard/variables/query.ts @@ -1,6 +1,8 @@ +import { IDashboardVariable } from '../getAll'; + export type PayloadVariables = Record< string, - undefined | null | string | number | boolean | (string | number | boolean)[] + IDashboardVariable['selectedValue'] >; export type Props = { From 82936f73a3720d028f96653bd868b03ad14388da Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Fri, 16 Jun 2023 00:06:01 +0530 Subject: [PATCH 24/37] chore: update Makefile (#2917) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(docker-buildkit): 🐛 use progress plain * chore(Makefile): add targets for clearing only clickhouse data --------- Signed-off-by: Prashant Shahi --- Makefile | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 0c22db72d6..bef8c8bce7 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ build-push-frontend: @echo "--> Building and pushing frontend docker image" @echo "------------------" @cd $(FRONTEND_DIRECTORY) && \ - docker buildx build --file Dockerfile --progress plane --push --platform linux/arm64,linux/amd64 \ + docker buildx build --file Dockerfile --progress plain --push --platform linux/arm64,linux/amd64 \ --tag $(REPONAME)/$(FRONTEND_DOCKER_IMAGE):$(DOCKER_TAG) . # Steps to build and push docker image of query service @@ -73,7 +73,7 @@ build-push-query-service: @echo "------------------" @echo "--> Building and pushing query-service docker image" @echo "------------------" - @docker buildx build --file $(QUERY_SERVICE_DIRECTORY)/Dockerfile --progress plane \ + @docker buildx build --file $(QUERY_SERVICE_DIRECTORY)/Dockerfile --progress plain \ --push --platform linux/arm64,linux/amd64 --build-arg LD_FLAGS="$(LD_FLAGS)" \ --tag $(REPONAME)/$(QUERY_SERVICE_DOCKER_IMAGE):$(DOCKER_TAG) . @@ -98,7 +98,7 @@ build-push-ee-query-service: @echo "--> Building and pushing query-service docker image" @echo "------------------" @docker buildx build --file $(EE_QUERY_SERVICE_DIRECTORY)/Dockerfile \ - --progress plane --push --platform linux/arm64,linux/amd64 \ + --progress plain --push --platform linux/arm64,linux/amd64 \ --build-arg LD_FLAGS="$(LD_FLAGS)" --tag $(REPONAME)/$(QUERY_SERVICE_DOCKER_IMAGE):$(DOCKER_TAG) . dev-setup: @@ -136,6 +136,14 @@ clear-swarm-data: @docker run --rm -v "$(PWD)/$(SWARM_DIRECTORY)/data:/pwd" busybox \ sh -c "cd /pwd && rm -rf alertmanager/* clickhouse*/* signoz/* zookeeper-*/*" +clear-standalone-ch: + @docker run --rm -v "$(PWD)/$(STANDALONE_DIRECTORY)/data:/pwd" busybox \ + sh -c "cd /pwd && rm -rf clickhouse*/* zookeeper-*/*" + +clear-swarm-ch: + @docker run --rm -v "$(PWD)/$(SWARM_DIRECTORY)/data:/pwd" busybox \ + sh -c "cd /pwd && rm -rf clickhouse*/* zookeeper-*/*" + test: go test ./pkg/query-service/app/metrics/... go test ./pkg/query-service/cache/... From 5bdb0e84d1e7b98e88edccc96a478dd41ffbab32 Mon Sep 17 00:00:00 2001 From: Yevhen Shevchenko <90138953+yeshev@users.noreply.github.com> Date: Fri, 16 Jun 2023 13:38:39 +0300 Subject: [PATCH 25/37] Feat/logs explorer (#2905) * feat: add query builder and graph * feat: add graph * fix: id in the another places * fix: multiple queries for explorer logs * chore: chunkName is updated --------- Co-authored-by: Chintan Sudani <46838508+techchintan@users.noreply.github.com> Co-authored-by: Palash Gupta --- frontend/src/AppRoutes/pageComponents.ts | 4 + frontend/src/AppRoutes/routes.ts | 8 + frontend/src/constants/queryBuilder.ts | 59 ++++- .../src/constants/queryBuilderQueryNames.ts | 1 + frontend/src/constants/routes.ts | 1 + frontend/src/constants/theme.ts | 3 + .../src/container/CreateAlertRule/defaults.ts | 27 +-- .../src/container/CreateAlertRule/index.tsx | 21 +- .../FormAlertRules/ChartPreview/index.tsx | 14 +- .../src/container/FormAlertRules/index.tsx | 42 +--- .../src/container/GridGraphLayout/utils.ts | 17 +- .../LogsExplorerChart.styled.ts | 11 + .../LogsExplorerChart/LogsExplorerChart.tsx | 66 ++++++ .../src/container/LogsExplorerChart/index.ts | 1 + .../LogsExplorerViews.styled.ts | 9 + .../LogsExplorerViews/LogsExplorerViews.tsx | 75 ++++++ .../src/container/LogsExplorerViews/index.ts | 1 + .../MetricsPageQueriesFactory.ts | 8 +- .../MetricsApplication/Tabs/DBCall.tsx | 3 + .../MetricsApplication/Tabs/External.tsx | 5 + .../MetricsApplication/Tabs/Overview.tsx | 3 + .../NewDashboard/ComponentsSlider/index.tsx | 4 +- .../QueryBuilder/QueryBuilder.interfaces.ts | 2 + .../QueryBuilder/QueryBuilder.styled.ts | 6 + .../container/QueryBuilder/QueryBuilder.tsx | 57 +++-- .../HavingFilter/__tests__/utils.test.tsx | 16 +- frontend/src/container/SideNav/menuItems.tsx | 20 +- .../container/TopNav/Breadcrumbs/index.tsx | 1 + .../queryBuilder/useGetCompositeQueryParam.ts | 14 ++ .../useGetPanelTypesQueryParam.ts | 16 ++ .../hooks/queryBuilder/useGetQueryRange.ts | 13 +- .../hooks/queryBuilder/useQueryOperations.ts | 23 +- .../hooks/queryBuilder/useShareBuilderUrl.ts | 25 +- .../src/lib/explorer/getExplorerChartData.ts | 46 ++++ .../getOperatorsBySourceAndPanelType.ts | 5 + .../mapQueryDataFromApi.ts | 10 +- .../transformQueryBuilderDataModel.ts | 4 +- frontend/src/pages/LogsExplorer/index.tsx | 45 ++++ frontend/src/pages/LogsExplorer/styles.ts | 11 + frontend/src/providers/QueryBuilder.tsx | 215 ++++++++++-------- .../store/actions/dashboard/getDashboard.ts | 4 +- .../actions/dashboard/getQueryResults.ts | 1 + .../api/queryBuilder/queryBuilderData.ts | 1 + frontend/src/types/common/queryBuilder.ts | 12 +- frontend/src/utils/permission/index.ts | 1 + 45 files changed, 644 insertions(+), 287 deletions(-) create mode 100644 frontend/src/container/LogsExplorerChart/LogsExplorerChart.styled.ts create mode 100644 frontend/src/container/LogsExplorerChart/LogsExplorerChart.tsx create mode 100644 frontend/src/container/LogsExplorerChart/index.ts create mode 100644 frontend/src/container/LogsExplorerViews/LogsExplorerViews.styled.ts create mode 100644 frontend/src/container/LogsExplorerViews/LogsExplorerViews.tsx create mode 100644 frontend/src/container/LogsExplorerViews/index.ts create mode 100644 frontend/src/container/QueryBuilder/QueryBuilder.styled.ts create mode 100644 frontend/src/hooks/queryBuilder/useGetCompositeQueryParam.ts create mode 100644 frontend/src/hooks/queryBuilder/useGetPanelTypesQueryParam.ts create mode 100644 frontend/src/lib/explorer/getExplorerChartData.ts create mode 100644 frontend/src/pages/LogsExplorer/index.tsx create mode 100644 frontend/src/pages/LogsExplorer/styles.ts diff --git a/frontend/src/AppRoutes/pageComponents.ts b/frontend/src/AppRoutes/pageComponents.ts index 0b241fa121..d6f67f11df 100644 --- a/frontend/src/AppRoutes/pageComponents.ts +++ b/frontend/src/AppRoutes/pageComponents.ts @@ -101,6 +101,10 @@ export const Logs = Loadable( () => import(/* webpackChunkName: "Logs" */ 'pages/Logs'), ); +export const LogsExplorer = Loadable( + () => import(/* webpackChunkName: "Logs Explorer" */ 'pages/LogsExplorer'), +); + export const Login = Loadable( () => import(/* webpackChunkName: "Login" */ 'pages/Login'), ); diff --git a/frontend/src/AppRoutes/routes.ts b/frontend/src/AppRoutes/routes.ts index 7210fd5928..d31b457c03 100644 --- a/frontend/src/AppRoutes/routes.ts +++ b/frontend/src/AppRoutes/routes.ts @@ -16,6 +16,7 @@ import { ListAllALertsPage, Login, Logs, + LogsExplorer, MySettings, NewDashboardPage, OrganizationSettings, @@ -209,6 +210,13 @@ const routes: AppRoutes[] = [ key: 'LOGS', isPrivate: true, }, + { + path: ROUTES.LOGS_EXPLORER, + exact: true, + component: LogsExplorer, + key: 'LOGS_EXPLORER', + isPrivate: true, + }, { path: ROUTES.LOGIN, exact: true, diff --git a/frontend/src/constants/queryBuilder.ts b/frontend/src/constants/queryBuilder.ts index a31397dd3c..0ac5de8030 100644 --- a/frontend/src/constants/queryBuilder.ts +++ b/frontend/src/constants/queryBuilder.ts @@ -1,5 +1,6 @@ // ** Helpers import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; +import { createIdFromObjectFields } from 'lib/createIdFromObjectFields'; import { createNewBuilderItemName } from 'lib/newQueryBuilder/createNewBuilderItemName'; import { BaseAutocompleteData, @@ -18,6 +19,7 @@ import { EQueryType } from 'types/common/dashboard'; import { BoolOperators, DataSource, + LogsAggregatorOperator, MetricAggregateOperator, NumberOperators, PanelTypeKeys, @@ -25,6 +27,7 @@ import { QueryBuilderData, ReduceOperators, StringOperators, + TracesAggregatorOperator, } from 'types/common/queryBuilder'; import { SelectOption } from 'types/common/select'; import { v4 as uuid } from 'uuid'; @@ -100,14 +103,17 @@ export const initialHavingValues: HavingForm = { }; export const initialAutocompleteData: BaseAutocompleteData = { - id: uuid(), + id: createIdFromObjectFields( + { dataType: null, key: '', isColumn: null, type: null }, + baseAutoCompleteIdKeysOrder, + ), dataType: null, key: '', isColumn: null, type: null, }; -export const initialQueryBuilderFormValues: IBuilderQuery = { +const initialQueryBuilderFormValues: IBuilderQuery = { dataSource: DataSource.METRICS, queryName: createNewBuilderItemName({ existNames: [], sourceNames: alphabet }), aggregateOperator: MetricAggregateOperator.NOOP, @@ -127,6 +133,27 @@ export const initialQueryBuilderFormValues: IBuilderQuery = { reduceTo: 'sum', }; +const initialQueryBuilderFormLogsValues: IBuilderQuery = { + ...initialQueryBuilderFormValues, + aggregateOperator: LogsAggregatorOperator.COUNT, + dataSource: DataSource.LOGS, +}; + +const initialQueryBuilderFormTracesValues: IBuilderQuery = { + ...initialQueryBuilderFormValues, + aggregateOperator: TracesAggregatorOperator.COUNT, + dataSource: DataSource.TRACES, +}; + +export const initialQueryBuilderFormValuesMap: Record< + DataSource, + IBuilderQuery +> = { + metrics: initialQueryBuilderFormValues, + logs: initialQueryBuilderFormLogsValues, + traces: initialQueryBuilderFormTracesValues, +}; + export const initialFormulaBuilderFormValues: IBuilderFormula = { queryName: createNewBuilderItemName({ existNames: [], @@ -161,17 +188,39 @@ export const initialSingleQueryMap: Record< IClickHouseQuery | IPromQLQuery > = { clickhouse_sql: initialClickHouseData, promql: initialQueryPromQLData }; -export const initialQuery: QueryState = { +export const initialQueryState: QueryState = { + id: uuid(), builder: initialQueryBuilderData, clickhouse_sql: [initialClickHouseData], promql: [initialQueryPromQLData], }; -export const initialQueryWithType: Query = { - ...initialQuery, +const initialQueryWithType: Query = { + ...initialQueryState, queryType: EQueryType.QUERY_BUILDER, }; +const initialQueryLogsWithType: Query = { + ...initialQueryWithType, + builder: { + ...initialQueryWithType.builder, + queryData: [initialQueryBuilderFormValuesMap.logs], + }, +}; +const initialQueryTracesWithType: Query = { + ...initialQueryWithType, + builder: { + ...initialQueryWithType.builder, + queryData: [initialQueryBuilderFormValuesMap.traces], + }, +}; + +export const initialQueriesMap: Record = { + metrics: initialQueryWithType, + logs: initialQueryLogsWithType, + traces: initialQueryTracesWithType, +}; + export const operatorsByTypes: Record = { string: Object.values(StringOperators), number: Object.values(NumberOperators), diff --git a/frontend/src/constants/queryBuilderQueryNames.ts b/frontend/src/constants/queryBuilderQueryNames.ts index cf668b7ef3..5a9e9dbfe9 100644 --- a/frontend/src/constants/queryBuilderQueryNames.ts +++ b/frontend/src/constants/queryBuilderQueryNames.ts @@ -1 +1,2 @@ export const COMPOSITE_QUERY = 'compositeQuery'; +export const PANEL_TYPES_QUERY = 'panelTypes'; diff --git a/frontend/src/constants/routes.ts b/frontend/src/constants/routes.ts index b618dda805..fb1ab7609f 100644 --- a/frontend/src/constants/routes.ts +++ b/frontend/src/constants/routes.ts @@ -27,6 +27,7 @@ const ROUTES = { UN_AUTHORIZED: '/un-authorized', NOT_FOUND: '/not-found', LOGS: '/logs', + LOGS_EXPLORER: '/logs-explorer', HOME_PAGE: '/', PASSWORD_RESET: '/password-reset', LIST_LICENSES: '/licenses', diff --git a/frontend/src/constants/theme.ts b/frontend/src/constants/theme.ts index ce6cdd354a..c6c1b0b32b 100644 --- a/frontend/src/constants/theme.ts +++ b/frontend/src/constants/theme.ts @@ -36,8 +36,11 @@ const themeColors = { royalGrey: '#888888', matterhornGrey: '#555555', whiteCream: '#ffffffd5', + white: '#ffffff', black: '#000000', + lightBlack: '#141414', lightgrey: '#ddd', + lightWhite: '#ffffffd9', borderLightGrey: '#d9d9d9', borderDarkGrey: '#424242', }; diff --git a/frontend/src/container/CreateAlertRule/defaults.ts b/frontend/src/container/CreateAlertRule/defaults.ts index 523997c2a3..ce73dda62b 100644 --- a/frontend/src/container/CreateAlertRule/defaults.ts +++ b/frontend/src/container/CreateAlertRule/defaults.ts @@ -1,5 +1,5 @@ import { - initialQueryBuilderFormValues, + initialQueryBuilderFormValuesMap, initialQueryPromQLData, PANEL_TYPES, } from 'constants/queryBuilder'; @@ -11,11 +11,6 @@ import { defaultMatchType, } from 'types/api/alerts/def'; import { EQueryType } from 'types/common/dashboard'; -import { - DataSource, - LogsAggregatorOperator, - TracesAggregatorOperator, -} from 'types/common/queryBuilder'; const defaultAlertDescription = 'This alert is fired when the defined metric (current value: {{$value}}) crosses the threshold ({{$threshold}})'; @@ -32,7 +27,7 @@ export const alertDefaults: AlertDef = { condition: { compositeQuery: { builderQueries: { - A: initialQueryBuilderFormValues, + A: initialQueryBuilderFormValuesMap.metrics, }, promQueries: { A: initialQueryPromQLData }, chQueries: { @@ -61,11 +56,7 @@ export const logAlertDefaults: AlertDef = { condition: { compositeQuery: { builderQueries: { - A: { - ...initialQueryBuilderFormValues, - aggregateOperator: LogsAggregatorOperator.COUNT, - dataSource: DataSource.LOGS, - }, + A: initialQueryBuilderFormValuesMap.logs, }, promQueries: { A: initialQueryPromQLData }, chQueries: { @@ -95,11 +86,7 @@ export const traceAlertDefaults: AlertDef = { condition: { compositeQuery: { builderQueries: { - A: { - ...initialQueryBuilderFormValues, - aggregateOperator: TracesAggregatorOperator.COUNT, - dataSource: DataSource.TRACES, - }, + A: initialQueryBuilderFormValuesMap.traces, }, promQueries: { A: initialQueryPromQLData }, chQueries: { @@ -129,11 +116,7 @@ export const exceptionAlertDefaults: AlertDef = { condition: { compositeQuery: { builderQueries: { - A: { - ...initialQueryBuilderFormValues, - aggregateOperator: TracesAggregatorOperator.COUNT, - dataSource: DataSource.TRACES, - }, + A: initialQueryBuilderFormValuesMap.traces, }, promQueries: { A: initialQueryPromQLData }, chQueries: { diff --git a/frontend/src/container/CreateAlertRule/index.tsx b/frontend/src/container/CreateAlertRule/index.tsx index b0d146206d..40145d324e 100644 --- a/frontend/src/container/CreateAlertRule/index.tsx +++ b/frontend/src/container/CreateAlertRule/index.tsx @@ -1,16 +1,11 @@ import { Form, Row } from 'antd'; -import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames'; import FormAlertRules from 'container/FormAlertRules'; -import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; -import useUrlQuery from 'hooks/useUrlQuery'; -import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi'; import { useState } from 'react'; import { AlertTypes } from 'types/api/alerts/alertTypes'; import { AlertDef } from 'types/api/alerts/def'; import { alertDefaults, - ALERTS_VALUES_MAP, exceptionAlertDefaults, logAlertDefaults, traceAlertDefaults, @@ -18,18 +13,12 @@ import { import SelectAlertType from './SelectAlertType'; function CreateRules(): JSX.Element { - const [initValues, setInitValues] = useState(alertDefaults); + const [initValues, setInitValues] = useState(null); const [alertType, setAlertType] = useState( AlertTypes.METRICS_BASED_ALERT, ); const [formInstance] = Form.useForm(); - const urlQuery = useUrlQuery(); - - const compositeQuery = urlQuery.get(COMPOSITE_QUERY); - - const { redirectWithQueryBuilderData } = useQueryBuilder(); - const onSelectType = (typ: AlertTypes): void => { setAlertType(typ); switch (typ) { @@ -45,15 +34,9 @@ function CreateRules(): JSX.Element { default: setInitValues(alertDefaults); } - - const value = ALERTS_VALUES_MAP[typ].condition.compositeQuery; - - const compositeQuery = mapQueryDataFromApi(value); - - redirectWithQueryBuilderData(compositeQuery); }; - if (!compositeQuery) { + if (!initValues) { return ( diff --git a/frontend/src/container/FormAlertRules/ChartPreview/index.tsx b/frontend/src/container/FormAlertRules/ChartPreview/index.tsx index 37d28617a0..f08d22df96 100644 --- a/frontend/src/container/FormAlertRules/ChartPreview/index.tsx +++ b/frontend/src/container/FormAlertRules/ChartPreview/index.tsx @@ -1,7 +1,7 @@ import { InfoCircleOutlined } from '@ant-design/icons'; import { StaticLineProps } from 'components/Graph'; import Spinner from 'components/Spinner'; -import { PANEL_TYPES } from 'constants/queryBuilder'; +import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder'; import GridGraphComponent from 'container/GridGraphComponent'; import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems'; @@ -17,7 +17,7 @@ import { ChartContainer, FailedMessageContainer } from './styles'; export interface ChartPreviewProps { name: string; - query: Query | undefined; + query: Query | null; graphType?: GRAPH_TYPES; selectedTime?: timePreferenceType; selectedInterval?: Time; @@ -74,15 +74,7 @@ function ChartPreview({ const queryResponse = useGetQueryRange( { - query: query || { - queryType: EQueryType.QUERY_BUILDER, - promql: [], - builder: { - queryFormulas: [], - queryData: [], - }, - clickhouse_sql: [], - }, + query: query || initialQueriesMap.metrics, globalSelectedInterval: selectedInterval, graphType, selectedTime, diff --git a/frontend/src/container/FormAlertRules/index.tsx b/frontend/src/container/FormAlertRules/index.tsx index 9eec5ad9d0..e903945fea 100644 --- a/frontend/src/container/FormAlertRules/index.tsx +++ b/frontend/src/container/FormAlertRules/index.tsx @@ -48,7 +48,12 @@ function FormAlertRules({ // init namespace for translations const { t } = useTranslation('alerts'); - const { currentQuery, redirectWithQueryBuilderData } = useQueryBuilder(); + const { + currentQuery, + stagedQuery, + handleRunQuery, + redirectWithQueryBuilderData, + } = useQueryBuilder(); // use query client const ruleCache = useQueryClient(); @@ -65,35 +70,14 @@ function FormAlertRules({ const sq = useMemo(() => mapQueryDataFromApi(initQuery), [initQuery]); - // manualStagedQuery requires manual staging of query - // when user clicks run query button. Useful for clickhouse tab where - // run query button is provided. - const [manualStagedQuery, setManualStagedQuery] = useState(); - - // this use effect initiates staged query and - // other queries based on server data. - // useful when fetching of initial values (from api) - // is delayed - - const { compositeQuery } = useShareBuilderUrl({ defaultValue: sq }); + useShareBuilderUrl({ defaultValue: sq }); useEffect(() => { - if (compositeQuery && !manualStagedQuery) { - setManualStagedQuery(compositeQuery); - } setAlertDef(initialValue); - }, [ - initialValue, - initQuery, - redirectWithQueryBuilderData, - currentQuery, - manualStagedQuery, - compositeQuery, - ]); + }, [initialValue]); const onRunQuery = (): void => { - setManualStagedQuery(currentQuery); - redirectWithQueryBuilderData(currentQuery); + handleRunQuery(); }; const onCancelHandler = useCallback(() => { @@ -115,8 +99,6 @@ function FormAlertRules({ } const query: Query = { ...currentQuery, queryType: val }; - setManualStagedQuery(query); - redirectWithQueryBuilderData(query); }; const { notifications } = useNotifications(); @@ -368,7 +350,7 @@ function FormAlertRules({ headline={} name="" threshold={alertDef.condition?.target} - query={manualStagedQuery} + query={stagedQuery} selectedInterval={toChartInterval(alertDef.evalWindow)} /> ); @@ -378,7 +360,7 @@ function FormAlertRules({ headline={} name="Chart Preview" threshold={alertDef.condition?.target} - query={manualStagedQuery} + query={stagedQuery} /> ); @@ -387,7 +369,7 @@ function FormAlertRules({ headline={} name="Chart Preview" threshold={alertDef.condition?.target} - query={manualStagedQuery} + query={stagedQuery} selectedInterval={toChartInterval(alertDef.evalWindow)} /> ); diff --git a/frontend/src/container/GridGraphLayout/utils.ts b/frontend/src/container/GridGraphLayout/utils.ts index 1cef8eed7c..6f6910b3b5 100644 --- a/frontend/src/container/GridGraphLayout/utils.ts +++ b/frontend/src/container/GridGraphLayout/utils.ts @@ -1,15 +1,10 @@ import { NotificationInstance } from 'antd/es/notification/interface'; import updateDashboardApi from 'api/dashboard/update'; -import { - initialClickHouseData, - initialQueryBuilderFormValues, - initialQueryPromQLData, -} from 'constants/queryBuilder'; +import { initialQueriesMap } from 'constants/queryBuilder'; import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; import { Layout } from 'react-grid-layout'; import store from 'store'; import { Dashboard, Widgets } from 'types/api/dashboard/getAll'; -import { EQueryType } from 'types/common/dashboard'; export const UpdateDashboard = async ( { @@ -41,15 +36,7 @@ export const UpdateDashboard = async ( nullZeroValues: widgetData?.nullZeroValues || '', opacity: '', panelTypes: graphType, - query: widgetData?.query || { - queryType: EQueryType.QUERY_BUILDER, - promql: [initialQueryPromQLData], - clickhouse_sql: [initialClickHouseData], - builder: { - queryFormulas: [], - queryData: [initialQueryBuilderFormValues], - }, - }, + query: widgetData?.query || initialQueriesMap.metrics, timePreferance: widgetData?.timePreferance || 'GLOBAL_TIME', title: widgetData ? copyTitle : '', }, diff --git a/frontend/src/container/LogsExplorerChart/LogsExplorerChart.styled.ts b/frontend/src/container/LogsExplorerChart/LogsExplorerChart.styled.ts new file mode 100644 index 0000000000..6fbe2d2e23 --- /dev/null +++ b/frontend/src/container/LogsExplorerChart/LogsExplorerChart.styled.ts @@ -0,0 +1,11 @@ +import { Card } from 'antd'; +import styled from 'styled-components'; + +export const CardStyled = styled(Card)` + position: relative; + margin: 0.5rem 0 3.1rem 0; + .ant-card-body { + height: 20vh; + min-height: 200px; + } +`; diff --git a/frontend/src/container/LogsExplorerChart/LogsExplorerChart.tsx b/frontend/src/container/LogsExplorerChart/LogsExplorerChart.tsx new file mode 100644 index 0000000000..6c2307efc2 --- /dev/null +++ b/frontend/src/container/LogsExplorerChart/LogsExplorerChart.tsx @@ -0,0 +1,66 @@ +import Graph from 'components/Graph'; +import Spinner from 'components/Spinner'; +import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder'; +import { REACT_QUERY_KEY } from 'constants/reactQueryKeys'; +import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam'; +import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange'; +import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; +import { getExplorerChartData } from 'lib/explorer/getExplorerChartData'; +import { useMemo } from 'react'; +import { useSelector } from 'react-redux'; +import { AppState } from 'store/reducers'; +import { GlobalReducer } from 'types/reducer/globalTime'; + +import { CardStyled } from './LogsExplorerChart.styled'; + +export function LogsExplorerChart(): JSX.Element { + const { stagedQuery } = useQueryBuilder(); + + const { selectedTime } = useSelector( + (state) => state.globalTime, + ); + + const panelTypeParam = useGetPanelTypesQueryParam(PANEL_TYPES.LIST); + + const { data, isFetching } = useGetQueryRange( + { + query: stagedQuery || initialQueriesMap.metrics, + graphType: panelTypeParam, + globalSelectedInterval: selectedTime, + selectedTime: 'GLOBAL_TIME', + }, + { + queryKey: [ + REACT_QUERY_KEY.GET_QUERY_RANGE, + selectedTime, + stagedQuery, + panelTypeParam, + ], + enabled: !!stagedQuery, + }, + ); + + const graphData = useMemo(() => { + if (data?.payload.data && data.payload.data.result.length > 0) { + return getExplorerChartData([data.payload.data.result[0]]); + } + + return getExplorerChartData([]); + }, [data]); + + return ( + + {isFetching ? ( + + ) : ( + + )} + + ); +} diff --git a/frontend/src/container/LogsExplorerChart/index.ts b/frontend/src/container/LogsExplorerChart/index.ts new file mode 100644 index 0000000000..48d9469dba --- /dev/null +++ b/frontend/src/container/LogsExplorerChart/index.ts @@ -0,0 +1 @@ +export { LogsExplorerChart } from './LogsExplorerChart'; diff --git a/frontend/src/container/LogsExplorerViews/LogsExplorerViews.styled.ts b/frontend/src/container/LogsExplorerViews/LogsExplorerViews.styled.ts new file mode 100644 index 0000000000..4fd3046e3b --- /dev/null +++ b/frontend/src/container/LogsExplorerViews/LogsExplorerViews.styled.ts @@ -0,0 +1,9 @@ +import { Tabs } from 'antd'; +import { themeColors } from 'constants/theme'; +import styled from 'styled-components'; + +export const TabsStyled = styled(Tabs)` + & .ant-tabs-nav { + background-color: ${themeColors.lightBlack}; + } +`; diff --git a/frontend/src/container/LogsExplorerViews/LogsExplorerViews.tsx b/frontend/src/container/LogsExplorerViews/LogsExplorerViews.tsx new file mode 100644 index 0000000000..303db79f01 --- /dev/null +++ b/frontend/src/container/LogsExplorerViews/LogsExplorerViews.tsx @@ -0,0 +1,75 @@ +import { TabsProps } from 'antd'; +import { PANEL_TYPES } from 'constants/queryBuilder'; +import { PANEL_TYPES_QUERY } from 'constants/queryBuilderQueryNames'; +import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; +import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam'; +import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; +import useUrlQuery from 'hooks/useUrlQuery'; +import { useCallback, useEffect, useMemo } from 'react'; +import { useHistory, useLocation } from 'react-router-dom'; + +import { TabsStyled } from './LogsExplorerViews.styled'; + +export function LogsExplorerViews(): JSX.Element { + const location = useLocation(); + const urlQuery = useUrlQuery(); + const history = useHistory(); + const { currentQuery } = useQueryBuilder(); + + const panelTypeParams = useGetPanelTypesQueryParam(PANEL_TYPES.LIST); + + const isMultipleQueries = useMemo( + () => + currentQuery.builder.queryData.length > 1 || + currentQuery.builder.queryFormulas.length > 0, + [currentQuery], + ); + + const tabsItems: TabsProps['items'] = useMemo( + () => [ + { + label: 'List View', + key: PANEL_TYPES.LIST, + disabled: isMultipleQueries, + }, + { label: 'TimeSeries', key: PANEL_TYPES.TIME_SERIES }, + { label: 'Table', key: PANEL_TYPES.TABLE }, + ], + [isMultipleQueries], + ); + + const handleChangeView = useCallback( + (panelType: string) => { + urlQuery.set(PANEL_TYPES_QUERY, JSON.stringify(panelType) as GRAPH_TYPES); + const path = `${location.pathname}?${urlQuery}`; + + history.push(path); + }, + [history, location, urlQuery], + ); + + const currentTabKey = useMemo( + () => + Object.values(PANEL_TYPES).includes(panelTypeParams) + ? panelTypeParams + : PANEL_TYPES.LIST, + [panelTypeParams], + ); + + useEffect(() => { + if (panelTypeParams === 'list' && isMultipleQueries) { + handleChangeView(PANEL_TYPES.TIME_SERIES); + } + }, [panelTypeParams, isMultipleQueries, handleChangeView]); + + return ( +
+ +
+ ); +} diff --git a/frontend/src/container/LogsExplorerViews/index.ts b/frontend/src/container/LogsExplorerViews/index.ts new file mode 100644 index 0000000000..4a29ed0988 --- /dev/null +++ b/frontend/src/container/LogsExplorerViews/index.ts @@ -0,0 +1 @@ +export { LogsExplorerViews } from './LogsExplorerViews'; diff --git a/frontend/src/container/MetricsApplication/MetricsPageQueries/MetricsPageQueriesFactory.ts b/frontend/src/container/MetricsApplication/MetricsPageQueries/MetricsPageQueriesFactory.ts index 57d4829ea3..b678c833a2 100644 --- a/frontend/src/container/MetricsApplication/MetricsPageQueries/MetricsPageQueriesFactory.ts +++ b/frontend/src/container/MetricsApplication/MetricsPageQueries/MetricsPageQueriesFactory.ts @@ -1,6 +1,6 @@ import { initialFormulaBuilderFormValues, - initialQueryBuilderFormValues, + initialQueryBuilderFormValuesMap, } from 'constants/queryBuilder'; import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData'; @@ -18,7 +18,7 @@ export const getQueryBuilderQueries = ({ queryFormulas: [], queryData: [ { - ...initialQueryBuilderFormValues, + ...initialQueryBuilderFormValuesMap.metrics, aggregateOperator: MetricAggregateOperator.SUM_RATE, disabled: false, groupBy, @@ -53,7 +53,7 @@ export const getQueryBuilderQuerieswithFormula = ({ ], queryData: [ { - ...initialQueryBuilderFormValues, + ...initialQueryBuilderFormValuesMap.metrics, aggregateOperator: MetricAggregateOperator.SUM_RATE, disabled, groupBy, @@ -66,7 +66,7 @@ export const getQueryBuilderQuerieswithFormula = ({ }, }, { - ...initialQueryBuilderFormValues, + ...initialQueryBuilderFormValuesMap.metrics, aggregateOperator: MetricAggregateOperator.SUM_RATE, disabled, groupBy, diff --git a/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx b/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx index ca4c374125..74df7c2dc3 100644 --- a/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx @@ -14,6 +14,7 @@ import { useParams } from 'react-router-dom'; import { Widgets } from 'types/api/dashboard/getAll'; import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData'; import { EQueryType } from 'types/common/dashboard'; +import { v4 as uuid } from 'uuid'; import { Card, GraphContainer, GraphTitle, Row } from '../styles'; import { Button } from './styles'; @@ -56,6 +57,7 @@ function DBCall({ getWidgetQueryBuilder }: DBCallProps): JSX.Element { tagFilterItems, }), clickhouse_sql: [], + id: uuid(), }), [getWidgetQueryBuilder, servicename, tagFilterItems], ); @@ -69,6 +71,7 @@ function DBCall({ getWidgetQueryBuilder }: DBCallProps): JSX.Element { tagFilterItems, }), clickhouse_sql: [], + id: uuid(), }), [getWidgetQueryBuilder, servicename, tagFilterItems], ); diff --git a/frontend/src/container/MetricsApplication/Tabs/External.tsx b/frontend/src/container/MetricsApplication/Tabs/External.tsx index 1a4a511653..37e206b933 100644 --- a/frontend/src/container/MetricsApplication/Tabs/External.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/External.tsx @@ -15,6 +15,7 @@ import { useMemo, useState } from 'react'; import { useParams } from 'react-router-dom'; import { Widgets } from 'types/api/dashboard/getAll'; import { EQueryType } from 'types/common/dashboard'; +import { v4 as uuid } from 'uuid'; import { Card, GraphContainer, GraphTitle, Row } from '../styles'; import { legend } from './constant'; @@ -48,6 +49,7 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element { tagFilterItems, }), clickhouse_sql: [], + id: uuid(), }), [getWidgetQueryBuilder, servicename, tagFilterItems], ); @@ -67,6 +69,7 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element { tagFilterItems, }), clickhouse_sql: [], + id: uuid(), }), [getWidgetQueryBuilder, servicename, tagFilterItems], ); @@ -82,6 +85,7 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element { tagFilterItems, }), clickhouse_sql: [], + id: uuid(), }), [getWidgetQueryBuilder, servicename, tagFilterItems], ); @@ -97,6 +101,7 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element { tagFilterItems, }), clickhouse_sql: [], + id: uuid(), }), [getWidgetQueryBuilder, servicename, tagFilterItems], ); diff --git a/frontend/src/container/MetricsApplication/Tabs/Overview.tsx b/frontend/src/container/MetricsApplication/Tabs/Overview.tsx index 3fb81df2e0..75d2109e8e 100644 --- a/frontend/src/container/MetricsApplication/Tabs/Overview.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/Overview.tsx @@ -21,6 +21,7 @@ import { AppState } from 'store/reducers'; import { Widgets } from 'types/api/dashboard/getAll'; import { EQueryType } from 'types/common/dashboard'; import MetricReducer from 'types/reducer/metrics'; +import { v4 as uuid } from 'uuid'; import { errorPercentage, @@ -91,6 +92,7 @@ function Application({ getWidgetQueryBuilder }: DashboardProps): JSX.Element { topLevelOperations, }), clickhouse_sql: [], + id: uuid(), }), [getWidgetQueryBuilder, servicename, topLevelOperations, tagFilterItems], ); @@ -106,6 +108,7 @@ function Application({ getWidgetQueryBuilder }: DashboardProps): JSX.Element { topLevelOperations, }), clickhouse_sql: [], + id: uuid(), }), [servicename, topLevelOperations, tagFilterItems, getWidgetQueryBuilder], ); diff --git a/frontend/src/container/NewDashboard/ComponentsSlider/index.tsx b/frontend/src/container/NewDashboard/ComponentsSlider/index.tsx index af1e14feaa..b20c4388f8 100644 --- a/frontend/src/container/NewDashboard/ComponentsSlider/index.tsx +++ b/frontend/src/container/NewDashboard/ComponentsSlider/index.tsx @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { initialQueryWithType } from 'constants/queryBuilder'; +import { initialQueriesMap } from 'constants/queryBuilder'; import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames'; import { useIsDarkMode } from 'hooks/useDarkMode'; import { useNotifications } from 'hooks/useNotifications'; @@ -47,7 +47,7 @@ function DashboardGraphSlider({ toggleAddWidget }: Props): JSX.Element { history.push( `${history.location.pathname}/new?graphType=${name}&widgetId=${ emptyLayout.i - }&${COMPOSITE_QUERY}=${JSON.stringify(initialQueryWithType)}`, + }&${COMPOSITE_QUERY}=${JSON.stringify(initialQueriesMap.metrics)}`, ); } catch (error) { notifications.error({ diff --git a/frontend/src/container/QueryBuilder/QueryBuilder.interfaces.ts b/frontend/src/container/QueryBuilder/QueryBuilder.interfaces.ts index 41ea0b5b3f..ab61c94f22 100644 --- a/frontend/src/container/QueryBuilder/QueryBuilder.interfaces.ts +++ b/frontend/src/container/QueryBuilder/QueryBuilder.interfaces.ts @@ -1,4 +1,5 @@ import { ITEMS } from 'container/NewDashboard/ComponentsSlider/menuItems'; +import { ReactNode } from 'react'; import { DataSource } from 'types/common/queryBuilder'; export type QueryBuilderConfig = @@ -11,4 +12,5 @@ export type QueryBuilderConfig = export type QueryBuilderProps = { config?: QueryBuilderConfig; panelType: ITEMS; + actions?: ReactNode; }; diff --git a/frontend/src/container/QueryBuilder/QueryBuilder.styled.ts b/frontend/src/container/QueryBuilder/QueryBuilder.styled.ts new file mode 100644 index 0000000000..20dc483e01 --- /dev/null +++ b/frontend/src/container/QueryBuilder/QueryBuilder.styled.ts @@ -0,0 +1,6 @@ +import { Col } from 'antd'; +import styled from 'styled-components'; + +export const ActionsWrapperStyled = styled(Col)` + padding-right: 1rem; +`; diff --git a/frontend/src/container/QueryBuilder/QueryBuilder.tsx b/frontend/src/container/QueryBuilder/QueryBuilder.tsx index e0900cc947..564248a1a3 100644 --- a/frontend/src/container/QueryBuilder/QueryBuilder.tsx +++ b/frontend/src/container/QueryBuilder/QueryBuilder.tsx @@ -11,15 +11,16 @@ import { Formula, Query } from './components'; // ** Types import { QueryBuilderProps } from './QueryBuilder.interfaces'; // ** Styles +import { ActionsWrapperStyled } from './QueryBuilder.styled'; export const QueryBuilder = memo(function QueryBuilder({ config, panelType, + actions, }: QueryBuilderProps): JSX.Element { const { currentQuery, setupInitialDataSource, - resetQueryBuilderInfo, addNewBuilderQuery, addNewFormula, handleSetPanelType, @@ -35,13 +36,6 @@ export const QueryBuilder = memo(function QueryBuilder({ handleSetPanelType(panelType); }, [handleSetPanelType, panelType]); - useEffect( - () => (): void => { - resetQueryBuilderInfo(); - }, - [resetQueryBuilderInfo], - ); - const isDisabledQueryButton = useMemo( () => currentQuery.builder.queryData.length >= MAX_QUERIES, [currentQuery], @@ -81,28 +75,31 @@ export const QueryBuilder = memo(function QueryBuilder({
- - - - - - - - + + + + + + + + + {actions} + + ); }); diff --git a/frontend/src/container/QueryBuilder/filters/HavingFilter/__tests__/utils.test.tsx b/frontend/src/container/QueryBuilder/filters/HavingFilter/__tests__/utils.test.tsx index f22d88a66a..5567947f44 100644 --- a/frontend/src/container/QueryBuilder/filters/HavingFilter/__tests__/utils.test.tsx +++ b/frontend/src/container/QueryBuilder/filters/HavingFilter/__tests__/utils.test.tsx @@ -3,19 +3,17 @@ import userEvent from '@testing-library/user-event'; // Constants import { HAVING_OPERATORS, - initialQueryBuilderFormValues, + initialQueryBuilderFormValuesMap, } from 'constants/queryBuilder'; import { transformFromStringToHaving } from 'lib/query/transformQueryBuilderData'; // ** Types import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; -import { DataSource } from 'types/common/queryBuilder'; // ** Components import { HavingFilter } from '../HavingFilter'; const valueWithAttributeAndOperator: IBuilderQuery = { - ...initialQueryBuilderFormValues, - dataSource: DataSource.LOGS, + ...initialQueryBuilderFormValuesMap.logs, aggregateOperator: 'SUM', aggregateAttribute: { isColumn: false, @@ -29,7 +27,10 @@ describe('Having filter behaviour', () => { test('Having filter render is rendered', () => { const mockFn = jest.fn(); const { unmount } = render( - , + , ); const selectId = 'havingSelect'; @@ -44,7 +45,10 @@ describe('Having filter behaviour', () => { test('Having render is disabled initially', () => { const mockFn = jest.fn(); const { unmount } = render( - , + , ); const input = screen.getByRole('combobox'); diff --git a/frontend/src/container/SideNav/menuItems.tsx b/frontend/src/container/SideNav/menuItems.tsx index 6254cf84a6..a784a39c0a 100644 --- a/frontend/src/container/SideNav/menuItems.tsx +++ b/frontend/src/container/SideNav/menuItems.tsx @@ -53,16 +53,20 @@ const menus: SidebarMenu[] = [ ], }, { - key: ROUTES.LOGS, + key: 'logs', label: 'Logs', icon: , - // label: createLabelWithTags('Logs', ['Beta']), - // children: [ - // { - // key: ROUTES.LOGS, - // label: 'Search', - // }, - // ], + children: [ + { + key: ROUTES.LOGS, + label: 'Search', + }, + // TODO: uncomment when will be ready explorer + // { + // key: ROUTES.LOGS_EXPLORER, + // label: 'Views', + // }, + ], }, { key: ROUTES.ALL_DASHBOARD, diff --git a/frontend/src/container/TopNav/Breadcrumbs/index.tsx b/frontend/src/container/TopNav/Breadcrumbs/index.tsx index 01ec22677c..d8ad3a6f40 100644 --- a/frontend/src/container/TopNav/Breadcrumbs/index.tsx +++ b/frontend/src/container/TopNav/Breadcrumbs/index.tsx @@ -19,6 +19,7 @@ const breadcrumbNameMap = { [ROUTES.LIST_ALL_ALERT]: 'Alerts', [ROUTES.ALL_DASHBOARD]: 'Dashboard', [ROUTES.LOGS]: 'Logs', + [ROUTES.LOGS_EXPLORER]: 'Logs Explorer', }; function ShowBreadcrumbs(props: RouteComponentProps): JSX.Element { diff --git a/frontend/src/hooks/queryBuilder/useGetCompositeQueryParam.ts b/frontend/src/hooks/queryBuilder/useGetCompositeQueryParam.ts new file mode 100644 index 0000000000..4477a9fbf7 --- /dev/null +++ b/frontend/src/hooks/queryBuilder/useGetCompositeQueryParam.ts @@ -0,0 +1,14 @@ +import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames'; +import useUrlQuery from 'hooks/useUrlQuery'; +import { useMemo } from 'react'; +import { Query } from 'types/api/queryBuilder/queryBuilderData'; + +export const useGetCompositeQueryParam = (): Query | null => { + const urlQuery = useUrlQuery(); + + return useMemo(() => { + const compositeQuery = urlQuery.get(COMPOSITE_QUERY); + + return compositeQuery ? JSON.parse(compositeQuery) : null; + }, [urlQuery]); +}; diff --git a/frontend/src/hooks/queryBuilder/useGetPanelTypesQueryParam.ts b/frontend/src/hooks/queryBuilder/useGetPanelTypesQueryParam.ts new file mode 100644 index 0000000000..06cc11829a --- /dev/null +++ b/frontend/src/hooks/queryBuilder/useGetPanelTypesQueryParam.ts @@ -0,0 +1,16 @@ +import { PANEL_TYPES_QUERY } from 'constants/queryBuilderQueryNames'; +import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; +import useUrlQuery from 'hooks/useUrlQuery'; +import { useMemo } from 'react'; + +export const useGetPanelTypesQueryParam = ( + defaultPanelType?: T, +): T extends undefined ? GRAPH_TYPES | null : GRAPH_TYPES => { + const urlQuery = useUrlQuery(); + + return useMemo(() => { + const panelTypeQuery = urlQuery.get(PANEL_TYPES_QUERY); + + return panelTypeQuery ? JSON.parse(panelTypeQuery) : defaultPanelType; + }, [urlQuery, defaultPanelType]); +}; diff --git a/frontend/src/hooks/queryBuilder/useGetQueryRange.ts b/frontend/src/hooks/queryBuilder/useGetQueryRange.ts index 7091ffb15b..b6e12b517c 100644 --- a/frontend/src/hooks/queryBuilder/useGetQueryRange.ts +++ b/frontend/src/hooks/queryBuilder/useGetQueryRange.ts @@ -1,7 +1,6 @@ import { REACT_QUERY_KEY } from 'constants/reactQueryKeys'; import { useMemo } from 'react'; import { useQuery, UseQueryOptions, UseQueryResult } from 'react-query'; -import { useLocation } from 'react-router-dom'; import { GetMetricQueryRange, GetQueryResultsProps, @@ -9,18 +8,18 @@ import { import { SuccessResponse } from 'types/api'; import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; -export const useGetQueryRange = ( +type UseGetQueryRange = ( requestData: GetQueryResultsProps, options?: UseQueryOptions, Error>, -): UseQueryResult, Error> => { - const { key } = useLocation(); +) => UseQueryResult, Error>; +export const useGetQueryRange: UseGetQueryRange = (requestData, options) => { const queryKey = useMemo(() => { if (options?.queryKey) { - return [...options.queryKey, key]; + return [...options.queryKey]; } - return [REACT_QUERY_KEY.GET_QUERY_RANGE, key, requestData]; - }, [key, options?.queryKey, requestData]); + return [REACT_QUERY_KEY.GET_QUERY_RANGE, requestData]; + }, [options?.queryKey, requestData]); return useQuery, Error>({ queryFn: async () => GetMetricQueryRange(requestData), diff --git a/frontend/src/hooks/queryBuilder/useQueryOperations.ts b/frontend/src/hooks/queryBuilder/useQueryOperations.ts index 949606c7ad..bbbc12ffd5 100644 --- a/frontend/src/hooks/queryBuilder/useQueryOperations.ts +++ b/frontend/src/hooks/queryBuilder/useQueryOperations.ts @@ -1,6 +1,6 @@ import { initialAutocompleteData, - initialQueryBuilderFormValues, + initialQueryBuilderFormValuesMap, mapOfFilters, } from 'constants/queryBuilder'; import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; @@ -21,6 +21,7 @@ export const useQueryOperations: UseQueryOperations = ({ query, index }) => { handleSetQueryData, removeQueryBuilderEntityByIndex, panelType, + initialDataSource, } = useQueryBuilder(); const [operators, setOperators] = useState[]>([]); const [listOfAdditionalFilters, setListOfAdditionalFilters] = useState< @@ -80,9 +81,9 @@ export const useQueryOperations: UseQueryOperations = ({ query, index }) => { panelType, }); - const entries = Object.entries(initialQueryBuilderFormValues).filter( - ([key]) => key !== 'queryName' && key !== 'expression', - ); + const entries = Object.entries( + initialQueryBuilderFormValuesMap.metrics, + ).filter(([key]) => key !== 'queryName' && key !== 'expression'); const initCopyResult = Object.fromEntries(entries); @@ -121,12 +122,24 @@ export const useQueryOperations: UseQueryOperations = ({ query, index }) => { ); useEffect(() => { + if (initialDataSource && dataSource !== initialDataSource) return; + const initialOperators = getOperatorsBySourceAndPanelType({ dataSource, panelType, }); + + if (JSON.stringify(operators) === JSON.stringify(initialOperators)) return; + setOperators(initialOperators); - }, [dataSource, panelType]); + handleChangeOperator(initialOperators[0].value); + }, [ + dataSource, + initialDataSource, + panelType, + operators, + handleChangeOperator, + ]); useEffect(() => { const additionalFilters = getNewListOfAdditionalFilters(dataSource); diff --git a/frontend/src/hooks/queryBuilder/useShareBuilderUrl.ts b/frontend/src/hooks/queryBuilder/useShareBuilderUrl.ts index f6f34fac39..168e5af77a 100644 --- a/frontend/src/hooks/queryBuilder/useShareBuilderUrl.ts +++ b/frontend/src/hooks/queryBuilder/useShareBuilderUrl.ts @@ -1,27 +1,19 @@ -import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames'; import useUrlQuery from 'hooks/useUrlQuery'; -import { useEffect, useMemo } from 'react'; +import { useEffect } from 'react'; import { Query } from 'types/api/queryBuilder/queryBuilderData'; +import { useGetCompositeQueryParam } from './useGetCompositeQueryParam'; import { useQueryBuilder } from './useQueryBuilder'; type UseShareBuilderUrlParams = { defaultValue: Query }; -type UseShareBuilderUrlReturnType = { compositeQuery: Query | null }; export const useShareBuilderUrl = ({ defaultValue, -}: UseShareBuilderUrlParams): UseShareBuilderUrlReturnType => { - const { redirectWithQueryBuilderData } = useQueryBuilder(); +}: UseShareBuilderUrlParams): void => { + const { redirectWithQueryBuilderData, resetStagedQuery } = useQueryBuilder(); const urlQuery = useUrlQuery(); - const compositeQuery: Query | null = useMemo(() => { - const query = urlQuery.get(COMPOSITE_QUERY); - if (query) { - return JSON.parse(query); - } - - return null; - }, [urlQuery]); + const compositeQuery = useGetCompositeQueryParam(); useEffect(() => { if (!compositeQuery) { @@ -29,5 +21,10 @@ export const useShareBuilderUrl = ({ } }, [defaultValue, urlQuery, redirectWithQueryBuilderData, compositeQuery]); - return { compositeQuery }; + useEffect( + () => (): void => { + resetStagedQuery(); + }, + [resetStagedQuery], + ); }; diff --git a/frontend/src/lib/explorer/getExplorerChartData.ts b/frontend/src/lib/explorer/getExplorerChartData.ts new file mode 100644 index 0000000000..152b72f9ac --- /dev/null +++ b/frontend/src/lib/explorer/getExplorerChartData.ts @@ -0,0 +1,46 @@ +import { ChartData } from 'chart.js'; +import getLabelName from 'lib/getLabelName'; +import { QueryData } from 'types/api/widgets/getQuery'; + +import { colors } from '../getRandomColor'; + +export const getExplorerChartData = ( + queryData: QueryData[], +): ChartData<'bar'> => { + const uniqueTimeLabels = new Set(); + + const sortedData = [...queryData].sort((a, b) => { + if (a.queryName < b.queryName) return -1; + if (a.queryName > b.queryName) return 1; + return 0; + }); + + const modifiedData: { label: string }[] = sortedData.map((result) => { + const { metric, queryName, legend } = result; + result.values.forEach((value) => { + uniqueTimeLabels.add(value[0] * 1000); + }); + + return { + label: getLabelName(metric, queryName || '', legend || ''), + }; + }); + + const labels = Array.from(uniqueTimeLabels) + .sort((a, b) => a - b) + .map((value) => new Date(value)); + + const allLabels = modifiedData.map((e) => e.label); + + const data: ChartData<'bar'> = { + labels, + datasets: queryData.map((result, index) => ({ + label: allLabels[index], + data: result.values.map((item) => parseFloat(item[1])), + backgroundColor: colors[index % colors.length] || 'red', + borderColor: colors[index % colors.length] || 'red', + })), + }; + + return data; +}; diff --git a/frontend/src/lib/newQueryBuilder/getOperatorsBySourceAndPanelType.ts b/frontend/src/lib/newQueryBuilder/getOperatorsBySourceAndPanelType.ts index d9a9753d6e..21b3bc7498 100644 --- a/frontend/src/lib/newQueryBuilder/getOperatorsBySourceAndPanelType.ts +++ b/frontend/src/lib/newQueryBuilder/getOperatorsBySourceAndPanelType.ts @@ -15,6 +15,11 @@ export const getOperatorsBySourceAndPanelType = ({ }: GetQueryOperatorsParams): SelectOption[] => { let operatorsByDataSource = mapOfOperators[dataSource]; + if (panelType === PANEL_TYPES.LIST) { + operatorsByDataSource = operatorsByDataSource.filter( + (operator) => operator.value === StringOperators.NOOP, + ); + } if (dataSource !== DataSource.METRICS && panelType !== PANEL_TYPES.LIST) { operatorsByDataSource = operatorsByDataSource.filter( (operator) => operator.value !== StringOperators.NOOP, diff --git a/frontend/src/lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi.ts b/frontend/src/lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi.ts index 860b2d1266..f30bfc13b7 100644 --- a/frontend/src/lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi.ts +++ b/frontend/src/lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi.ts @@ -1,6 +1,7 @@ -import { initialQuery } from 'constants/queryBuilder'; +import { initialQueryState } from 'constants/queryBuilder'; import { ICompositeMetricQuery } from 'types/api/alerts/compositeQuery'; import { Query } from 'types/api/queryBuilder/queryBuilderData'; +import { v4 as uuid } from 'uuid'; import { transformQueryBuilderDataModel } from '../transformQueryBuilderDataModel'; @@ -9,14 +10,14 @@ export const mapQueryDataFromApi = ( ): Query => { const builder = compositeQuery.builderQueries ? transformQueryBuilderDataModel(compositeQuery.builderQueries) - : initialQuery.builder; + : initialQueryState.builder; const promql = compositeQuery.promQueries ? Object.keys(compositeQuery.promQueries).map((key) => ({ ...compositeQuery.promQueries[key], name: key, })) - : initialQuery.promql; + : initialQueryState.promql; const clickhouseSql = compositeQuery.chQueries ? Object.keys(compositeQuery.chQueries).map((key) => ({ @@ -24,12 +25,13 @@ export const mapQueryDataFromApi = ( name: key, query: compositeQuery.chQueries[key].query, })) - : initialQuery.clickhouse_sql; + : initialQueryState.clickhouse_sql; return { builder, promql, clickhouse_sql: clickhouseSql, queryType: compositeQuery.queryType, + id: uuid(), }; }; diff --git a/frontend/src/lib/newQueryBuilder/transformQueryBuilderDataModel.ts b/frontend/src/lib/newQueryBuilder/transformQueryBuilderDataModel.ts index 784ac41921..3cf545d49b 100644 --- a/frontend/src/lib/newQueryBuilder/transformQueryBuilderDataModel.ts +++ b/frontend/src/lib/newQueryBuilder/transformQueryBuilderDataModel.ts @@ -1,6 +1,6 @@ import { initialFormulaBuilderFormValues, - initialQueryBuilderFormValues, + initialQueryBuilderFormValuesMap, } from 'constants/queryBuilder'; import { FORMULA_REGEXP } from 'constants/regExp'; import { @@ -22,7 +22,7 @@ export const transformQueryBuilderDataModel = ( queryFormulas.push({ ...initialFormulaBuilderFormValues, ...formula }); } else { const query = value as IBuilderQuery; - queryData.push({ ...initialQueryBuilderFormValues, ...query }); + queryData.push({ ...initialQueryBuilderFormValuesMap.metrics, ...query }); } }); diff --git a/frontend/src/pages/LogsExplorer/index.tsx b/frontend/src/pages/LogsExplorer/index.tsx new file mode 100644 index 0000000000..fb8685717c --- /dev/null +++ b/frontend/src/pages/LogsExplorer/index.tsx @@ -0,0 +1,45 @@ +import { Button, Col, Row } from 'antd'; +import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder'; +import { LogsExplorerChart } from 'container/LogsExplorerChart'; +import { LogsExplorerViews } from 'container/LogsExplorerViews'; +import { QueryBuilder } from 'container/QueryBuilder'; +import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam'; +import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; +import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl'; +import { DataSource } from 'types/common/queryBuilder'; + +// ** Styles +import { ButtonWrapperStyled, WrapperStyled } from './styles'; + +function LogsExporer(): JSX.Element { + const { handleRunQuery } = useQueryBuilder(); + const panelTypes = useGetPanelTypesQueryParam(PANEL_TYPES.LIST); + + useShareBuilderUrl({ defaultValue: initialQueriesMap.logs }); + + return ( + + + + + + + } + /> + + + + + + + + ); +} + +export default LogsExporer; diff --git a/frontend/src/pages/LogsExplorer/styles.ts b/frontend/src/pages/LogsExplorer/styles.ts new file mode 100644 index 0000000000..3e479cc001 --- /dev/null +++ b/frontend/src/pages/LogsExplorer/styles.ts @@ -0,0 +1,11 @@ +import { Col } from 'antd'; +import { themeColors } from 'constants/theme'; +import styled from 'styled-components'; + +export const WrapperStyled = styled.div` + color: ${themeColors.lightWhite}; +`; + +export const ButtonWrapperStyled = styled(Col)` + margin-left: auto; +`; diff --git a/frontend/src/providers/QueryBuilder.tsx b/frontend/src/providers/QueryBuilder.tsx index 7064af91d2..2389ca01bc 100644 --- a/frontend/src/providers/QueryBuilder.tsx +++ b/frontend/src/providers/QueryBuilder.tsx @@ -4,10 +4,10 @@ import { formulasNames, initialClickHouseData, initialFormulaBuilderFormValues, - initialQuery, - initialQueryBuilderFormValues, + initialQueriesMap, + initialQueryBuilderFormValuesMap, initialQueryPromQLData, - initialQueryWithType, + initialQueryState, initialSingleQueryMap, MAX_FORMULAS, MAX_QUERIES, @@ -15,6 +15,7 @@ import { } from 'constants/queryBuilder'; import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames'; import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; +import { useGetCompositeQueryParam } from 'hooks/queryBuilder/useGetCompositeQueryParam'; import useUrlQuery from 'hooks/useUrlQuery'; import { createIdFromObjectFields } from 'lib/createIdFromObjectFields'; import { createNewBuilderItemName } from 'lib/newQueryBuilder/createNewBuilderItemName'; @@ -44,19 +45,17 @@ import { QueryBuilderContextType, QueryBuilderData, } from 'types/common/queryBuilder'; +import { v4 as uuid } from 'uuid'; export const QueryBuilderContext = createContext({ - currentQuery: initialQueryWithType, + currentQuery: initialQueriesMap.metrics, + stagedQuery: initialQueriesMap.metrics, initialDataSource: null, panelType: PANEL_TYPES.TIME_SERIES, - resetQueryBuilderData: () => {}, - resetQueryBuilderInfo: () => {}, handleSetQueryData: () => {}, handleSetFormulaData: () => {}, handleSetQueryItemData: () => {}, handleSetPanelType: () => {}, - handleSetQueryType: () => {}, - initQueryBuilderData: () => {}, setupInitialDataSource: () => {}, removeQueryBuilderEntityByIndex: () => {}, removeQueryTypeItemByIndex: () => {}, @@ -64,6 +63,8 @@ export const QueryBuilderContext = createContext({ addNewFormula: () => {}, addNewQueryItem: () => {}, redirectWithQueryBuilderData: () => {}, + handleRunQuery: () => {}, + resetStagedQuery: () => {}, }); export function QueryBuilderProvider({ @@ -73,6 +74,8 @@ export function QueryBuilderProvider({ const history = useHistory(); const location = useLocation(); + const compositeQueryParam = useGetCompositeQueryParam(); + const [initialDataSource, setInitialDataSource] = useState( null, ); @@ -81,81 +84,77 @@ export function QueryBuilderProvider({ PANEL_TYPES.TIME_SERIES, ); - const [currentQuery, setCurrentQuery] = useState(initialQuery); + const [currentQuery, setCurrentQuery] = useState( + initialQueryState, + ); + const [stagedQuery, setStagedQuery] = useState(null); const [queryType, setQueryType] = useState( EQueryType.QUERY_BUILDER, ); - const handleSetQueryType = useCallback((newQueryType: EQueryType) => { - setQueryType(newQueryType); - }, []); + const initQueryBuilderData = useCallback( + (query: Query): void => { + const { queryType: newQueryType, ...queryState } = query; - const resetQueryBuilderInfo = useCallback((): void => { - setInitialDataSource(null); - setPanelType(PANEL_TYPES.TIME_SERIES); - }, []); - - const resetQueryBuilderData = useCallback(() => { - setCurrentQuery(initialQuery); - }, []); - - const initQueryBuilderData = useCallback((query: Partial): void => { - const { queryType, ...queryState } = query; - - const builder: QueryBuilderData = { - queryData: queryState.builder - ? queryState.builder.queryData.map((item) => ({ - ...initialQueryBuilderFormValues, - ...item, - })) - : initialQuery.builder.queryData, - queryFormulas: queryState.builder - ? queryState.builder.queryFormulas.map((item) => ({ - ...initialFormulaBuilderFormValues, - ...item, - })) - : initialQuery.builder.queryFormulas, - }; - - const promql: IPromQLQuery[] = queryState.promql - ? queryState.promql.map((item) => ({ - ...initialQueryPromQLData, + const builder: QueryBuilderData = { + queryData: queryState.builder.queryData.map((item) => ({ + ...initialQueryBuilderFormValuesMap[ + initialDataSource || DataSource.METRICS + ], ...item, - })) - : initialQuery.promql; + })), + queryFormulas: queryState.builder.queryFormulas.map((item) => ({ + ...initialFormulaBuilderFormValues, + ...item, + })), + }; - const clickHouse: IClickHouseQuery[] = queryState.clickhouse_sql - ? queryState.clickhouse_sql.map((item) => ({ + const promql: IPromQLQuery[] = queryState.promql.map((item) => ({ + ...initialQueryPromQLData, + ...item, + })); + + const clickHouse: IClickHouseQuery[] = queryState.clickhouse_sql.map( + (item) => ({ ...initialClickHouseData, ...item, - })) - : initialQuery.clickhouse_sql; + }), + ); - setCurrentQuery({ - clickhouse_sql: clickHouse, - promql, - builder: { - ...builder, - queryData: builder.queryData.map((q) => ({ - ...q, - groupBy: q.groupBy.map(({ id: _, ...item }) => ({ - ...item, - id: createIdFromObjectFields(item, baseAutoCompleteIdKeysOrder), + const type = newQueryType || EQueryType.QUERY_BUILDER; + + const newQueryState: QueryState = { + clickhouse_sql: clickHouse, + promql, + builder: { + ...builder, + queryData: builder.queryData.map((q) => ({ + ...q, + groupBy: q.groupBy.map(({ id: _, ...item }) => ({ + ...item, + id: createIdFromObjectFields(item, baseAutoCompleteIdKeysOrder), + })), + aggregateAttribute: { + ...q.aggregateAttribute, + id: createIdFromObjectFields( + q.aggregateAttribute, + baseAutoCompleteIdKeysOrder, + ), + }, })), - aggregateAttribute: { - ...q.aggregateAttribute, - id: createIdFromObjectFields( - q.aggregateAttribute, - baseAutoCompleteIdKeysOrder, - ), - }, - })), - }, - }); + }, + id: queryState.id, + }; - setQueryType(queryType || EQueryType.QUERY_BUILDER); - }, []); + const nextQuery: Query = { ...newQueryState, queryType: type }; + + setStagedQuery(nextQuery); + setCurrentQuery(newQueryState); + setQueryType(type); + }, + [initialDataSource], + ); const removeQueryBuilderEntityByIndex = useCallback( (type: keyof QueryBuilderData, index: number) => { @@ -190,9 +189,11 @@ export function QueryBuilderProvider({ const createNewBuilderQuery = useCallback( (queries: IBuilderQuery[]): IBuilderQuery => { const existNames = queries.map((item) => item.queryName); + const initialBuilderQuery = + initialQueryBuilderFormValuesMap[initialDataSource || DataSource.METRICS]; const newQuery: IBuilderQuery = { - ...initialQueryBuilderFormValues, + ...initialBuilderQuery, queryName: createNewBuilderItemName({ existNames, sourceNames: alphabet }), expression: createNewBuilderItemName({ existNames, @@ -381,7 +382,7 @@ export function QueryBuilderProvider({ }, []); const redirectWithQueryBuilderData = useCallback( - (query: Partial) => { + (query: Partial, searchParams?: Record) => { const currentGeneratedQuery: Query = { queryType: !query.queryType || !Object.values(EQueryType).includes(query.queryType) @@ -389,63 +390,84 @@ export function QueryBuilderProvider({ : query.queryType, builder: !query.builder || query.builder.queryData.length === 0 - ? initialQuery.builder + ? initialQueryState.builder : query.builder, promql: !query.promql || query.promql.length === 0 - ? initialQuery.promql + ? initialQueryState.promql : query.promql, clickhouse_sql: !query.clickhouse_sql || query.clickhouse_sql.length === 0 - ? initialQuery.clickhouse_sql + ? initialQueryState.clickhouse_sql : query.clickhouse_sql, + id: uuid(), }; urlQuery.set(COMPOSITE_QUERY, JSON.stringify(currentGeneratedQuery)); - const generatedUrl = `${location.pathname}?${urlQuery.toString()}`; + if (searchParams) { + Object.keys(searchParams).forEach((param) => + urlQuery.set(param, JSON.stringify(searchParams[param])), + ); + } + + const generatedUrl = `${location.pathname}?${urlQuery}`; history.push(generatedUrl); }, [history, location, urlQuery], ); - useEffect(() => { - const compositeQuery = urlQuery.get(COMPOSITE_QUERY); - if (!compositeQuery) return; + const handleRunQuery = useCallback(() => { + redirectWithQueryBuilderData({ ...currentQuery, queryType }); + }, [redirectWithQueryBuilderData, currentQuery, queryType]); - const newQuery: Query = JSON.parse(compositeQuery); + const resetStagedQuery = useCallback(() => { + setStagedQuery(null); + }, []); + + useEffect(() => { + if (!compositeQueryParam) return; + + if (stagedQuery && stagedQuery.id === compositeQueryParam.id) { + return; + } const { isValid, validData } = replaceIncorrectObjectFields( - newQuery, - initialQueryWithType, + compositeQueryParam, + initialQueriesMap.metrics, ); if (!isValid) { redirectWithQueryBuilderData(validData); } else { - initQueryBuilderData(newQuery); + initQueryBuilderData(compositeQueryParam); } - }, [initQueryBuilderData, redirectWithQueryBuilderData, urlQuery]); - - const query: Query = useMemo(() => ({ ...currentQuery, queryType }), [ - currentQuery, - queryType, + }, [ + initQueryBuilderData, + redirectWithQueryBuilderData, + compositeQueryParam, + stagedQuery, ]); + const query: Query = useMemo( + () => ({ + ...currentQuery, + queryType, + }), + [currentQuery, queryType], + ); + const contextValues: QueryBuilderContextType = useMemo( () => ({ currentQuery: query, + stagedQuery, initialDataSource, panelType, - resetQueryBuilderData, - resetQueryBuilderInfo, handleSetQueryData, handleSetFormulaData, handleSetQueryItemData, handleSetPanelType, - handleSetQueryType, - initQueryBuilderData, setupInitialDataSource, removeQueryBuilderEntityByIndex, removeQueryTypeItemByIndex, @@ -453,19 +475,18 @@ export function QueryBuilderProvider({ addNewFormula, addNewQueryItem, redirectWithQueryBuilderData, + handleRunQuery, + resetStagedQuery, }), [ query, + stagedQuery, initialDataSource, panelType, - resetQueryBuilderData, - resetQueryBuilderInfo, handleSetQueryData, handleSetFormulaData, handleSetQueryItemData, handleSetPanelType, - handleSetQueryType, - initQueryBuilderData, setupInitialDataSource, removeQueryBuilderEntityByIndex, removeQueryTypeItemByIndex, @@ -473,6 +494,8 @@ export function QueryBuilderProvider({ addNewFormula, addNewQueryItem, redirectWithQueryBuilderData, + handleRunQuery, + resetStagedQuery, ], ); diff --git a/frontend/src/store/actions/dashboard/getDashboard.ts b/frontend/src/store/actions/dashboard/getDashboard.ts index a2484ee555..f84461c655 100644 --- a/frontend/src/store/actions/dashboard/getDashboard.ts +++ b/frontend/src/store/actions/dashboard/getDashboard.ts @@ -1,5 +1,5 @@ import getDashboard from 'api/dashboard/get'; -import { initialQueryWithType, PANEL_TYPES } from 'constants/queryBuilder'; +import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder'; import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; import { Dispatch } from 'redux'; import AppActions from 'types/actions'; @@ -39,7 +39,7 @@ export const GetDashboard = ({ panelTypes: graphType || PANEL_TYPES.TIME_SERIES, timePreferance: 'GLOBAL_TIME', title: '', - query: initialQueryWithType, + query: initialQueriesMap.metrics, }, }); } diff --git a/frontend/src/store/actions/dashboard/getQueryResults.ts b/frontend/src/store/actions/dashboard/getQueryResults.ts index 11d59c5aa2..fff445e463 100644 --- a/frontend/src/store/actions/dashboard/getQueryResults.ts +++ b/frontend/src/store/actions/dashboard/getQueryResults.ts @@ -12,6 +12,7 @@ import getStep from 'lib/getStep'; import { mapQueryDataToApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataToApi'; import { isEmpty } from 'lodash-es'; import store from 'store'; +import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; import { SuccessResponse } from 'types/api'; import { Query } from 'types/api/queryBuilder/queryBuilderData'; import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; diff --git a/frontend/src/types/api/queryBuilder/queryBuilderData.ts b/frontend/src/types/api/queryBuilder/queryBuilderData.ts index b89c81346a..ee9cfb6aef 100644 --- a/frontend/src/types/api/queryBuilder/queryBuilderData.ts +++ b/frontend/src/types/api/queryBuilder/queryBuilderData.ts @@ -79,6 +79,7 @@ export interface Query { promql: IPromQLQuery[]; builder: QueryBuilderData; clickhouse_sql: IClickHouseQuery[]; + id: string; } export type QueryState = Omit; diff --git a/frontend/src/types/common/queryBuilder.ts b/frontend/src/types/common/queryBuilder.ts index 0b2ded5ec5..16b6f8cd08 100644 --- a/frontend/src/types/common/queryBuilder.ts +++ b/frontend/src/types/common/queryBuilder.ts @@ -154,10 +154,9 @@ export type QueryBuilderData = { export type QueryBuilderContextType = { currentQuery: Query; + stagedQuery: Query | null; initialDataSource: DataSource | null; panelType: GRAPH_TYPES; - resetQueryBuilderData: () => void; - resetQueryBuilderInfo: () => void; handleSetQueryData: (index: number, queryData: IBuilderQuery) => void; handleSetFormulaData: (index: number, formulaData: IBuilderFormula) => void; handleSetQueryItemData: ( @@ -166,8 +165,6 @@ export type QueryBuilderContextType = { newQueryData: IPromQLQuery | IClickHouseQuery, ) => void; handleSetPanelType: (newPanelType: GRAPH_TYPES) => void; - handleSetQueryType: (newQueryType: EQueryType) => void; - initQueryBuilderData: (query: Partial) => void; setupInitialDataSource: (newInitialDataSource: DataSource | null) => void; removeQueryBuilderEntityByIndex: ( type: keyof QueryBuilderData, @@ -180,7 +177,12 @@ export type QueryBuilderContextType = { addNewBuilderQuery: () => void; addNewFormula: () => void; addNewQueryItem: (type: EQueryType.PROM | EQueryType.CLICKHOUSE) => void; - redirectWithQueryBuilderData: (query: Query) => void; + redirectWithQueryBuilderData: ( + query: Query, + searchParams?: Record, + ) => void; + handleRunQuery: () => void; + resetStagedQuery: () => void; }; export type QueryAdditionalFilter = { diff --git a/frontend/src/utils/permission/index.ts b/frontend/src/utils/permission/index.ts index 62c7c2012e..9134bae30f 100644 --- a/frontend/src/utils/permission/index.ts +++ b/frontend/src/utils/permission/index.ts @@ -69,6 +69,7 @@ export const routePermission: Record = { USAGE_EXPLORER: ['ADMIN', 'EDITOR', 'VIEWER'], VERSION: ['ADMIN', 'EDITOR', 'VIEWER'], LOGS: ['ADMIN', 'EDITOR', 'VIEWER'], + LOGS_EXPLORER: ['ADMIN', 'EDITOR', 'VIEWER'], LIST_LICENSES: ['ADMIN'], TRACE_EXPLORER: ['ADMIN', 'EDITOR', 'VIEWER'], }; From 7f05ce3d050e34b480ba6652dd4b6789e7a8633b Mon Sep 17 00:00:00 2001 From: Yevhen Shevchenko <90138953+yeshev@users.noreply.github.com> Date: Fri, 16 Jun 2023 15:40:54 +0300 Subject: [PATCH 26/37] fix: query operator (#2924) --- frontend/src/hooks/queryBuilder/useQueryOperations.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/frontend/src/hooks/queryBuilder/useQueryOperations.ts b/frontend/src/hooks/queryBuilder/useQueryOperations.ts index bbbc12ffd5..b1d2f35c18 100644 --- a/frontend/src/hooks/queryBuilder/useQueryOperations.ts +++ b/frontend/src/hooks/queryBuilder/useQueryOperations.ts @@ -132,12 +132,20 @@ export const useQueryOperations: UseQueryOperations = ({ query, index }) => { if (JSON.stringify(operators) === JSON.stringify(initialOperators)) return; setOperators(initialOperators); - handleChangeOperator(initialOperators[0].value); + + const isCurrentOperatorAvailableInList = initialOperators + .map((operator) => operator.value) + .includes(aggregateOperator); + + if (!isCurrentOperatorAvailableInList) { + handleChangeOperator(initialOperators[0].value); + } }, [ dataSource, initialDataSource, panelType, operators, + aggregateOperator, handleChangeOperator, ]); From bcacb1d2b03c05173e268c7e5db01feca044cf31 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Fri, 16 Jun 2023 22:22:11 +0530 Subject: [PATCH 27/37] =?UTF-8?q?ci(gh-workflows):=20=F0=9F=91=B7=20bump?= =?UTF-8?q?=20up=20versions=20and=20minor=20updates=20(#2923)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ci(gh-workflows): 👷 bump up versions and minor updates * ci(gh-workflows): 👷 bump up versions of verify-linked-issue-action to v0.71 * ci(e2e-k3s): 👷 use ipconfig instead * ci(remove-label): 👷 create separate step for remove label --------- Signed-off-by: Prashant Shahi --- .github/workflows/build.yaml | 6 ++-- .github/workflows/codeql.yaml | 8 +++--- .../workflows/create-issue-on-pr-merge.yml | 4 +-- .github/workflows/e2e-k3s.yaml | 8 ++++-- .github/workflows/playwright.yaml | 4 +-- .github/workflows/pr_verify_linked_issue.yml | 2 +- .github/workflows/push.yaml | 28 +++++++++---------- .github/workflows/release-drafter.yml | 6 ++++ .github/workflows/remove-label.yaml | 12 ++++++-- .github/workflows/sonar.yml | 4 +-- 10 files changed, 48 insertions(+), 34 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index ec417a851b..744688a733 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install dependencies run: cd frontend && yarn install - name: Run ESLint @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Run tests shell: bash run: | @@ -45,7 +45,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Build EE query-service image shell: bash run: | diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml index 404cc66f7b..14a0c127aa 100644 --- a/.github/workflows/codeql.yaml +++ b/.github/workflows/codeql.yaml @@ -39,11 +39,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -54,7 +54,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -68,4 +68,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/create-issue-on-pr-merge.yml b/.github/workflows/create-issue-on-pr-merge.yml index 12910628ed..2b0c849ffa 100644 --- a/.github/workflows/create-issue-on-pr-merge.yml +++ b/.github/workflows/create-issue-on-pr-merge.yml @@ -12,11 +12,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Codebase - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: signoz/gh-bot - name: Use Node v16 - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: 16 - name: Setup Cache & Install Dependencies diff --git a/.github/workflows/e2e-k3s.yaml b/.github/workflows/e2e-k3s.yaml index a1a307a9d9..8eab9d9beb 100644 --- a/.github/workflows/e2e-k3s.yaml +++ b/.github/workflows/e2e-k3s.yaml @@ -13,7 +13,7 @@ jobs: DOCKER_TAG: pull-${{ github.event.number }} steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Build query-service image env: @@ -69,12 +69,14 @@ jobs: --restart='OnFailure' -i --rm --command -- curl -X POST -F \ 'locust_count=6' -F 'hatch_rate=2' http://locust-master:8089/swarm - - name: Get short commit SHA and display tunnel URL + - name: Get short commit SHA, display tunnel URL and IP Address of the worker node id: get-subdomain run: | subdomain="pr-$(git rev-parse --short HEAD)" echo "URL for tunnelling: https://$subdomain.loca.lt" - echo "::set-output name=subdomain::$subdomain" + echo "subdomain=$subdomain" >> $GITHUB_OUTPUT + worker_ip="$(curl -4 -s ipconfig.io/ip)" + echo "Worker node IP address: $worker_ip" - name: Start tunnel env: diff --git a/.github/workflows/playwright.yaml b/.github/workflows/playwright.yaml index 0a6addfaeb..d6c05dfd6f 100644 --- a/.github/workflows/playwright.yaml +++ b/.github/workflows/playwright.yaml @@ -9,8 +9,8 @@ jobs: timeout-minutes: 60 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: "16.x" - name: Install dependencies diff --git a/.github/workflows/pr_verify_linked_issue.yml b/.github/workflows/pr_verify_linked_issue.yml index a2442cc3a4..927b46c216 100644 --- a/.github/workflows/pr_verify_linked_issue.yml +++ b/.github/workflows/pr_verify_linked_issue.yml @@ -14,6 +14,6 @@ jobs: name: Ensure Pull Request has a linked issue. steps: - name: Verify Linked Issue - uses: srikanthccv/verify-linked-issue-action@v0.70 + uses: srikanthccv/verify-linked-issue-action@v0.71 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/push.yaml b/.github/workflows/push.yaml index b497db5001..c198442ae5 100644 --- a/.github/workflows/push.yaml +++ b/.github/workflows/push.yaml @@ -14,19 +14,19 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 with: version: latest - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - uses: benjlevesque/short-sha@v1.2 + - uses: benjlevesque/short-sha@v2.2 id: short-sha - name: Get branch name id: branch-name @@ -49,19 +49,19 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 with: version: latest - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - uses: benjlevesque/short-sha@v1.2 + - uses: benjlevesque/short-sha@v2.2 id: short-sha - name: Get branch name id: branch-name @@ -84,7 +84,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install dependencies working-directory: frontend run: yarn install @@ -97,15 +97,15 @@ jobs: run: npm run lint continue-on-error: true - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 with: version: latest - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - uses: benjlevesque/short-sha@v1.2 + - uses: benjlevesque/short-sha@v2.2 id: short-sha - name: Get branch name id: branch-name diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 678007f91a..cb8189b134 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -12,6 +12,12 @@ on: jobs: update_release_draft: + permissions: + # write permission is required to create a github release + contents: write + # write permission is required for autolabeler + # otherwise, read permission is required at least + pull-requests: write runs-on: ubuntu-latest steps: # (Optional) GitHub Enterprise requires GHE_HOST variable set diff --git a/.github/workflows/remove-label.yaml b/.github/workflows/remove-label.yaml index 418475ea23..ef570a6ac1 100644 --- a/.github/workflows/remove-label.yaml +++ b/.github/workflows/remove-label.yaml @@ -8,9 +8,15 @@ jobs: remove: runs-on: ubuntu-latest steps: - - name: Remove label - uses: buildsville/add-remove-label@v1 + - name: Remove label ok-to-test from PR + uses: buildsville/add-remove-label@v2.0.0 with: - label: ok-to-test,testing-deploy + label: ok-to-test + type: remove + token: ${{ secrets.GITHUB_TOKEN }} + - name: Remove label testing-deploy from PR + uses: buildsville/add-remove-label@v2.0.0 + with: + label: testing-deploy type: remove token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index c19c4f5452..742768525f 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -3,7 +3,7 @@ on: pull_request: branches: - main - - v* + - develop paths: - 'frontend/**' defaults: @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - name: Sonar analysis From b782bd89097f238dfd4e83b7f0cb4cb3b3317aef Mon Sep 17 00:00:00 2001 From: Palash Gupta Date: Mon, 19 Jun 2023 12:15:57 +0530 Subject: [PATCH 28/37] chore: try signoz cloud link is updated (#2928) --- frontend/src/container/Header/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/container/Header/index.tsx b/frontend/src/container/Header/index.tsx index 93bb6c08f3..b1334ade34 100644 --- a/frontend/src/container/Header/index.tsx +++ b/frontend/src/container/Header/index.tsx @@ -91,7 +91,7 @@ function HeaderContainer(): JSX.Element { const onClickSignozCloud = (): void => { window.open( - 'https://signoz.io/teams/?utm_source=product_navbar&utm_medium=frontend', + 'https://signoz.io/oss-to-cloud/?utm_source=product_navbar&utm_medium=frontend&utm_campaign=oss_users', '_blank', ); }; From 37fc00b55fb1d48239cfcb75fd72914a61805c05 Mon Sep 17 00:00:00 2001 From: dnazarenkosignoz <134951516+dnazarenkosignoz@users.noreply.github.com> Date: Mon, 19 Jun 2023 15:57:58 +0300 Subject: [PATCH 29/37] feat: add the Trace Explorer page with Query Builder (#2843) * feat: update the SideNav component * feat: add the Trace Explorer page with Query Builder * chore: build is fixed * chore: tsc build is fixed * chore: menu items is updated --------- Co-authored-by: Nazarenko19 Co-authored-by: Palash Gupta --- frontend/src/AppRoutes/pageComponents.ts | 5 ++ frontend/src/AppRoutes/routes.ts | 8 ++ frontend/src/constants/routes.ts | 2 +- frontend/src/container/Controls/config.ts | 7 ++ frontend/src/container/Controls/index.tsx | 69 ++++++++++++++++++ frontend/src/container/Controls/styles.ts | 7 ++ frontend/src/container/LogControls/config.ts | 1 - frontend/src/container/LogControls/index.tsx | 60 +++------------ .../container/LogDetailedView/TableView.tsx | 2 +- .../container/QueryBuilder/QueryBuilder.tsx | 2 +- .../AdditionalFiltersToggler.tsx | 6 +- .../components/FilterLabel/FilterLabel.tsx | 7 +- frontend/src/container/SideNav/config.ts | 2 +- frontend/src/container/SideNav/menuItems.tsx | 47 ++++++------ .../container/TopNav/Breadcrumbs/index.tsx | 1 + .../TracesExplorer/Controls/index.tsx | 25 +++++++ .../TracesExplorer/Controls/styles.ts | 8 ++ .../TracesExplorer/QuerySection/index.tsx | 32 ++++++++ .../TracesExplorer/QuerySection/styles.ts | 16 ++++ .../TracesExplorer/TimeSeriesView/index.tsx | 73 +++++++++++++++++++ .../TracesExplorer/TimeSeriesView/styles.ts | 17 +++++ .../getDashboardVariables.ts | 14 +--- frontend/src/lib/getStartEndRangeTime.ts | 48 ++++++++++++ .../src/pages/TracesExplorer/constants.ts | 6 ++ frontend/src/pages/TracesExplorer/index.tsx | 59 +++++++++++++++ frontend/src/pages/TracesExplorer/styles.ts | 5 ++ frontend/src/pages/TracesExplorer/utils.tsx | 17 +++++ .../actions/dashboard/getQueryResults.ts | 27 ++----- frontend/src/utils/permission/index.ts | 2 +- 29 files changed, 464 insertions(+), 111 deletions(-) create mode 100644 frontend/src/container/Controls/config.ts create mode 100644 frontend/src/container/Controls/index.tsx create mode 100644 frontend/src/container/Controls/styles.ts delete mode 100644 frontend/src/container/LogControls/config.ts create mode 100644 frontend/src/container/TracesExplorer/Controls/index.tsx create mode 100644 frontend/src/container/TracesExplorer/Controls/styles.ts create mode 100644 frontend/src/container/TracesExplorer/QuerySection/index.tsx create mode 100644 frontend/src/container/TracesExplorer/QuerySection/styles.ts create mode 100644 frontend/src/container/TracesExplorer/TimeSeriesView/index.tsx create mode 100644 frontend/src/container/TracesExplorer/TimeSeriesView/styles.ts create mode 100644 frontend/src/lib/getStartEndRangeTime.ts create mode 100644 frontend/src/pages/TracesExplorer/constants.ts create mode 100644 frontend/src/pages/TracesExplorer/index.tsx create mode 100644 frontend/src/pages/TracesExplorer/styles.ts create mode 100644 frontend/src/pages/TracesExplorer/utils.tsx diff --git a/frontend/src/AppRoutes/pageComponents.ts b/frontend/src/AppRoutes/pageComponents.ts index d6f67f11df..a4d6b89c16 100644 --- a/frontend/src/AppRoutes/pageComponents.ts +++ b/frontend/src/AppRoutes/pageComponents.ts @@ -15,6 +15,11 @@ export const ServiceMapPage = Loadable( () => import(/* webpackChunkName: "ServiceMapPage" */ 'modules/Servicemap'), ); +export const TracesExplorer = Loadable( + () => + import(/* webpackChunkName: "Traces Explorer Page" */ 'pages/TracesExplorer'), +); + export const TraceFilter = Loadable( () => import(/* webpackChunkName: "Trace Filter Page" */ 'pages/Trace'), ); diff --git a/frontend/src/AppRoutes/routes.ts b/frontend/src/AppRoutes/routes.ts index d31b457c03..49d48de066 100644 --- a/frontend/src/AppRoutes/routes.ts +++ b/frontend/src/AppRoutes/routes.ts @@ -30,6 +30,7 @@ import { StatusPage, TraceDetail, TraceFilter, + TracesExplorer, UnAuthorized, UsageExplorerPage, } from './pageComponents'; @@ -140,6 +141,13 @@ const routes: AppRoutes[] = [ isPrivate: true, key: 'TRACE', }, + { + path: ROUTES.TRACES_EXPLORER, + exact: true, + component: TracesExplorer, + isPrivate: true, + key: 'TRACES_EXPLORER', + }, { path: ROUTES.CHANNELS_NEW, exact: true, diff --git a/frontend/src/constants/routes.ts b/frontend/src/constants/routes.ts index fb1ab7609f..f911b6be57 100644 --- a/frontend/src/constants/routes.ts +++ b/frontend/src/constants/routes.ts @@ -5,6 +5,7 @@ const ROUTES = { SERVICE_MAP: '/service-map', TRACE: '/trace', TRACE_DETAIL: '/trace/:id', + TRACES_EXPLORER: '/traces-explorer', SETTINGS: '/settings', INSTRUMENTATION: '/get-started', USAGE_EXPLORER: '/usage-explorer', @@ -31,7 +32,6 @@ const ROUTES = { HOME_PAGE: '/', PASSWORD_RESET: '/password-reset', LIST_LICENSES: '/licenses', - TRACE_EXPLORER: '/trace-explorer', }; export default ROUTES; diff --git a/frontend/src/container/Controls/config.ts b/frontend/src/container/Controls/config.ts new file mode 100644 index 0000000000..cc0378c546 --- /dev/null +++ b/frontend/src/container/Controls/config.ts @@ -0,0 +1,7 @@ +import { CSSProperties } from 'react'; + +export const ITEMS_PER_PAGE_OPTIONS = [25, 50, 100, 200]; + +export const defaultSelectStyle: CSSProperties = { + minWidth: '6rem', +}; diff --git a/frontend/src/container/Controls/index.tsx b/frontend/src/container/Controls/index.tsx new file mode 100644 index 0000000000..a9a656bfc8 --- /dev/null +++ b/frontend/src/container/Controls/index.tsx @@ -0,0 +1,69 @@ +import { LeftOutlined, RightOutlined } from '@ant-design/icons'; +import { Button, Select } from 'antd'; +import { memo, useMemo } from 'react'; + +import { defaultSelectStyle, ITEMS_PER_PAGE_OPTIONS } from './config'; +import { Container } from './styles'; + +interface ControlsProps { + count: number; + countPerPage: number; + isLoading: boolean; + handleNavigatePrevious: () => void; + handleNavigateNext: () => void; + handleCountItemsPerPageChange: (e: number) => void; +} + +function Controls(props: ControlsProps): JSX.Element | null { + const { + count, + isLoading, + countPerPage, + handleNavigatePrevious, + handleNavigateNext, + handleCountItemsPerPageChange, + } = props; + + const isNextAndPreviousDisabled = useMemo( + () => isLoading || countPerPage === 0 || count === 0 || count < countPerPage, + [isLoading, countPerPage, count], + ); + + return ( + + + + + + ); +} + +export default memo(Controls); diff --git a/frontend/src/container/Controls/styles.ts b/frontend/src/container/Controls/styles.ts new file mode 100644 index 0000000000..0407b8f790 --- /dev/null +++ b/frontend/src/container/Controls/styles.ts @@ -0,0 +1,7 @@ +import styled from 'styled-components'; + +export const Container = styled.div` + display: flex; + align-items: center; + gap: 0.5rem; +`; diff --git a/frontend/src/container/LogControls/config.ts b/frontend/src/container/LogControls/config.ts deleted file mode 100644 index 7d3b0f71ee..0000000000 --- a/frontend/src/container/LogControls/config.ts +++ /dev/null @@ -1 +0,0 @@ -export const ITEMS_PER_PAGE_OPTIONS = [25, 50, 100, 200]; diff --git a/frontend/src/container/LogControls/index.tsx b/frontend/src/container/LogControls/index.tsx index 68c4c5a08b..d5f28ba45f 100644 --- a/frontend/src/container/LogControls/index.tsx +++ b/frontend/src/container/LogControls/index.tsx @@ -1,16 +1,11 @@ -import { - CloudDownloadOutlined, - FastBackwardOutlined, - LeftOutlined, - RightOutlined, -} from '@ant-design/icons'; -import { Button, Divider, Dropdown, MenuProps, Select } from 'antd'; +import { CloudDownloadOutlined, FastBackwardOutlined } from '@ant-design/icons'; +import { Button, Divider, Dropdown, MenuProps } from 'antd'; import { Excel } from 'antd-table-saveas-excel'; +import Controls from 'container/Controls'; import { getGlobalTime } from 'container/LogsSearchFilter/utils'; import { getMinMax } from 'container/TopNav/AutoRefresh/config'; import dayjs from 'dayjs'; import { FlatLogData } from 'lib/logs/flatLogData'; -import { defaultSelectStyle } from 'pages/Logs/config'; import * as Papa from 'papaparse'; import { memo, useCallback, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; @@ -26,7 +21,6 @@ import { import { GlobalReducer } from 'types/reducer/globalTime'; import { ILogsReducer } from 'types/reducer/logs'; -import { ITEMS_PER_PAGE_OPTIONS } from './config'; import { Container, DownloadLogButton } from './styles'; function LogControls(): JSX.Element | null { @@ -149,15 +143,6 @@ function LogControls(): JSX.Element | null { const isLoading = isLogsLoading || isLoadingAggregate; - const isNextAndPreviousDisabled = useMemo( - () => - isLoading || - logLinesPerPage === 0 || - logs.length === 0 || - logs.length < logLinesPerPage, - [isLoading, logLinesPerPage, logs.length], - ); - if (liveTail !== 'STOPPED') { return null; } @@ -179,37 +164,14 @@ function LogControls(): JSX.Element | null { Go to latest - - - + ); } diff --git a/frontend/src/container/LogDetailedView/TableView.tsx b/frontend/src/container/LogDetailedView/TableView.tsx index 2959be7dcc..7d4db12acc 100644 --- a/frontend/src/container/LogDetailedView/TableView.tsx +++ b/frontend/src/container/LogDetailedView/TableView.tsx @@ -32,7 +32,7 @@ function TableView({ logData }: TableViewProps): JSX.Element | null { const dispatch = useDispatch>(); - const flattenLogData: Record | null = useMemo( + const flattenLogData: Record | null = useMemo( () => (logData ? flattenObject(logData) : null), [logData], ); diff --git a/frontend/src/container/QueryBuilder/QueryBuilder.tsx b/frontend/src/container/QueryBuilder/QueryBuilder.tsx index 564248a1a3..dae8717920 100644 --- a/frontend/src/container/QueryBuilder/QueryBuilder.tsx +++ b/frontend/src/container/QueryBuilder/QueryBuilder.tsx @@ -54,7 +54,7 @@ export const QueryBuilder = memo(function QueryBuilder({ ); return ( - + {currentQuery.builder.queryData.map((query, index) => ( diff --git a/frontend/src/container/QueryBuilder/components/AdditionalFiltersToggler/AdditionalFiltersToggler.tsx b/frontend/src/container/QueryBuilder/components/AdditionalFiltersToggler/AdditionalFiltersToggler.tsx index 79aa1b0715..d50a754e4c 100644 --- a/frontend/src/container/QueryBuilder/components/AdditionalFiltersToggler/AdditionalFiltersToggler.tsx +++ b/frontend/src/container/QueryBuilder/components/AdditionalFiltersToggler/AdditionalFiltersToggler.tsx @@ -1,4 +1,4 @@ -import { Col, Row } from 'antd'; +import { Col, Row, Typography } from 'antd'; import { Fragment, memo, ReactNode, useState } from 'react'; // ** Types @@ -46,7 +46,9 @@ export const AdditionalFiltersToggler = memo(function AdditionalFiltersToggler({ {isOpenedFilters ? : } - {!isOpenedFilters && Add conditions for {filtersTexts}} + {!isOpenedFilters && ( + Add conditions for {filtersTexts} + )} {isOpenedFilters && {children}} diff --git a/frontend/src/container/QueryBuilder/components/FilterLabel/FilterLabel.tsx b/frontend/src/container/QueryBuilder/components/FilterLabel/FilterLabel.tsx index 8fd4421f2a..9d1c17514d 100644 --- a/frontend/src/container/QueryBuilder/components/FilterLabel/FilterLabel.tsx +++ b/frontend/src/container/QueryBuilder/components/FilterLabel/FilterLabel.tsx @@ -1,3 +1,4 @@ +import { Typography } from 'antd'; import { useIsDarkMode } from 'hooks/useDarkMode'; import { memo } from 'react'; @@ -11,5 +12,9 @@ export const FilterLabel = memo(function FilterLabel({ }: FilterLabelProps): JSX.Element { const isDarkMode = useIsDarkMode(); - return {label}; + return ( + + {label} + + ); }); diff --git a/frontend/src/container/SideNav/config.ts b/frontend/src/container/SideNav/config.ts index 9938b54278..0246bc0e8e 100644 --- a/frontend/src/container/SideNav/config.ts +++ b/frontend/src/container/SideNav/config.ts @@ -30,10 +30,10 @@ export const routeConfig: Record = { [ROUTES.SETTINGS]: [QueryParams.resourceAttributes], [ROUTES.SIGN_UP]: [QueryParams.resourceAttributes], [ROUTES.SOMETHING_WENT_WRONG]: [QueryParams.resourceAttributes], + [ROUTES.TRACES_EXPLORER]: [QueryParams.resourceAttributes], [ROUTES.TRACE]: [QueryParams.resourceAttributes], [ROUTES.TRACE_DETAIL]: [QueryParams.resourceAttributes], [ROUTES.UN_AUTHORIZED]: [QueryParams.resourceAttributes], [ROUTES.USAGE_EXPLORER]: [QueryParams.resourceAttributes], [ROUTES.VERSION]: [QueryParams.resourceAttributes], - [ROUTES.TRACE_EXPLORER]: [QueryParams.resourceAttributes], }; diff --git a/frontend/src/container/SideNav/menuItems.tsx b/frontend/src/container/SideNav/menuItems.tsx index a784a39c0a..3da53f194c 100644 --- a/frontend/src/container/SideNav/menuItems.tsx +++ b/frontend/src/container/SideNav/menuItems.tsx @@ -38,35 +38,36 @@ const menus: SidebarMenu[] = [ icon: , }, { - key: 'traces', + key: ROUTES.TRACE, label: 'Traces', icon: , - children: [ - { - key: ROUTES.TRACE, - label: 'Traces', - }, - // { - // key: ROUTES.TRACE_EXPLORER, - // label: 'Explorer', - // }, - ], + // children: [ + // { + // key: ROUTES.TRACE, + // label: 'Traces', + // }, + // TODO: uncomment when will be ready explorer + // { + // key: ROUTES.TRACES_EXPLORER, + // label: "Explorer", + // }, + // ], }, { - key: 'logs', + key: ROUTES.LOGS, label: 'Logs', icon: , - children: [ - { - key: ROUTES.LOGS, - label: 'Search', - }, - // TODO: uncomment when will be ready explorer - // { - // key: ROUTES.LOGS_EXPLORER, - // label: 'Views', - // }, - ], + // children: [ + // { + // key: ROUTES.LOGS, + // label: 'Search', + // }, + // TODO: uncomment when will be ready explorer + // { + // key: ROUTES.LOGS_EXPLORER, + // label: 'Views', + // }, + // ], }, { key: ROUTES.ALL_DASHBOARD, diff --git a/frontend/src/container/TopNav/Breadcrumbs/index.tsx b/frontend/src/container/TopNav/Breadcrumbs/index.tsx index d8ad3a6f40..f3bcfe560f 100644 --- a/frontend/src/container/TopNav/Breadcrumbs/index.tsx +++ b/frontend/src/container/TopNav/Breadcrumbs/index.tsx @@ -5,6 +5,7 @@ import { Link, RouteComponentProps, withRouter } from 'react-router-dom'; const breadcrumbNameMap = { [ROUTES.APPLICATION]: 'Services', [ROUTES.TRACE]: 'Traces', + [ROUTES.TRACES_EXPLORER]: 'Traces Explorer', [ROUTES.SERVICE_MAP]: 'Service Map', [ROUTES.USAGE_EXPLORER]: 'Usage Explorer', [ROUTES.INSTRUMENTATION]: 'Get Started', diff --git a/frontend/src/container/TracesExplorer/Controls/index.tsx b/frontend/src/container/TracesExplorer/Controls/index.tsx new file mode 100644 index 0000000000..515fe12c67 --- /dev/null +++ b/frontend/src/container/TracesExplorer/Controls/index.tsx @@ -0,0 +1,25 @@ +import Controls from 'container/Controls'; +import { memo } from 'react'; + +import { Container } from './styles'; + +function TraceExplorerControls(): JSX.Element | null { + const handleCountItemsPerPageChange = (): void => {}; + const handleNavigatePrevious = (): void => {}; + const handleNavigateNext = (): void => {}; + + return ( + + + + ); +} + +export default memo(TraceExplorerControls); diff --git a/frontend/src/container/TracesExplorer/Controls/styles.ts b/frontend/src/container/TracesExplorer/Controls/styles.ts new file mode 100644 index 0000000000..f91bc43363 --- /dev/null +++ b/frontend/src/container/TracesExplorer/Controls/styles.ts @@ -0,0 +1,8 @@ +import styled from 'styled-components'; + +export const Container = styled.div` + display: flex; + align-items: center; + justify-content: flex-end; + gap: 0.5rem; +`; diff --git a/frontend/src/container/TracesExplorer/QuerySection/index.tsx b/frontend/src/container/TracesExplorer/QuerySection/index.tsx new file mode 100644 index 0000000000..169fa7ba79 --- /dev/null +++ b/frontend/src/container/TracesExplorer/QuerySection/index.tsx @@ -0,0 +1,32 @@ +import { Button } from 'antd'; +import { PANEL_TYPES } from 'constants/queryBuilder'; +import { QueryBuilder } from 'container/QueryBuilder'; +import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; +import { DataSource } from 'types/common/queryBuilder'; + +import { ButtonWrapper, Container } from './styles'; + +function QuerySection(): JSX.Element { + const { handleRunQuery } = useQueryBuilder(); + + return ( + + + + + } + /> + + ); +} + +export default QuerySection; diff --git a/frontend/src/container/TracesExplorer/QuerySection/styles.ts b/frontend/src/container/TracesExplorer/QuerySection/styles.ts new file mode 100644 index 0000000000..cdb46bd580 --- /dev/null +++ b/frontend/src/container/TracesExplorer/QuerySection/styles.ts @@ -0,0 +1,16 @@ +import { Col } from 'antd'; +import Card from 'antd/es/card/Card'; +import styled from 'styled-components'; + +export const Container = styled(Card)` + border: none; + background: inherit; + + .ant-card-body { + padding: 0; + } +`; + +export const ButtonWrapper = styled(Col)` + margin-left: auto; +`; diff --git a/frontend/src/container/TracesExplorer/TimeSeriesView/index.tsx b/frontend/src/container/TracesExplorer/TimeSeriesView/index.tsx new file mode 100644 index 0000000000..ee531d7f40 --- /dev/null +++ b/frontend/src/container/TracesExplorer/TimeSeriesView/index.tsx @@ -0,0 +1,73 @@ +import Graph from 'components/Graph'; +import Spinner from 'components/Spinner'; +import { initialQueriesMap } from 'constants/queryBuilder'; +import { REACT_QUERY_KEY } from 'constants/reactQueryKeys'; +import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange'; +import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; +import getChartData from 'lib/getChartData'; +import { useMemo } from 'react'; +import { useSelector } from 'react-redux'; +import { AppState } from 'store/reducers'; +import { GlobalReducer } from 'types/reducer/globalTime'; + +import { Container, ErrorText } from './styles'; + +function TimeSeriesView(): JSX.Element { + const { stagedQuery } = useQueryBuilder(); + + const { selectedTime: globalSelectedTime, maxTime, minTime } = useSelector< + AppState, + GlobalReducer + >((state) => state.globalTime); + + const { data, isLoading, isError } = useGetQueryRange( + { + query: stagedQuery || initialQueriesMap.traces, + graphType: 'graph', + selectedTime: 'GLOBAL_TIME', + globalSelectedInterval: globalSelectedTime, + params: { + dataSource: 'traces', + }, + }, + { + queryKey: [ + REACT_QUERY_KEY.GET_QUERY_RANGE, + globalSelectedTime, + stagedQuery, + maxTime, + minTime, + ], + enabled: !!stagedQuery, + }, + ); + + const chartData = useMemo( + () => + getChartData({ + queryData: [ + { + queryData: data?.payload?.data?.result || [], + }, + ], + }), + [data], + ); + + return ( + + {isLoading && } + {isError && {data?.error || 'Something went wrong'}} + {!isLoading && !isError && ( + + )} + + ); +} + +export default TimeSeriesView; diff --git a/frontend/src/container/TracesExplorer/TimeSeriesView/styles.ts b/frontend/src/container/TracesExplorer/TimeSeriesView/styles.ts new file mode 100644 index 0000000000..9f002e047f --- /dev/null +++ b/frontend/src/container/TracesExplorer/TimeSeriesView/styles.ts @@ -0,0 +1,17 @@ +import { Typography } from 'antd'; +import Card from 'antd/es/card/Card'; +import styled from 'styled-components'; + +export const Container = styled(Card)` + position: relative; + margin: 0.5rem 0 3.1rem 0; + + .ant-card-body { + height: 50vh; + min-height: 350px; + } +`; + +export const ErrorText = styled(Typography)` + text-align: center; +`; diff --git a/frontend/src/lib/dashbaordVariables/getDashboardVariables.ts b/frontend/src/lib/dashbaordVariables/getDashboardVariables.ts index 05707b5fa1..e9f4f1c6e1 100644 --- a/frontend/src/lib/dashbaordVariables/getDashboardVariables.ts +++ b/frontend/src/lib/dashbaordVariables/getDashboardVariables.ts @@ -1,5 +1,4 @@ -import GetMinMax from 'lib/getMinMax'; -import GetStartAndEndTime from 'lib/getStartAndEndTime'; +import getStartEndRangeTime from 'lib/getStartEndRangeTime'; import store from 'store'; export const getDashboardVariables = (): Record => { @@ -13,16 +12,11 @@ export const getDashboardVariables = (): Record => { data: { variables = {} }, } = selectedDashboard; - const minMax = GetMinMax(globalTime.selectedTime, [ - globalTime.minTime / 1000000, - globalTime.maxTime / 1000000, - ]); - - const { start, end } = GetStartAndEndTime({ + const { start, end } = getStartEndRangeTime({ type: 'GLOBAL_TIME', - minTime: minMax.minTime, - maxTime: minMax.maxTime, + interval: globalTime.selectedTime, }); + const variablesTuple: Record = { SIGNOZ_START_TIME: parseInt(start, 10) * 1e3, SIGNOZ_END_TIME: parseInt(end, 10) * 1e3, diff --git a/frontend/src/lib/getStartEndRangeTime.ts b/frontend/src/lib/getStartEndRangeTime.ts new file mode 100644 index 0000000000..486b6d0784 --- /dev/null +++ b/frontend/src/lib/getStartEndRangeTime.ts @@ -0,0 +1,48 @@ +import { ITEMS } from 'container/NewDashboard/ComponentsSlider/menuItems'; +import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems'; +import { Time } from 'container/TopNav/DateTimeSelection/config'; +import store from 'store'; + +import getMaxMinTime from './getMaxMinTime'; +import getMinMax from './getMinMax'; +import getStartAndEndTime from './getStartAndEndTime'; + +const getStartEndRangeTime = ({ + type = 'GLOBAL_TIME', + graphType = null, + interval = 'custom', +}: GetStartEndRangeTimesProps): GetStartEndRangeTimesPayload => { + const { globalTime } = store.getState(); + + const minMax = getMinMax(interval, [ + globalTime.minTime / 1000000, + globalTime.maxTime / 1000000, + ]); + + const maxMinTime = getMaxMinTime({ + graphType, + maxTime: minMax.maxTime, + minTime: minMax.minTime, + }); + + const { end, start } = getStartAndEndTime({ + type, + maxTime: maxMinTime.maxTime, + minTime: maxMinTime.minTime, + }); + + return { start, end }; +}; + +interface GetStartEndRangeTimesProps { + type?: timePreferenceType; + graphType?: ITEMS | null; + interval?: Time; +} + +interface GetStartEndRangeTimesPayload { + start: string; + end: string; +} + +export default getStartEndRangeTime; diff --git a/frontend/src/pages/TracesExplorer/constants.ts b/frontend/src/pages/TracesExplorer/constants.ts new file mode 100644 index 0000000000..ceea4e582e --- /dev/null +++ b/frontend/src/pages/TracesExplorer/constants.ts @@ -0,0 +1,6 @@ +export const CURRENT_TRACES_EXPLORER_TAB = 'currentTab'; + +export enum TracesExplorerTabs { + TIME_SERIES = 'times-series', + TRACES = 'traces', +} diff --git a/frontend/src/pages/TracesExplorer/index.tsx b/frontend/src/pages/TracesExplorer/index.tsx new file mode 100644 index 0000000000..57c2310d78 --- /dev/null +++ b/frontend/src/pages/TracesExplorer/index.tsx @@ -0,0 +1,59 @@ +import { Tabs } from 'antd'; +import { initialQueriesMap } from 'constants/queryBuilder'; +import QuerySection from 'container/TracesExplorer/QuerySection'; +import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl'; +import useUrlQuery from 'hooks/useUrlQuery'; +import { useCallback, useEffect } from 'react'; +import { useHistory, useLocation } from 'react-router-dom'; + +import { CURRENT_TRACES_EXPLORER_TAB, TracesExplorerTabs } from './constants'; +import { Container } from './styles'; +import { getTabsItems } from './utils'; + +function TracesExplorer(): JSX.Element { + const urlQuery = useUrlQuery(); + const history = useHistory(); + const location = useLocation(); + + const currentUrlTab = urlQuery.get( + CURRENT_TRACES_EXPLORER_TAB, + ) as TracesExplorerTabs; + const currentTab = currentUrlTab || TracesExplorerTabs.TIME_SERIES; + const tabsItems = getTabsItems(); + + const redirectWithCurrentTab = useCallback( + (tabKey: string): void => { + urlQuery.set(CURRENT_TRACES_EXPLORER_TAB, tabKey); + const generatedUrl = `${location.pathname}?${urlQuery.toString()}`; + history.push(generatedUrl); + }, + [history, location, urlQuery], + ); + + const handleTabChange = useCallback( + (tabKey: string): void => { + redirectWithCurrentTab(tabKey); + }, + [redirectWithCurrentTab], + ); + + useShareBuilderUrl({ defaultValue: initialQueriesMap.traces }); + + useEffect(() => { + if (currentUrlTab) return; + + redirectWithCurrentTab(TracesExplorerTabs.TIME_SERIES); + }, [currentUrlTab, redirectWithCurrentTab]); + + return ( + <> + + + + + + + ); +} + +export default TracesExplorer; diff --git a/frontend/src/pages/TracesExplorer/styles.ts b/frontend/src/pages/TracesExplorer/styles.ts new file mode 100644 index 0000000000..6da55b8d4d --- /dev/null +++ b/frontend/src/pages/TracesExplorer/styles.ts @@ -0,0 +1,5 @@ +import styled from 'styled-components'; + +export const Container = styled.div` + margin: 1rem 0; +`; diff --git a/frontend/src/pages/TracesExplorer/utils.tsx b/frontend/src/pages/TracesExplorer/utils.tsx new file mode 100644 index 0000000000..aff29bba58 --- /dev/null +++ b/frontend/src/pages/TracesExplorer/utils.tsx @@ -0,0 +1,17 @@ +import { TabsProps } from 'antd'; +import TimeSeriesView from 'container/TracesExplorer/TimeSeriesView'; + +import { TracesExplorerTabs } from './constants'; + +export const getTabsItems = (): TabsProps['items'] => [ + { + label: 'Time Series', + key: TracesExplorerTabs.TIME_SERIES, + children: , + }, + { + label: 'Traces', + key: TracesExplorerTabs.TRACES, + children:
Traces tab
, + }, +]; diff --git a/frontend/src/store/actions/dashboard/getQueryResults.ts b/frontend/src/store/actions/dashboard/getQueryResults.ts index fff445e463..c139c232c3 100644 --- a/frontend/src/store/actions/dashboard/getQueryResults.ts +++ b/frontend/src/store/actions/dashboard/getQueryResults.ts @@ -5,19 +5,16 @@ import { getMetricsQueryRange } from 'api/metrics/getQueryRange'; import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems'; import { Time } from 'container/TopNav/DateTimeSelection/config'; -import GetMaxMinTime from 'lib/getMaxMinTime'; -import GetMinMax from 'lib/getMinMax'; -import GetStartAndEndTime from 'lib/getStartAndEndTime'; import getStep from 'lib/getStep'; import { mapQueryDataToApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataToApi'; import { isEmpty } from 'lodash-es'; -import store from 'store'; import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; import { SuccessResponse } from 'types/api'; import { Query } from 'types/api/queryBuilder/queryBuilderData'; import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; import { EQueryType } from 'types/common/dashboard'; import { convertNewDataToOld } from 'lib/newQueryBuilder/convertNewDataToOld'; +import getStartEndRangeTime from 'lib/getStartEndRangeTime'; export async function GetMetricQueryRange({ query, @@ -25,6 +22,7 @@ export async function GetMetricQueryRange({ graphType, selectedTime, variables = {}, + params = {}, }: GetQueryResultsProps): Promise> { const queryData = query[query.queryType]; let legendMap: Record = {}; @@ -83,30 +81,18 @@ export async function GetMetricQueryRange({ return; } - const { globalTime } = store.getState(); - - const minMax = GetMinMax(globalSelectedInterval, [ - globalTime.minTime / 1000000, - globalTime.maxTime / 1000000, - ]); - - const getMaxMinTime = GetMaxMinTime({ - graphType: null, - maxTime: minMax.maxTime, - minTime: minMax.minTime, - }); - - const { end, start } = GetStartAndEndTime({ + const { start, end } = getStartEndRangeTime({ type: selectedTime, - maxTime: getMaxMinTime.maxTime, - minTime: getMaxMinTime.minTime, + interval: globalSelectedInterval, }); + const response = await getMetricsQueryRange({ start: parseInt(start, 10) * 1e3, end: parseInt(end, 10) * 1e3, step: getStep({ start, end, inputFormat: 'ms' }), variables, ...QueryPayload, + ...params, }); if (response.statusCode >= 400) { throw new Error( @@ -148,4 +134,5 @@ export interface GetQueryResultsProps { selectedTime: timePreferenceType; globalSelectedInterval: Time; variables?: Record; + params?: Record; } diff --git a/frontend/src/utils/permission/index.ts b/frontend/src/utils/permission/index.ts index 9134bae30f..452d495fec 100644 --- a/frontend/src/utils/permission/index.ts +++ b/frontend/src/utils/permission/index.ts @@ -63,6 +63,7 @@ export const routePermission: Record = { SETTINGS: ['ADMIN', 'EDITOR', 'VIEWER'], SIGN_UP: ['ADMIN', 'EDITOR', 'VIEWER'], SOMETHING_WENT_WRONG: ['ADMIN', 'EDITOR', 'VIEWER'], + TRACES_EXPLORER: ['ADMIN', 'EDITOR', 'VIEWER'], TRACE: ['ADMIN', 'EDITOR', 'VIEWER'], TRACE_DETAIL: ['ADMIN', 'EDITOR', 'VIEWER'], UN_AUTHORIZED: ['ADMIN', 'EDITOR', 'VIEWER'], @@ -71,5 +72,4 @@ export const routePermission: Record = { LOGS: ['ADMIN', 'EDITOR', 'VIEWER'], LOGS_EXPLORER: ['ADMIN', 'EDITOR', 'VIEWER'], LIST_LICENSES: ['ADMIN'], - TRACE_EXPLORER: ['ADMIN', 'EDITOR', 'VIEWER'], }; From 96b94a619ea5d1ae6506d15e3281ae83b0d76cfb Mon Sep 17 00:00:00 2001 From: dnazarenkosignoz <134951516+dnazarenkosignoz@users.noreply.github.com> Date: Mon, 19 Jun 2023 16:37:44 +0300 Subject: [PATCH 30/37] feat: add the export panel (#2925) * feat: add the export panel * feat: dropdown overlay is updated to dropdown * chore: loading variable is updated for create dashboard * chore: export panel is updated --------- Co-authored-by: Nazarenko19 Co-authored-by: Palash Gupta --- frontend/src/constants/reactQueryKeys.ts | 1 + .../src/container/ExportPanel/ExportPanel.tsx | 113 ++++++++++++++++++ frontend/src/container/ExportPanel/config.ts | 9 ++ frontend/src/container/ExportPanel/index.tsx | 70 +++++++++++ frontend/src/container/ExportPanel/styles.ts | 33 +++++ frontend/src/container/ExportPanel/utils.ts | 10 ++ 6 files changed, 236 insertions(+) create mode 100644 frontend/src/container/ExportPanel/ExportPanel.tsx create mode 100644 frontend/src/container/ExportPanel/config.ts create mode 100644 frontend/src/container/ExportPanel/index.tsx create mode 100644 frontend/src/container/ExportPanel/styles.ts create mode 100644 frontend/src/container/ExportPanel/utils.ts diff --git a/frontend/src/constants/reactQueryKeys.ts b/frontend/src/constants/reactQueryKeys.ts index 920bba6e7b..c4997dd45b 100644 --- a/frontend/src/constants/reactQueryKeys.ts +++ b/frontend/src/constants/reactQueryKeys.ts @@ -1,4 +1,5 @@ export const REACT_QUERY_KEY = { GET_ALL_LICENCES: 'GET_ALL_LICENCES', GET_QUERY_RANGE: 'GET_QUERY_RANGE', + GET_ALL_DASHBOARDS: 'GET_ALL_DASHBOARDS', }; diff --git a/frontend/src/container/ExportPanel/ExportPanel.tsx b/frontend/src/container/ExportPanel/ExportPanel.tsx new file mode 100644 index 0000000000..2cd24e25d1 --- /dev/null +++ b/frontend/src/container/ExportPanel/ExportPanel.tsx @@ -0,0 +1,113 @@ +import { Button, Typography } from 'antd'; +import createDashboard from 'api/dashboard/create'; +import getAll from 'api/dashboard/getAll'; +import axios from 'axios'; +import { REACT_QUERY_KEY } from 'constants/reactQueryKeys'; +import { useNotifications } from 'hooks/useNotifications'; +import { useCallback, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useMutation, useQuery } from 'react-query'; + +import { ExportPanelProps } from '.'; +import { + DashboardSelect, + NewDashboardButton, + SelectWrapper, + Title, + Wrapper, +} from './styles'; +import { getSelectOptions } from './utils'; + +function ExportPanel({ onExport }: ExportPanelProps): JSX.Element { + const { notifications } = useNotifications(); + const { t } = useTranslation(['dashboard']); + + const [selectedDashboardId, setSelectedDashboardId] = useState( + null, + ); + + const { data, isLoading, refetch } = useQuery({ + queryFn: getAll, + queryKey: REACT_QUERY_KEY.GET_ALL_DASHBOARDS, + }); + + const { + mutate: createNewDashboard, + isLoading: createDashboardLoading, + } = useMutation(createDashboard, { + onSuccess: () => { + refetch(); + }, + onError: (error) => { + if (axios.isAxiosError(error)) { + notifications.error({ + message: error.message, + }); + } + }, + }); + + const options = useMemo(() => getSelectOptions(data?.payload || []), [data]); + + const handleExportClick = useCallback((): void => { + const currentSelectedDashboard = data?.payload?.find( + ({ uuid }) => uuid === selectedDashboardId, + ); + + onExport(currentSelectedDashboard || null); + }, [data, selectedDashboardId, onExport]); + + const handleSelect = useCallback( + (selectedDashboardValue: string): void => { + setSelectedDashboardId(selectedDashboardValue); + }, + [setSelectedDashboardId], + ); + + const handleNewDashboard = useCallback(async () => { + createNewDashboard({ + title: t('new_dashboard_title', { + ns: 'dashboard', + }), + uploadedGrafana: false, + }); + }, [t, createNewDashboard]); + + return ( + + Export Panel + + + + + + + + Or create dashboard with this panel - + + New Dashboard + + + + ); +} + +export default ExportPanel; diff --git a/frontend/src/container/ExportPanel/config.ts b/frontend/src/container/ExportPanel/config.ts new file mode 100644 index 0000000000..a70d996b79 --- /dev/null +++ b/frontend/src/container/ExportPanel/config.ts @@ -0,0 +1,9 @@ +export const MENU_KEY = { + EXPORT: 'export', + CREATE_ALERTS: 'create-alerts', +}; + +export const MENU_LABEL = { + EXPORT: 'Export Panel', + CREATE_ALERTS: 'Create Alerts', +}; diff --git a/frontend/src/container/ExportPanel/index.tsx b/frontend/src/container/ExportPanel/index.tsx new file mode 100644 index 0000000000..a1673b541c --- /dev/null +++ b/frontend/src/container/ExportPanel/index.tsx @@ -0,0 +1,70 @@ +import { Button, Dropdown, MenuProps, Modal } from 'antd'; +import { useCallback, useMemo, useState } from 'react'; +import { Dashboard } from 'types/api/dashboard/getAll'; + +import { MENU_KEY, MENU_LABEL } from './config'; +import ExportPanelContainer from './ExportPanel'; + +function ExportPanel({ onExport }: ExportPanelProps): JSX.Element { + const [isExport, setIsExport] = useState(false); + + const onModalToggle = useCallback((value: boolean) => { + setIsExport(value); + }, []); + + const onMenuClickHandler: MenuProps['onClick'] = useCallback( + (e: OnClickProps) => { + if (e.key === MENU_KEY.EXPORT) { + onModalToggle(true); + } + }, + [onModalToggle], + ); + + const menu: MenuProps = useMemo( + () => ({ + items: [ + { + key: MENU_KEY.EXPORT, + label: MENU_LABEL.EXPORT, + }, + { + key: MENU_KEY.CREATE_ALERTS, + label: MENU_LABEL.CREATE_ALERTS, + }, + ], + onClick: onMenuClickHandler, + }), + [onMenuClickHandler], + ); + + const onCancel = (value: boolean) => (): void => { + onModalToggle(value); + }; + + return ( + <> + + + + + + + + ); +} + +interface OnClickProps { + key: string; +} + +export interface ExportPanelProps { + onExport: (dashboard: Dashboard | null) => void; +} + +export default ExportPanel; diff --git a/frontend/src/container/ExportPanel/styles.ts b/frontend/src/container/ExportPanel/styles.ts new file mode 100644 index 0000000000..8aa3f2fde8 --- /dev/null +++ b/frontend/src/container/ExportPanel/styles.ts @@ -0,0 +1,33 @@ +import { Button, Select, SelectProps, Space, Typography } from 'antd'; +import { FunctionComponent } from 'react'; +import styled from 'styled-components'; + +export const DashboardSelect: FunctionComponent = styled( + Select, +)` + width: 100%; +`; + +export const SelectWrapper = styled(Space)` + width: 100%; + margin-bottom: 1rem; + + .ant-space-item:first-child { + width: 100%; + max-width: 20rem; + } +`; + +export const Wrapper = styled(Space)` + width: 100%; +`; + +export const NewDashboardButton = styled(Button)` + &&& { + padding: 0 0.125rem; + } +`; + +export const Title = styled(Typography.Text)` + font-size: 1rem; +`; diff --git a/frontend/src/container/ExportPanel/utils.ts b/frontend/src/container/ExportPanel/utils.ts new file mode 100644 index 0000000000..128de92324 --- /dev/null +++ b/frontend/src/container/ExportPanel/utils.ts @@ -0,0 +1,10 @@ +import { SelectProps } from 'antd'; +import { PayloadProps as AllDashboardsData } from 'types/api/dashboard/getAll'; + +export const getSelectOptions = ( + data: AllDashboardsData, +): SelectProps['options'] => + data.map(({ uuid, data }) => ({ + label: data.title, + value: uuid, + })); From 0d82a93f183a5a22630628ea383bb3b71cf1bf65 Mon Sep 17 00:00:00 2001 From: Rajat Dabade Date: Tue, 20 Jun 2023 09:07:19 +0530 Subject: [PATCH 31/37] fix: fixed the initial graph load issue for dashboard (#2938) --- frontend/src/container/GridGraphLayout/Graph/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/container/GridGraphLayout/Graph/index.tsx b/frontend/src/container/GridGraphLayout/Graph/index.tsx index 53d8ad4180..196ba14c03 100644 --- a/frontend/src/container/GridGraphLayout/Graph/index.tsx +++ b/frontend/src/container/GridGraphLayout/Graph/index.tsx @@ -54,7 +54,7 @@ function GridCardGraph({ const { ref: graphRef, inView: isGraphVisible } = useInView({ threshold: 0, triggerOnce: true, - initialInView: true, + initialInView: false, }); const { notifications } = useNotifications(); From 9e305cb672405da5592719f96491ef8521a5fcac Mon Sep 17 00:00:00 2001 From: Vishal Sharma Date: Wed, 21 Jun 2023 11:47:30 +0530 Subject: [PATCH 32/37] feat: add zap otel logger support (#2790) * feat: add zap otel logger support --- ee/query-service/app/server.go | 4 +- ee/query-service/main.go | 57 ++++++++++++++++- go.mod | 33 ++++++---- go.sum | 79 +++++++++++++++--------- pkg/query-service/app/server.go | 4 +- pkg/query-service/constants/constants.go | 3 + 6 files changed, 131 insertions(+), 49 deletions(-) diff --git a/ee/query-service/app/server.go b/ee/query-service/app/server.go index 315a211f9f..942ed24ced 100644 --- a/ee/query-service/app/server.go +++ b/ee/query-service/app/server.go @@ -277,7 +277,7 @@ func loggingMiddleware(next http.Handler) http.Handler { path, _ := route.GetPathTemplate() startTime := time.Now() next.ServeHTTP(w, r) - zap.S().Info(path, "\ttimeTaken: ", time.Now().Sub(startTime)) + zap.L().Info(path+"\ttimeTaken:"+time.Now().Sub(startTime).String(), zap.Duration("timeTaken", time.Now().Sub(startTime)), zap.String("path", path)) }) } @@ -289,7 +289,7 @@ func loggingMiddlewarePrivate(next http.Handler) http.Handler { path, _ := route.GetPathTemplate() startTime := time.Now() next.ServeHTTP(w, r) - zap.S().Info(path, "\tprivatePort: true", "\ttimeTaken: ", time.Now().Sub(startTime)) + zap.L().Info(path+"\tprivatePort: true \ttimeTaken"+time.Now().Sub(startTime).String(), zap.Duration("timeTaken", time.Now().Sub(startTime)), zap.String("path", path), zap.Bool("tprivatePort", true)) }) } diff --git a/ee/query-service/main.go b/ee/query-service/main.go index e29b86797a..6d38fb9f65 100644 --- a/ee/query-service/main.go +++ b/ee/query-service/main.go @@ -3,25 +3,73 @@ package main import ( "context" "flag" + "log" "os" "os/signal" + "strconv" "syscall" + "time" + "go.opentelemetry.io/otel/sdk/resource" + semconv "go.opentelemetry.io/otel/semconv/v1.4.0" "go.signoz.io/signoz/ee/query-service/app" "go.signoz.io/signoz/pkg/query-service/auth" + "go.signoz.io/signoz/pkg/query-service/constants" baseconst "go.signoz.io/signoz/pkg/query-service/constants" "go.signoz.io/signoz/pkg/query-service/version" + "google.golang.org/grpc" + + zapotlpencoder "github.com/SigNoz/zap_otlp/zap_otlp_encoder" + zapotlpsync "github.com/SigNoz/zap_otlp/zap_otlp_sync" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) -func initZapLog() *zap.Logger { +func initZapLog(enableQueryServiceLogOTLPExport bool) *zap.Logger { config := zap.NewDevelopmentConfig() + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) + defer stop() + + config.EncoderConfig.EncodeDuration = zapcore.StringDurationEncoder + otlpEncoder := zapotlpencoder.NewOTLPEncoder(config.EncoderConfig) + consoleEncoder := zapcore.NewConsoleEncoder(config.EncoderConfig) + defaultLogLevel := zapcore.DebugLevel config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder config.EncoderConfig.TimeKey = "timestamp" config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder - logger, _ := config.Build() + + res := resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String("query-service"), + ) + + core := zapcore.NewTee( + zapcore.NewCore(consoleEncoder, os.Stdout, defaultLogLevel), + ) + + if enableQueryServiceLogOTLPExport == true { + conn, err := grpc.DialContext(ctx, constants.OTLPTarget, grpc.WithBlock(), grpc.WithInsecure(), grpc.WithTimeout(time.Second*30)) + if err != nil { + log.Println("failed to connect to otlp collector to export query service logs with error:", err) + } else { + logExportBatchSizeInt, err := strconv.Atoi(baseconst.LogExportBatchSize) + if err != nil { + logExportBatchSizeInt = 1000 + } + ws := zapcore.AddSync(zapotlpsync.NewOtlpSyncer(conn, zapotlpsync.Options{ + BatchSize: logExportBatchSizeInt, + ResourceSchema: semconv.SchemaURL, + Resource: res, + })) + core = zapcore.NewTee( + zapcore.NewCore(consoleEncoder, os.Stdout, defaultLogLevel), + zapcore.NewCore(otlpEncoder, zapcore.NewMultiWriteSyncer(ws), defaultLogLevel), + ) + } + } + logger := zap.New(core, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel)) + return logger } @@ -34,12 +82,15 @@ func main() { // the url used to build link in the alert messages in slack and other systems var ruleRepoURL string + var enableQueryServiceLogOTLPExport bool + flag.StringVar(&promConfigPath, "config", "./config/prometheus.yml", "(prometheus config to read metrics)") flag.BoolVar(&disableRules, "rules.disable", false, "(disable rule evaluation)") flag.StringVar(&ruleRepoURL, "rules.repo-url", baseconst.AlertHelpPage, "(host address used to build rule link in alert messages)") + flag.BoolVar(&enableQueryServiceLogOTLPExport, "enable.query.service.log.otlp.export", false, "(enable query service log otlp export)") flag.Parse() - loggerMgr := initZapLog() + loggerMgr := initZapLog(enableQueryServiceLogOTLPExport) zap.ReplaceGlobals(loggerMgr) defer loggerMgr.Sync() // flushes buffer, if any diff --git a/go.mod b/go.mod index ef31d473ed..753e8fd613 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,8 @@ go 1.18 require ( github.com/ClickHouse/clickhouse-go/v2 v2.5.1 github.com/SigNoz/govaluate v0.0.0-20220522085550-d19c08c206cb + github.com/SigNoz/zap_otlp/zap_otlp_encoder v0.0.0-20230523034029-2b7ff773052c + github.com/SigNoz/zap_otlp/zap_otlp_sync v0.0.0-20230517094211-cd3f3f0aea85 github.com/coreos/go-oidc/v3 v3.4.0 github.com/dustin/go-humanize v1.0.0 github.com/go-kit/log v0.2.1 @@ -33,9 +35,10 @@ require ( github.com/russellhaering/goxmldsig v1.2.0 github.com/samber/lo v1.38.1 github.com/sethvargo/go-password v0.2.0 - github.com/smartystreets/goconvey v1.6.4 + github.com/smartystreets/goconvey v1.8.0 github.com/soheilhy/cmux v0.1.5 go.opentelemetry.io/collector/confmap v0.70.0 + go.opentelemetry.io/otel/sdk v1.15.1 go.uber.org/zap v1.24.0 gopkg.in/segmentio/analytics-go.v3 v3.1.0 gopkg.in/yaml.v3 v3.0.1 @@ -50,7 +53,7 @@ require ( github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/go-faster/city v1.0.1 // indirect github.com/go-faster/errors v0.6.1 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/swag v0.22.1 // indirect github.com/go-sql-driver/mysql v1.6.0 // indirect @@ -69,6 +72,7 @@ require ( require ( github.com/ClickHouse/ch-go v0.51.0 // indirect + github.com/SigNoz/zap_otlp v0.0.0-20230517094211-cd3f3f0aea85 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/andybalholm/brotli v1.0.4 // indirect github.com/armon/go-metrics v0.4.0 // indirect @@ -77,6 +81,7 @@ require ( github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect github.com/gorilla/websocket v1.5.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.1 // indirect github.com/jonboulle/clockwork v0.2.2 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/klauspost/cpuid v1.2.3 // indirect @@ -88,6 +93,8 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.14.0 // indirect go.opentelemetry.io/collector/featuregate v0.70.0 // indirect + go.opentelemetry.io/proto/otlp v0.19.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect ) @@ -104,9 +111,9 @@ require ( github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect + github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/gosimple/unidecode v1.0.0 // indirect github.com/hashicorp/consul v1.1.1-0.20180615161029-bed22a81e9fd // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -127,24 +134,24 @@ require ( github.com/segmentio/backo-go v1.0.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.0 // indirect - github.com/smartystreets/assertions v1.1.0 + github.com/smartystreets/assertions v1.13.1 github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/stretchr/testify v1.8.2 github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect - go.opentelemetry.io/otel v1.11.2 // indirect - go.opentelemetry.io/otel/trace v1.11.2 // indirect + go.opentelemetry.io/otel v1.15.1 + go.opentelemetry.io/otel/trace v1.15.1 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.9.0 golang.org/x/crypto v0.1.0 - golang.org/x/net v0.4.0 - golang.org/x/oauth2 v0.3.0 + golang.org/x/net v0.8.0 + golang.org/x/oauth2 v0.6.0 golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect + golang.org/x/sys v0.7.0 // indirect + golang.org/x/text v0.8.0 // indirect golang.org/x/time v0.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/grpc v1.51.0 - google.golang.org/protobuf v1.28.1 + google.golang.org/grpc v1.55.0 + google.golang.org/protobuf v1.30.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index d43d43782b..5e49f85e71 100644 --- a/go.sum +++ b/go.sum @@ -79,6 +79,12 @@ 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.77-0.2 h1:y5HpJR6RYkOd5ysP9rSsLgoGMj0A7EvP5cbqp5XY0Mc= github.com/SigNoz/prometheus v1.9.77-0.2/go.mod h1:bT6BCBpZQA4qOO8oJPvcZr80XpbZcn7go6503fxpYj4= +github.com/SigNoz/zap_otlp v0.0.0-20230517094211-cd3f3f0aea85 h1:Q8yY/S8tetcuZF02XHXSYZzxn9n3voEF82XKJjvxJgk= +github.com/SigNoz/zap_otlp v0.0.0-20230517094211-cd3f3f0aea85/go.mod h1:crDWweGk4YMuJM58GNkasbV/Z2D37px3PS4DpUuTbYg= +github.com/SigNoz/zap_otlp/zap_otlp_encoder v0.0.0-20230523034029-2b7ff773052c h1:jx+NF9RsxKZ24y/iBlPN6NIVjYBMlUeCTGsFLLna1Sw= +github.com/SigNoz/zap_otlp/zap_otlp_encoder v0.0.0-20230523034029-2b7ff773052c/go.mod h1:HRisMAQR1ndayIyjklWlJy6xWCZU8EWMaZSJK4w+GrA= +github.com/SigNoz/zap_otlp/zap_otlp_sync v0.0.0-20230517094211-cd3f3f0aea85 h1:r8P7AbNkivf6CElyMEaxUFzwAkuJ0wbX2vMqPgLqRA8= +github.com/SigNoz/zap_otlp/zap_otlp_sync v0.0.0-20230517094211-cd3f3f0aea85/go.mod h1:e68FpYSwt1ujeEgKTFs+6c7BRmPxgI6mxm+P4+zBNLY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -143,7 +149,7 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc h1:PYXxkRUBGUMa5xgMVMDl62vEklZvKpVaxQeN9ie7Hfk= +github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195 h1:58f1tJ1ra+zFINPlwLWvQsR9CzAKt2e+EWV2yX9oXQ4= github.com/coreos/go-oidc/v3 v3.4.0 h1:xz7elHb/LDwm/ERpwHd+5nb7wFHL32rsr6bBOgaeu6g= github.com/coreos/go-oidc/v3 v3.4.0/go.mod h1:eHUXhZtXPQLgEaDrOVTgwbgmz1xGOkJNye6h3zkD2Pw= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -177,9 +183,9 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/go-control-plane v0.10.3 h1:xdCVXxEe0Y3FQith+0cj2irwZudqGYvecuLB1HtdexY= +github.com/envoyproxy/go-control-plane v0.11.0 h1:jtLewhRR2vMRNnq2ZZUoCjUlgut+Y0+sDDWPOfwOi1o= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.9.1 h1:PS7VIOgmSVhWUEeZwTe7z7zouA22Cr590PzXKbZHOVY= +github.com/envoyproxy/protoc-gen-validate v0.10.0 h1:oIfnZFdC0YhpNNEX+SuIqko4cqqVZeN9IGTrhZje83Y= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= @@ -215,8 +221,8 @@ github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNV github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= @@ -243,6 +249,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -271,8 +279,9 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= @@ -332,8 +341,9 @@ github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/gophercloud/gophercloud v1.1.1 h1:MuGyqbSxiuVBqkPZ3+Nhbytk1xZxhmfCB2Rg1cJWFWM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= +github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= @@ -349,6 +359,9 @@ github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.1 h1:/sDbPb60SusIXjiJGYLUoS/rAQurQmvGWmwn2bBPM9c= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.1/go.mod h1:G+WkljZi4mflcqVxYSgvt8MNctRQHjEH8ubKtt1Ka3w= github.com/hashicorp/consul v1.1.1-0.20180615161029-bed22a81e9fd h1:u6o+bd6FHxDKoCSa8PJ5vrHhAYSKgJtAHQtLO1EYgos= github.com/hashicorp/consul v1.1.1-0.20180615161029-bed22a81e9fd/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI= github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ= @@ -627,11 +640,13 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0= github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/assertions v1.13.1 h1:Ef7KhSmjZcK6AVf9YbJdvPYG9avaF0ZxudX+ThRdWfU= +github.com/smartystreets/assertions v1.13.1/go.mod h1:cXr/IwVfSo/RbCSPhoAPv73p3hlSdrBH/b3SdnW/LMY= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.8.0 h1:Oi49ha/2MURE0WexF052Z0m+BNSGirfjg5RL+JXWq3w= +github.com/smartystreets/goconvey v1.8.0/go.mod h1:EdX8jtrTIj26jmjCOVNMVSIYAtgexqXKHOXW2Dx9JLg= 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/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -682,13 +697,17 @@ go.opentelemetry.io/collector/featuregate v0.70.0 h1:Xr6hrMT/++SjTm06nreex8WlpgF go.opentelemetry.io/collector/featuregate v0.70.0/go.mod h1:ih+oCwrHW3bLac/qnPUzes28yDCDmh8WzsAKKauwCYI= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0 h1:yt2NKzK7Vyo6h0+X8BA4FpreZQTlVEIarnsBP/H5mzs= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0/go.mod h1:+ARmXlUlc51J7sZeCBkBJNdHGySrdOzgzxp6VWRWM1U= -go.opentelemetry.io/otel v1.11.2 h1:YBZcQlsVekzFsFbjygXMOXSs6pialIZxcjfO/mBDmR0= -go.opentelemetry.io/otel v1.11.2/go.mod h1:7p4EUV+AqgdlNV9gL97IgUZiVR3yrFXYo53f9BM3tRI= +go.opentelemetry.io/otel v1.15.1 h1:3Iwq3lfRByPaws0f6bU3naAqOR1n5IeDWd9390kWHa8= +go.opentelemetry.io/otel v1.15.1/go.mod h1:mHHGEHVDLal6YrKMmk9LqC4a3sF5g+fHfrttQIB1NTc= go.opentelemetry.io/otel/metric v0.34.0 h1:MCPoQxcg/26EuuJwpYN1mZTeCYAUGx8ABxfW07YkjP8= go.opentelemetry.io/otel/metric v0.34.0/go.mod h1:ZFuI4yQGNCupurTXCwkeD/zHBt+C2bR7bw5JqUm/AP8= -go.opentelemetry.io/otel/trace v1.11.2 h1:Xf7hWSF2Glv0DE3MH7fBHvtpSBsjcBUe5MYAmZM/+y0= -go.opentelemetry.io/otel/trace v1.11.2/go.mod h1:4N+yC7QEz7TTsG9BSRLNAa63eg5E06ObSbKPmxQ/pKA= +go.opentelemetry.io/otel/sdk v1.15.1 h1:5FKR+skgpzvhPQHIEfcwMYjCBr14LWzs3uSqKiQzETI= +go.opentelemetry.io/otel/sdk v1.15.1/go.mod h1:8rVtxQfrbmbHKfqzpQkT5EzZMcbMBwTzNAggbEAM0KA= +go.opentelemetry.io/otel/trace v1.15.1 h1:uXLo6iHJEzDfrNC0L0mNjItIp06SyaBQxu5t3xMlngY= +go.opentelemetry.io/otel/trace v1.15.1/go.mod h1:IWdQG/5N1x7f6YUlmdLeJvH9yxtuJAfc4VW5Agv9r/8= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= @@ -750,7 +769,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -806,8 +825,8 @@ golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -829,8 +848,8 @@ golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.3.0 h1:6l90koy8/LaBLmLu8jpHeHexzMwEita0zFfYlggy2F8= -golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= +golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -933,12 +952,12 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= +golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -950,8 +969,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1014,7 +1033,7 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1148,7 +1167,8 @@ google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20221207170731-23e4bf6bdc37 h1:jmIfw8+gSvXcZSgaFAGyInDXeWzUhvYH57G/5GKMn70= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -1177,13 +1197,14 @@ google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= 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.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= +google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= 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= @@ -1199,8 +1220,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/query-service/app/server.go b/pkg/query-service/app/server.go index 78101ea406..10a172e000 100644 --- a/pkg/query-service/app/server.go +++ b/pkg/query-service/app/server.go @@ -220,7 +220,7 @@ func loggingMiddleware(next http.Handler) http.Handler { path, _ := route.GetPathTemplate() startTime := time.Now() next.ServeHTTP(w, r) - zap.S().Info(path, "\ttimeTaken: ", time.Now().Sub(startTime)) + zap.S().Info(path+"\ttimeTaken:"+time.Now().Sub(startTime).String(), zap.Duration("timeTaken", time.Now().Sub(startTime)), zap.String("path", path)) }) } @@ -232,7 +232,7 @@ func loggingMiddlewarePrivate(next http.Handler) http.Handler { path, _ := route.GetPathTemplate() startTime := time.Now() next.ServeHTTP(w, r) - zap.S().Info(path, "\tprivatePort: true", "\ttimeTaken: ", time.Now().Sub(startTime)) + zap.S().Info(path+"\tprivatePort: true \ttimeTaken"+time.Now().Sub(startTime).String(), zap.Duration("timeTaken", time.Now().Sub(startTime)), zap.String("path", path), zap.Bool("tprivatePort", true)) }) } diff --git a/pkg/query-service/constants/constants.go b/pkg/query-service/constants/constants.go index 853a1b5c09..d86d6df205 100644 --- a/pkg/query-service/constants/constants.go +++ b/pkg/query-service/constants/constants.go @@ -46,6 +46,9 @@ func GetAlertManagerApiPrefix() string { // Alert manager channel subpath var AmChannelApiPath = GetOrDefaultEnv("ALERTMANAGER_API_CHANNEL_PATH", "v1/routes") +var OTLPTarget = GetOrDefaultEnv("OTLP_TARGET", "") +var LogExportBatchSize = GetOrDefaultEnv("LOG_EXPORT_BATCH_SIZE", "1000") + var RELATIONAL_DATASOURCE_PATH = GetOrDefaultEnv("SIGNOZ_LOCAL_DB_PATH", "/var/lib/signoz/signoz.db") var DurationSortFeature = GetOrDefaultEnv("DURATION_SORT_FEATURE", "true") From cf05345ccd800400fe1aca933289b9c186d8d604 Mon Sep 17 00:00:00 2001 From: Palash Gupta Date: Wed, 21 Jun 2023 13:33:06 +0530 Subject: [PATCH 33/37] fix: white screen issue is fixed when cloning the panel (#2944) --- frontend/src/hooks/queryBuilder/useGetWidgetQueryRange.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/hooks/queryBuilder/useGetWidgetQueryRange.ts b/frontend/src/hooks/queryBuilder/useGetWidgetQueryRange.ts index f3eaa9914c..289e6c9f1a 100644 --- a/frontend/src/hooks/queryBuilder/useGetWidgetQueryRange.ts +++ b/frontend/src/hooks/queryBuilder/useGetWidgetQueryRange.ts @@ -33,7 +33,7 @@ export const useGetWidgetQueryRange = ( graphType, selectedTime, globalSelectedInterval, - query: JSON.parse(compositeQuery || ''), + query: JSON.parse(compositeQuery || '{}'), variables: getDashboardVariables(), }, { From 3f4cd130ed63f9838e11ede2e9a41526879b95ca Mon Sep 17 00:00:00 2001 From: Palash Gupta Date: Wed, 21 Jun 2023 16:46:11 +0530 Subject: [PATCH 34/37] fix: feature flag is added when we are switching the tab (#2930) --- .../src/container/FormAlertRules/QuerySection.tsx | 11 ++++++++++- .../NewWidget/LeftContainer/QuerySection/index.tsx | 8 +++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/frontend/src/container/FormAlertRules/QuerySection.tsx b/frontend/src/container/FormAlertRules/QuerySection.tsx index b8c88ab683..4ccac39fc4 100644 --- a/frontend/src/container/FormAlertRules/QuerySection.tsx +++ b/frontend/src/container/FormAlertRules/QuerySection.tsx @@ -4,8 +4,11 @@ import { PANEL_TYPES } from 'constants/queryBuilder'; import { QueryBuilder } from 'container/QueryBuilder'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; +import { useSelector } from 'react-redux'; +import { AppState } from 'store/reducers'; import { AlertTypes } from 'types/api/alerts/alertTypes'; import { EQueryType } from 'types/common/dashboard'; +import AppReducer from 'types/reducer/app'; import ChQuerySection from './ChQuerySection'; import PromqlSection from './PromqlSection'; @@ -20,8 +23,14 @@ function QuerySection({ // init namespace for translations const { t } = useTranslation('alerts'); + const { featureResponse } = useSelector( + (state) => state.app, + ); + const handleQueryCategoryChange = (queryType: string): void => { - setQueryCategory(queryType as EQueryType); + featureResponse.refetch().then(() => { + setQueryCategory(queryType as EQueryType); + }); }; const renderPromqlUI = (): JSX.Element => ; diff --git a/frontend/src/container/NewWidget/LeftContainer/QuerySection/index.tsx b/frontend/src/container/NewWidget/LeftContainer/QuerySection/index.tsx index 655ecaaee7..d3e52120b3 100644 --- a/frontend/src/container/NewWidget/LeftContainer/QuerySection/index.tsx +++ b/frontend/src/container/NewWidget/LeftContainer/QuerySection/index.tsx @@ -20,6 +20,7 @@ import AppActions from 'types/actions'; import { Widgets } from 'types/api/dashboard/getAll'; import { Query } from 'types/api/queryBuilder/queryBuilderData'; import { EQueryType } from 'types/common/dashboard'; +import AppReducer from 'types/reducer/app'; import DashboardReducer from 'types/reducer/dashboards'; import ClickHouseQueryContainer from './QueryBuilder/clickHouse'; @@ -32,6 +33,9 @@ function QuerySection({ }: QueryProps): JSX.Element { const { currentQuery, redirectWithQueryBuilderData } = useQueryBuilder(); const urlQuery = useUrlQuery(); + const { featureResponse } = useSelector( + (state) => state.app, + ); const { dashboards } = useSelector( (state) => state.dashboards, @@ -72,7 +76,9 @@ function QuerySection({ const handleQueryCategoryChange = (qCategory: string): void => { const currentQueryType = qCategory as EQueryType; - handleStageQuery({ ...currentQuery, queryType: currentQueryType }); + featureResponse.refetch().then(() => { + handleStageQuery({ ...currentQuery, queryType: currentQueryType }); + }); }; const handleRunQuery = (): void => { From a6237d8640f6b74201eb0febe3c2d209f069635f Mon Sep 17 00:00:00 2001 From: Palash Gupta Date: Wed, 21 Jun 2023 19:56:57 +0530 Subject: [PATCH 35/37] fix: save rules/dashboard is now enabled for metrics irrespective of feature flag disabled (#2946) * fix: save rules/dashboard is now enabled for metrics irrespective of feature flag disabled * chore: check is updated for alerts * chore: alert condition is updated * chore: condition for alert is updated --- .../src/container/FormAlertRules/index.tsx | 4 +-- frontend/src/container/NewWidget/index.tsx | 28 +++++++++++++------ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/frontend/src/container/FormAlertRules/index.tsx b/frontend/src/container/FormAlertRules/index.tsx index e903945fea..9db261afd0 100644 --- a/frontend/src/container/FormAlertRules/index.tsx +++ b/frontend/src/container/FormAlertRules/index.tsx @@ -380,8 +380,8 @@ function FormAlertRules({ const isAlertAvialableToSave = isAlertAvialable && - isNewRule && - currentQuery.queryType === EQueryType.QUERY_BUILDER; + currentQuery.queryType === EQueryType.QUERY_BUILDER && + alertType !== AlertTypes.METRICS_BASED_ALERT; return ( <> diff --git a/frontend/src/container/NewWidget/index.tsx b/frontend/src/container/NewWidget/index.tsx index 2352f506c5..3919f8fe12 100644 --- a/frontend/src/container/NewWidget/index.tsx +++ b/frontend/src/container/NewWidget/index.tsx @@ -20,6 +20,8 @@ import { import { AppState } from 'store/reducers'; import AppActions from 'types/actions'; import { FLUSH_DASHBOARD } from 'types/actions/dashboard'; +import { EQueryType } from 'types/common/dashboard'; +import { DataSource } from 'types/common/queryBuilder'; import AppReducer from 'types/reducer/app'; import DashboardReducer from 'types/reducer/dashboards'; @@ -161,15 +163,29 @@ function NewWidget({ selectedGraph, saveSettingOfPanel }: Props): JSX.Element { FeatureKeys.QUERY_BUILDER_PANELS, ); + const isSaveDisabled = useMemo( + () => + isQueryBuilderActive && + currentQuery.queryType === EQueryType.QUERY_BUILDER && + currentQuery.builder.queryData.find( + (query) => query.dataSource !== DataSource.METRICS, + ) !== undefined, + [ + currentQuery.builder.queryData, + currentQuery.queryType, + isQueryBuilderActive, + ], + ); + return ( - {isQueryBuilderActive && ( + {isSaveDisabled && ( )} From 4460b46e47d4cc47b013c4a346b9df661d382d7a Mon Sep 17 00:00:00 2001 From: Srikanth Chekuri Date: Wed, 21 Jun 2023 20:07:49 +0530 Subject: [PATCH 36/37] chore: bump SigNoz and collector versions --- deploy/docker-swarm/clickhouse-setup/docker-compose.yaml | 8 ++++---- deploy/docker/clickhouse-setup/docker-compose-core.yaml | 4 ++-- deploy/docker/clickhouse-setup/docker-compose.yaml | 8 ++++---- pkg/query-service/tests/test-deploy/docker-compose.yaml | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml b/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml index 2af03d4255..fec809c500 100644 --- a/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml +++ b/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml @@ -137,7 +137,7 @@ services: condition: on-failure query-service: - image: signoz/query-service:0.20.2 + image: signoz/query-service:0.21.0 command: ["-config=/root/config/prometheus.yml"] # ports: # - "6060:6060" # pprof port @@ -166,7 +166,7 @@ services: <<: *clickhouse-depend frontend: - image: signoz/frontend:0.20.2 + image: signoz/frontend:0.21.0 deploy: restart_policy: condition: on-failure @@ -179,7 +179,7 @@ services: - ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf otel-collector: - image: signoz/signoz-otel-collector:0.76.1 + image: signoz/signoz-otel-collector:0.79.1 command: ["--config=/etc/otel-collector-config.yaml", "--feature-gates=-pkg.translator.prometheus.NormalizeName"] user: root # required for reading docker container logs volumes: @@ -208,7 +208,7 @@ services: <<: *clickhouse-depend otel-collector-metrics: - image: signoz/signoz-otel-collector:0.76.1 + image: signoz/signoz-otel-collector:0.79.1 command: ["--config=/etc/otel-collector-metrics-config.yaml", "--feature-gates=-pkg.translator.prometheus.NormalizeName"] volumes: - ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml diff --git a/deploy/docker/clickhouse-setup/docker-compose-core.yaml b/deploy/docker/clickhouse-setup/docker-compose-core.yaml index e7b598ae38..84d2bdcd93 100644 --- a/deploy/docker/clickhouse-setup/docker-compose-core.yaml +++ b/deploy/docker/clickhouse-setup/docker-compose-core.yaml @@ -41,7 +41,7 @@ services: # Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md` otel-collector: container_name: otel-collector - image: signoz/signoz-otel-collector:0.76.1 + image: signoz/signoz-otel-collector:0.79.1 command: ["--config=/etc/otel-collector-config.yaml", "--feature-gates=-pkg.translator.prometheus.NormalizeName"] # user: root # required for reading docker container logs volumes: @@ -67,7 +67,7 @@ services: otel-collector-metrics: container_name: otel-collector-metrics - image: signoz/signoz-otel-collector:0.76.1 + image: signoz/signoz-otel-collector:0.79.1 command: ["--config=/etc/otel-collector-metrics-config.yaml", "--feature-gates=-pkg.translator.prometheus.NormalizeName"] volumes: - ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml diff --git a/deploy/docker/clickhouse-setup/docker-compose.yaml b/deploy/docker/clickhouse-setup/docker-compose.yaml index a270892a88..70441af123 100644 --- a/deploy/docker/clickhouse-setup/docker-compose.yaml +++ b/deploy/docker/clickhouse-setup/docker-compose.yaml @@ -153,7 +153,7 @@ services: # Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md` query-service: - image: signoz/query-service:${DOCKER_TAG:-0.20.2} + image: signoz/query-service:${DOCKER_TAG:-0.21.0} container_name: query-service command: ["-config=/root/config/prometheus.yml"] # ports: @@ -181,7 +181,7 @@ services: <<: *clickhouse-depend frontend: - image: signoz/frontend:${DOCKER_TAG:-0.20.2} + image: signoz/frontend:${DOCKER_TAG:-0.21.0} container_name: frontend restart: on-failure depends_on: @@ -193,7 +193,7 @@ services: - ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf otel-collector: - image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.76.1} + image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.79.1} command: ["--config=/etc/otel-collector-config.yaml", "--feature-gates=-pkg.translator.prometheus.NormalizeName"] user: root # required for reading docker container logs volumes: @@ -219,7 +219,7 @@ services: <<: *clickhouse-depend otel-collector-metrics: - image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.76.1} + image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.79.1} command: ["--config=/etc/otel-collector-metrics-config.yaml", "--feature-gates=-pkg.translator.prometheus.NormalizeName"] volumes: - ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml diff --git a/pkg/query-service/tests/test-deploy/docker-compose.yaml b/pkg/query-service/tests/test-deploy/docker-compose.yaml index fcb9c53175..057fa66ba2 100644 --- a/pkg/query-service/tests/test-deploy/docker-compose.yaml +++ b/pkg/query-service/tests/test-deploy/docker-compose.yaml @@ -169,7 +169,7 @@ services: <<: *clickhouse-depends otel-collector: - image: signoz/signoz-otel-collector:0.76.1 + image: signoz/signoz-otel-collector:0.79.1 command: ["--config=/etc/otel-collector-config.yaml", "--feature-gates=-pkg.translator.prometheus.NormalizeName"] user: root # required for reading docker container logs volumes: @@ -195,7 +195,7 @@ services: <<: *clickhouse-depends otel-collector-metrics: - image: signoz/signoz-otel-collector:0.76.1 + image: signoz/signoz-otel-collector:0.79.1 command: ["--config=/etc/otel-collector-metrics-config.yaml", "--feature-gates=-pkg.translator.prometheus.NormalizeName"] volumes: - ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml From 1c98d4f55c0426f1e9c2d5229dd852cfabfed722 Mon Sep 17 00:00:00 2001 From: Palash Gupta Date: Wed, 21 Jun 2023 20:56:15 +0530 Subject: [PATCH 37/37] fix: editing condition is updated (#2952) * fix: save rules/dashboard is now enabled for metrics irrespective of feature flag disabled * chore: check is updated for alerts * chore: alert condition is updated * chore: condition for alert is updated * fix: edit condition is fixed * fix: isTraceOrLogsQueryBuilder condition for editing a panel * fix: error message is shown to the user --------- Co-authored-by: makeavish --- frontend/src/container/NewWidget/index.tsx | 26 ++++++++++++++++++- .../store/actions/dashboard/saveDashboard.ts | 9 ++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/frontend/src/container/NewWidget/index.tsx b/frontend/src/container/NewWidget/index.tsx index 3919f8fe12..17cb4ea884 100644 --- a/frontend/src/container/NewWidget/index.tsx +++ b/frontend/src/container/NewWidget/index.tsx @@ -163,7 +163,7 @@ function NewWidget({ selectedGraph, saveSettingOfPanel }: Props): JSX.Element { FeatureKeys.QUERY_BUILDER_PANELS, ); - const isSaveDisabled = useMemo( + const isNewTraceLogsAvailable = useMemo( () => isQueryBuilderActive && currentQuery.queryType === EQueryType.QUERY_BUILDER && @@ -177,6 +177,30 @@ function NewWidget({ selectedGraph, saveSettingOfPanel }: Props): JSX.Element { ], ); + const isSaveDisabled = useMemo(() => { + // new created dashboard + if (selectedWidget?.id === 'empty') { + return isNewTraceLogsAvailable; + } + + const isTraceOrLogsQueryBuilder = + currentQuery.builder.queryData.find( + (query) => + query.dataSource === DataSource.TRACES || + query.dataSource === DataSource.LOGS, + ) !== undefined; + + if (isTraceOrLogsQueryBuilder) { + return false; + } + + return isNewTraceLogsAvailable; + }, [ + currentQuery.builder.queryData, + selectedWidget?.id, + isNewTraceLogsAvailable, + ]); + return ( diff --git a/frontend/src/store/actions/dashboard/saveDashboard.ts b/frontend/src/store/actions/dashboard/saveDashboard.ts index ac7516ff6e..107fecee25 100644 --- a/frontend/src/store/actions/dashboard/saveDashboard.ts +++ b/frontend/src/store/actions/dashboard/saveDashboard.ts @@ -1,3 +1,4 @@ +import { notification } from 'antd'; import updateDashboardApi from 'api/dashboard/update'; import { AxiosError } from 'axios'; import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames'; @@ -129,10 +130,16 @@ export const SaveDashboard = ({ }); history.push(generatePath(ROUTES.DASHBOARD, { dashboardId })); } else { + const error = 'Something went wrong'; + + notification.error({ + message: response.error || error, + }); + dispatch({ type: 'SAVE_SETTING_TO_PANEL_ERROR', payload: { - errorMessage: response.error || 'Something went wrong', + errorMessage: response.error || error, }, }); }