diff --git a/frontend/src/pages/Integrations/IntegrationDetailPage/IntegrationDetailPage.tsx b/frontend/src/pages/Integrations/IntegrationDetailPage/IntegrationDetailPage.tsx
index 2c7ffa070c..6cdb800f8f 100644
--- a/frontend/src/pages/Integrations/IntegrationDetailPage/IntegrationDetailPage.tsx
+++ b/frontend/src/pages/Integrations/IntegrationDetailPage/IntegrationDetailPage.tsx
@@ -4,7 +4,9 @@
import './IntegrationDetailPage.styles.scss';
import { Color } from '@signozhq/design-tokens';
-import { Button, Skeleton, Typography } from 'antd';
+import { Button, Flex, Skeleton, Typography } from 'antd';
+import FacingIssueBtn from 'components/facingIssueBtn/FacingIssueBtn';
+import { integrationDetailMessage } from 'components/facingIssueBtn/util';
import { useGetIntegration } from 'hooks/Integrations/useGetIntegration';
import { useGetIntegrationStatus } from 'hooks/Integrations/useGetIntegrationStatus';
import { defaultTo } from 'lodash-es';
@@ -64,16 +66,30 @@ function IntegrationDetailPage(props: IntegrationDetailPageProps): JSX.Element {
return (
-
}
- className="all-integrations-btn"
- onClick={(): void => {
- setSelectedIntegration(null);
- }}
- >
- All Integrations
-
+
+ }
+ className="all-integrations-btn"
+ onClick={(): void => {
+ setSelectedIntegration(null);
+ }}
+ >
+ All Integrations
+
+
+
{loading ? (
diff --git a/frontend/src/pages/Integrations/Integrations.styles.scss b/frontend/src/pages/Integrations/Integrations.styles.scss
index aec8433a26..fe0eaa3c23 100644
--- a/frontend/src/pages/Integrations/Integrations.styles.scss
+++ b/frontend/src/pages/Integrations/Integrations.styles.scss
@@ -172,6 +172,20 @@
}
}
}
+
+ .request-entity-container {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+
+ border-radius: 4px;
+ border: 0.5px solid rgba(78, 116, 248, 0.2);
+ background: rgba(69, 104, 220, 0.1);
+ padding: 12px;
+ margin: 24px 0;
+ margin-bottom: 80px;
+ }
}
}
diff --git a/frontend/src/pages/Integrations/Integrations.tsx b/frontend/src/pages/Integrations/Integrations.tsx
index 332c808311..8fdc943f77 100644
--- a/frontend/src/pages/Integrations/Integrations.tsx
+++ b/frontend/src/pages/Integrations/Integrations.tsx
@@ -8,6 +8,7 @@ import { useHistory, useLocation } from 'react-router-dom';
import Header from './Header';
import IntegrationDetailPage from './IntegrationDetailPage/IntegrationDetailPage';
import IntegrationsList from './IntegrationsList';
+import { RequestIntegrationBtn } from './RequestIntegrationBtn';
import { INTEGRATION_TELEMETRY_EVENTS } from './utils';
function Integrations(): JSX.Element {
@@ -65,6 +66,7 @@ function Integrations(): JSX.Element {
searchTerm={searchTerm}
setActiveDetailTab={setActiveDetailTab}
/>
+
>
)}
diff --git a/frontend/src/pages/Integrations/RequestIntegrationBtn.tsx b/frontend/src/pages/Integrations/RequestIntegrationBtn.tsx
new file mode 100644
index 0000000000..a65e87baae
--- /dev/null
+++ b/frontend/src/pages/Integrations/RequestIntegrationBtn.tsx
@@ -0,0 +1,95 @@
+import './Integrations.styles.scss';
+
+import { LoadingOutlined } from '@ant-design/icons';
+import { Button, Input, Space, Typography } from 'antd';
+import logEvent from 'api/common/logEvent';
+import { useNotifications } from 'hooks/useNotifications';
+import { Check } from 'lucide-react';
+import { useState } from 'react';
+import { useTranslation } from 'react-i18next';
+
+export function RequestIntegrationBtn(): JSX.Element {
+ const [
+ isSubmittingRequestForIntegration,
+ setIsSubmittingRequestForIntegration,
+ ] = useState(false);
+
+ const [requestedIntegrationName, setRequestedIntegrationName] = useState('');
+
+ const { notifications } = useNotifications();
+ const { t } = useTranslation(['common']);
+
+ const handleRequestIntegrationSubmit = async (): Promise
=> {
+ try {
+ setIsSubmittingRequestForIntegration(true);
+ const response = await logEvent('Integration Requested', {
+ screen: 'Integration list page',
+ integration: requestedIntegrationName,
+ });
+
+ if (response.statusCode === 200) {
+ notifications.success({
+ message: 'Integration Request Submitted',
+ });
+
+ setIsSubmittingRequestForIntegration(false);
+ } else {
+ notifications.error({
+ message:
+ response.error ||
+ t('something_went_wrong', {
+ ns: 'common',
+ }),
+ });
+
+ setIsSubmittingRequestForIntegration(false);
+ }
+ } catch (error) {
+ notifications.error({
+ message: t('something_went_wrong', {
+ ns: 'common',
+ }),
+ });
+
+ setIsSubmittingRequestForIntegration(false);
+ }
+ };
+
+ return (
+
+
+ Cannot find what you’re looking for? Request more integrations
+
+
+
+
+ setRequestedIntegrationName(e.target.value)}
+ />
+
+ ) : (
+
+ )
+ }
+ type="primary"
+ onClick={handleRequestIntegrationSubmit}
+ disabled={
+ isSubmittingRequestForIntegration ||
+ !requestedIntegrationName ||
+ requestedIntegrationName?.trim().length === 0
+ }
+ >
+ Submit
+
+
+
+
+ );
+}
diff --git a/frontend/src/pages/MetricsApplication/index.tsx b/frontend/src/pages/MetricsApplication/MetricsApplication.tsx
similarity index 73%
rename from frontend/src/pages/MetricsApplication/index.tsx
rename to frontend/src/pages/MetricsApplication/MetricsApplication.tsx
index 1b0229e5d1..497cdc1f5f 100644
--- a/frontend/src/pages/MetricsApplication/index.tsx
+++ b/frontend/src/pages/MetricsApplication/MetricsApplication.tsx
@@ -4,8 +4,9 @@ import DBCall from 'container/MetricsApplication/Tabs/DBCall';
import External from 'container/MetricsApplication/Tabs/External';
import Overview from 'container/MetricsApplication/Tabs/Overview';
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
+import useUrlQuery from 'hooks/useUrlQuery';
import history from 'lib/history';
-import { useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import { generatePath, useParams } from 'react-router-dom';
import ApDexApplication from './ApDex/ApDexApplication';
@@ -21,34 +22,40 @@ function MetricsApplication(): JSX.Element {
const activeKey = useMetricsApplicationTabKey();
+ const urlQuery = useUrlQuery();
+
+ const getRouteUrl = useCallback(
+ (tab: MetricsApplicationTab): string => {
+ urlQuery.set('tab', tab);
+ return `${generatePath(ROUTES.SERVICE_METRICS, {
+ servicename,
+ })}?${urlQuery.toString()}`;
+ },
+ [servicename, urlQuery],
+ );
+
const routes = useMemo(
() => [
{
Component: Overview,
name: TAB_KEY_VS_LABEL[MetricsApplicationTab.OVER_METRICS],
- route: `${generatePath(ROUTES.SERVICE_METRICS, {
- servicename,
- })}?tab=${MetricsApplicationTab.OVER_METRICS}`,
+ route: getRouteUrl(MetricsApplicationTab.OVER_METRICS),
key: MetricsApplicationTab.OVER_METRICS,
},
{
Component: DBCall,
name: TAB_KEY_VS_LABEL[MetricsApplicationTab.DB_CALL_METRICS],
- route: `${generatePath(ROUTES.SERVICE_METRICS, {
- servicename,
- })}?tab=${MetricsApplicationTab.DB_CALL_METRICS}`,
+ route: getRouteUrl(MetricsApplicationTab.DB_CALL_METRICS),
key: MetricsApplicationTab.DB_CALL_METRICS,
},
{
Component: External,
name: TAB_KEY_VS_LABEL[MetricsApplicationTab.EXTERNAL_METRICS],
- route: `${generatePath(ROUTES.SERVICE_METRICS, {
- servicename,
- })}?tab=${MetricsApplicationTab.EXTERNAL_METRICS}`,
+ route: getRouteUrl(MetricsApplicationTab.EXTERNAL_METRICS),
key: MetricsApplicationTab.EXTERNAL_METRICS,
},
],
- [servicename],
+ [getRouteUrl],
);
return (
diff --git a/frontend/src/pages/SaveView/SaveView.styles.scss b/frontend/src/pages/SaveView/SaveView.styles.scss
index 1e4b7bf0f6..e1eb1ab0b0 100644
--- a/frontend/src/pages/SaveView/SaveView.styles.scss
+++ b/frontend/src/pages/SaveView/SaveView.styles.scss
@@ -18,7 +18,7 @@
}
.subtitle {
- color: var(---bg-vanilla-400);
+ color: var(--bg-vanilla-400);
font-size: var(--font-size-sm);
font-style: normal;
font-weight: var(--font-weight-normal);
diff --git a/frontend/src/pages/Settings/config.tsx b/frontend/src/pages/Settings/config.tsx
index c6073ce322..94b06a5547 100644
--- a/frontend/src/pages/Settings/config.tsx
+++ b/frontend/src/pages/Settings/config.tsx
@@ -5,6 +5,7 @@ import APIKeys from 'container/APIKeys/APIKeys';
import GeneralSettings from 'container/GeneralSettings';
import GeneralSettingsCloud from 'container/GeneralSettingsCloud';
import IngestionSettings from 'container/IngestionSettings/IngestionSettings';
+import MultiIngestionSettings from 'container/IngestionSettings/MultiIngestionSettings';
import OrganizationSettings from 'container/OrganizationSettings';
import { TFunction } from 'i18next';
import { Backpack, BellDot, Building, Cpu, KeySquare } from 'lucide-react';
@@ -48,6 +49,21 @@ export const ingestionSettings = (t: TFunction): RouteTabProps['routes'] => [
},
];
+export const multiIngestionSettings = (
+ t: TFunction,
+): RouteTabProps['routes'] => [
+ {
+ Component: MultiIngestionSettings,
+ name: (
+
+ {t('routes:ingestion_settings').toString()}
+
+ ),
+ route: ROUTES.INGESTION_SETTINGS,
+ key: ROUTES.INGESTION_SETTINGS,
+ },
+];
+
export const generalSettings = (t: TFunction): RouteTabProps['routes'] => [
{
Component: GeneralSettings,
diff --git a/frontend/src/pages/Settings/index.tsx b/frontend/src/pages/Settings/index.tsx
index c2bdcef5e6..bef3d7cba8 100644
--- a/frontend/src/pages/Settings/index.tsx
+++ b/frontend/src/pages/Settings/index.tsx
@@ -1,5 +1,7 @@
import RouteTab from 'components/RouteTab';
+import { FeatureKeys } from 'constants/features';
import useComponentPermission from 'hooks/useComponentPermission';
+import useFeatureFlag from 'hooks/useFeatureFlag';
import history from 'lib/history';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
@@ -19,11 +21,12 @@ function SettingsPage(): JSX.Element {
);
const { t } = useTranslation(['routes']);
- const routes = useMemo(() => getRoutes(role, isCurrentOrgSettings, t), [
- role,
- isCurrentOrgSettings,
- t,
- ]);
+ const isGatewayEnabled = !!useFeatureFlag(FeatureKeys.GATEWAY)?.active;
+
+ const routes = useMemo(
+ () => getRoutes(role, isCurrentOrgSettings, isGatewayEnabled, t),
+ [role, isCurrentOrgSettings, isGatewayEnabled, t],
+ );
return ;
}
diff --git a/frontend/src/pages/Settings/utils.ts b/frontend/src/pages/Settings/utils.ts
index 6078ef7621..4d54c05603 100644
--- a/frontend/src/pages/Settings/utils.ts
+++ b/frontend/src/pages/Settings/utils.ts
@@ -8,12 +8,14 @@ import {
apiKeys,
generalSettings,
ingestionSettings,
+ multiIngestionSettings,
organizationSettings,
} from './config';
export const getRoutes = (
userRole: ROLES | null,
isCurrentOrgSettings: boolean,
+ isGatewayEnabled: boolean,
t: TFunction,
): RouteTabProps['routes'] => {
const settings = [];
@@ -24,13 +26,16 @@ export const getRoutes = (
settings.push(...organizationSettings(t));
}
- if (isCloudUser()) {
- settings.push(...ingestionSettings(t));
- settings.push(...alertChannels(t));
- } else {
- settings.push(...alertChannels(t));
+ if (isGatewayEnabled && userRole === USER_ROLES.ADMIN) {
+ settings.push(...multiIngestionSettings(t));
}
+ if (isCloudUser() && !isGatewayEnabled) {
+ settings.push(...ingestionSettings(t));
+ }
+
+ settings.push(...alertChannels(t));
+
if ((isCloudUser() || isEECloudUser()) && userRole === USER_ROLES.ADMIN) {
settings.push(...apiKeys(t));
}
diff --git a/frontend/src/pages/TracesExplorer/Filter/DurationSection.tsx b/frontend/src/pages/TracesExplorer/Filter/DurationSection.tsx
new file mode 100644
index 0000000000..ce124f623e
--- /dev/null
+++ b/frontend/src/pages/TracesExplorer/Filter/DurationSection.tsx
@@ -0,0 +1,139 @@
+import { Input, Slider } from 'antd';
+import { SliderRangeProps } from 'antd/es/slider';
+import { getMs } from 'container/Trace/Filters/Panel/PanelBody/Duration/util';
+import useDebouncedFn from 'hooks/useDebouncedFunction';
+import {
+ ChangeEventHandler,
+ Dispatch,
+ SetStateAction,
+ useCallback,
+ useEffect,
+ useMemo,
+ useState,
+} from 'react';
+
+import { addFilter, FilterType, traceFilterKeys } from './filterUtils';
+
+interface DurationProps {
+ selectedFilters: FilterType | undefined;
+ setSelectedFilters: Dispatch>;
+}
+
+export function DurationSection(props: DurationProps): JSX.Element {
+ const { setSelectedFilters, selectedFilters } = props;
+
+ const getDuration = useMemo(() => {
+ if (selectedFilters?.durationNanoMin || selectedFilters?.durationNanoMax) {
+ return {
+ minDuration: selectedFilters?.durationNanoMin?.values || '',
+ maxDuration: selectedFilters?.durationNanoMax?.values || '',
+ };
+ }
+
+ if (selectedFilters?.durationNano) {
+ return {
+ minDuration: getMs(selectedFilters?.durationNano?.values?.[0] || ''),
+ maxDuration: getMs(selectedFilters?.durationNano?.values?.[1] || ''),
+ };
+ }
+
+ return {
+ maxDuration: '',
+ minDuration: '',
+ };
+ }, [selectedFilters]);
+
+ const [preMax, setPreMax] = useState('');
+ const [preMin, setPreMin] = useState('');
+
+ useEffect(() => {
+ setPreMax(getDuration.maxDuration as string);
+ setPreMin(getDuration.minDuration as string);
+ }, [getDuration]);
+
+ const updateDurationFilter = (min: string, max: string): void => {
+ const durationMin = 'durationNanoMin';
+ const durationMax = 'durationNanoMax';
+
+ addFilter(durationMin, min, setSelectedFilters, traceFilterKeys.durationNano);
+ addFilter(durationMax, max, setSelectedFilters, traceFilterKeys.durationNano);
+ };
+
+ const onRangeSliderHandler = (number: [string, string]): void => {
+ const [min, max] = number;
+
+ setPreMin(min);
+ setPreMax(max);
+ };
+
+ const debouncedFunction = useDebouncedFn((min, max) => {
+ updateDurationFilter(min as string, max as string);
+ }, 1500);
+
+ const onChangeMaxHandler: ChangeEventHandler = (event) => {
+ const { value } = event.target;
+ const min = preMin;
+ const max = value;
+
+ onRangeSliderHandler([min, max]);
+ debouncedFunction(min, max);
+ };
+
+ const onChangeMinHandler: ChangeEventHandler = (event) => {
+ const { value } = event.target;
+ const min = value;
+ const max = preMax;
+
+ onRangeSliderHandler([min, max]);
+ debouncedFunction(min, max);
+ };
+
+ const onRangeHandler: SliderRangeProps['onChange'] = ([min, max]) => {
+ updateDurationFilter(min.toString(), max.toString());
+ };
+
+ const TipComponent = useCallback((value: undefined | number) => {
+ if (value === undefined) {
+ return ;
+ }
+ return {`${value?.toString()}ms`}
;
+ }, []);
+
+ return (
+
+ );
+}
diff --git a/frontend/src/pages/TracesExplorer/Filter/Filter.styles.scss b/frontend/src/pages/TracesExplorer/Filter/Filter.styles.scss
new file mode 100644
index 0000000000..497ac75ba8
--- /dev/null
+++ b/frontend/src/pages/TracesExplorer/Filter/Filter.styles.scss
@@ -0,0 +1,195 @@
+.collapseContainer {
+ background-color: var(--bg-ink-500);
+ .ant-collapse-header {
+ padding: 12px !important;
+ align-items: center !important;
+ }
+
+ .ant-collapse-header-text {
+ color: var(--bg-vanilla-400);
+ font-family: Inter;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 18px;
+ letter-spacing: -0.07px;
+ text-transform: capitalize;
+ }
+
+ .duration-inputs {
+ display: grid;
+ gap: 12px;
+
+ .min-max-input {
+ .ant-input-group-addon {
+ color: var(--bg-vanilla-400);
+ font-family: 'Space Mono', monospace;
+ font-size: 12px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 16px;
+ letter-spacing: 0.48px;
+ padding: 0 6px;
+ }
+
+ .ant-input {
+ padding: 4px 6px;
+
+ color: var(--bg-vanilla-400);
+ font-family: 'Space Mono', monospace;
+ font-size: 12px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 16px;
+ letter-spacing: 0.48px;
+ }
+ }
+ }
+}
+
+.divider {
+ background-color: var(--bg-slate-400);
+ margin: 0;
+ border-color: var(--bg-slate-400);
+}
+
+.filter-header {
+ padding: 16px 8px 16px 12px;
+ .filter-title {
+ display: flex;
+ gap: 6px;
+
+ .ant-typography {
+ color: var(--bg-vanilla-400);
+ font-family: Inter;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 18px;
+ letter-spacing: -0.07px;
+ }
+ }
+
+ .sync-icon {
+ background-color: var(--bg-ink-500);
+ border: 0;
+ box-shadow: none;
+ padding: 8px;
+ }
+
+ .arrow-icon {
+ background-color: var(--bg-ink-500);
+ border: 0;
+ box-shadow: none;
+ padding-top: 8px;
+
+ .anticon-vertical-align-top {
+ svg {
+ width: 16px;
+ height: 16px;
+ }
+ }
+ }
+}
+
+.section-body-header {
+ display: flex;
+
+ > button {
+ position: absolute;
+ right: 4px;
+ padding-top: 13px;
+ }
+ .ant-collapse {
+ width: 100%;
+ }
+}
+
+.section-card {
+ background-color: var(--bg-ink-500);
+ .ant-card-body {
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+
+ max-height: 500px;
+ overflow-x: hidden;
+ overflow-y: auto;
+ }
+ width: 240px;
+
+ .submenu-checkbox {
+ padding-bottom: 8px;
+ }
+
+ .search-input {
+ margin-bottom: 12px;
+ }
+
+ .checkbox-label {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+
+ .hasError-Error {
+ width: 2px;
+ height: 11px;
+ border-radius: 2px;
+ background: var(--bg-cherry-500);
+ }
+
+ .hasError-Ok {
+ width: 2px;
+ height: 11px;
+ border-radius: 2px;
+ background: var(--bg-forest-500);
+ }
+ }
+}
+.lightMode {
+ .collapseContainer {
+ background-color: var(--bg-vanilla-100);
+
+ .ant-collapse-header-text {
+ color: var(--bg-slate-100);
+ }
+
+ .duration-inputs {
+ .min-max-input {
+ .ant-input-group-addon {
+ color: var(--bg-slate-100);
+ }
+
+ .ant-input {
+ color: var(--bg-slate-100);
+ }
+ }
+ }
+ }
+
+ .divider {
+ background-color: var(--bg-vanilla-100);
+ border-color: var(--bg-vanilla-200);
+ }
+
+ .filter-header {
+ .filter-title {
+ .ant-typography {
+ color: var(--bg-slate-100);
+ }
+ }
+
+ .arrow-icon {
+ background-color: var(--bg-vanilla-100);
+ }
+
+ .sync-icon {
+ background-color: var(--bg-vanilla-100);
+ }
+ }
+
+ .section-card {
+ background-color: var(--bg-vanilla-100);
+ box-shadow: none;
+ }
+}
diff --git a/frontend/src/pages/TracesExplorer/Filter/Filter.tsx b/frontend/src/pages/TracesExplorer/Filter/Filter.tsx
new file mode 100644
index 0000000000..7eadc3d5cd
--- /dev/null
+++ b/frontend/src/pages/TracesExplorer/Filter/Filter.tsx
@@ -0,0 +1,247 @@
+/* eslint-disable react-hooks/exhaustive-deps */
+import './Filter.styles.scss';
+
+import {
+ FilterOutlined,
+ SyncOutlined,
+ VerticalAlignTopOutlined,
+} from '@ant-design/icons';
+import { Button, Flex, Tooltip, Typography } from 'antd';
+import { getMs } from 'container/Trace/Filters/Panel/PanelBody/Duration/util';
+import { useGetCompositeQueryParam } from 'hooks/queryBuilder/useGetCompositeQueryParam';
+import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
+import { isArray, isEqual } from 'lodash-es';
+import {
+ Dispatch,
+ SetStateAction,
+ useCallback,
+ useEffect,
+ useMemo,
+ useState,
+} from 'react';
+import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
+import { Query, TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
+import { v4 as uuid } from 'uuid';
+
+import {
+ AllTraceFilterKeys,
+ AllTraceFilterKeyValue,
+ AllTraceFilterOptions,
+ FilterType,
+ HandleRunProps,
+ unionTagFilterItems,
+} from './filterUtils';
+import { Section } from './Section';
+
+interface FilterProps {
+ setOpen: Dispatch>;
+}
+
+export function Filter(props: FilterProps): JSX.Element {
+ const { setOpen } = props;
+ const [selectedFilters, setSelectedFilters] = useState<
+ Record<
+ AllTraceFilterKeys,
+ { values: string[] | string; keys: BaseAutocompleteData }
+ >
+ >();
+
+ const { currentQuery, redirectWithQueryBuilderData } = useQueryBuilder();
+ const compositeQuery = useGetCompositeQueryParam();
+
+ // eslint-disable-next-line sonarjs/cognitive-complexity
+ const syncSelectedFilters = useMemo((): FilterType => {
+ const filters = compositeQuery?.builder.queryData?.[0].filters;
+ if (!filters) {
+ return {} as FilterType;
+ }
+
+ return filters.items
+ .filter((item) =>
+ Object.keys(AllTraceFilterKeyValue).includes(item.key?.key as string),
+ )
+ .filter(
+ (item) =>
+ (item.op === 'in' && item.key?.key !== 'durationNano') ||
+ (item.key?.key === 'durationNano' && ['>=', '<='].includes(item.op)),
+ )
+ .reduce((acc, item) => {
+ const keys = item.key as BaseAutocompleteData;
+ const attributeName = item.key?.key || '';
+ const values = item.value as string[];
+
+ if ((attributeName as AllTraceFilterKeys) === 'durationNano') {
+ if (item.op === '>=') {
+ acc.durationNanoMin = {
+ values: getMs(String(values)),
+ keys,
+ };
+ } else {
+ acc.durationNanoMax = {
+ values: getMs(String(values)),
+ keys,
+ };
+ }
+ return acc;
+ }
+
+ if (attributeName) {
+ if (acc[attributeName as AllTraceFilterKeys]) {
+ const existingValue = acc[attributeName as AllTraceFilterKeys];
+ acc[attributeName as AllTraceFilterKeys] = {
+ values: [...existingValue.values, ...values],
+ keys,
+ };
+ } else {
+ acc[attributeName as AllTraceFilterKeys] = { values, keys };
+ }
+ }
+
+ return acc;
+ }, {} as FilterType);
+ }, [compositeQuery]);
+
+ useEffect(() => {
+ if (!isEqual(syncSelectedFilters, selectedFilters)) {
+ setSelectedFilters(syncSelectedFilters);
+ }
+ }, [syncSelectedFilters]);
+
+ // eslint-disable-next-line sonarjs/cognitive-complexity
+ const preparePostData = (): TagFilterItem[] => {
+ if (!selectedFilters) {
+ return [];
+ }
+
+ const items = Object.keys(selectedFilters)?.flatMap((attribute) => {
+ const { keys, values } = selectedFilters[attribute as AllTraceFilterKeys];
+ if (
+ ['durationNanoMax', 'durationNanoMin', 'durationNano'].includes(
+ attribute as AllTraceFilterKeys,
+ )
+ ) {
+ if (!values || !values.length) {
+ return [];
+ }
+ let minValue = '';
+ let maxValue = '';
+
+ const durationItems: TagFilterItem[] = [];
+
+ if (isArray(values)) {
+ minValue = values?.[0];
+ maxValue = values?.[1];
+
+ const minItems: TagFilterItem = {
+ id: uuid().slice(0, 8),
+ op: '>=',
+ key: keys,
+ value: Number(minValue) * 1000000,
+ };
+
+ const maxItems: TagFilterItem = {
+ id: uuid().slice(0, 8),
+ op: '<=',
+ key: keys,
+ value: Number(maxValue) * 1000000,
+ };
+ return maxValue ? [minItems, maxItems] : [minItems];
+ }
+ if (attribute === 'durationNanoMin') {
+ durationItems.push({
+ id: uuid().slice(0, 8),
+ op: '>=',
+ key: keys,
+ value: Number(values) * 1000000,
+ });
+ } else {
+ durationItems.push({
+ id: uuid().slice(0, 8),
+ op: '<=',
+ key: keys,
+ value: Number(values) * 1000000,
+ });
+ }
+
+ return durationItems;
+ }
+ return {
+ id: uuid().slice(0, 8),
+ key: keys,
+ op: 'in',
+ value: values,
+ };
+ });
+
+ return items as TagFilterItem[];
+ };
+
+ const handleRun = useCallback(
+ (props?: HandleRunProps): void => {
+ const preparedQuery: Query = {
+ ...currentQuery,
+ builder: {
+ ...currentQuery.builder,
+ queryData: currentQuery.builder.queryData.map((item) => ({
+ ...item,
+ filters: {
+ ...item.filters,
+ items: props?.resetAll
+ ? []
+ : (unionTagFilterItems(item.filters.items, preparePostData())
+ .map((item) =>
+ item.key?.key === props?.clearByType ? undefined : item,
+ )
+ .filter((i) => i) as TagFilterItem[]),
+ },
+ })),
+ },
+ };
+ redirectWithQueryBuilderData(preparedQuery);
+ },
+ [currentQuery, redirectWithQueryBuilderData, selectedFilters],
+ );
+
+ useEffect(() => {
+ handleRun();
+ }, [selectedFilters]);
+
+ return (
+ <>
+
+
+
+
+ Filters
+
+
+
+
+
+
+
+
+
+ <>
+ {AllTraceFilterOptions.filter(
+ (i) => i !== 'durationNanoMax' && i !== 'durationNanoMin',
+ ).map((panelName) => (
+
+ ))}
+ >
+ >
+ );
+}
diff --git a/frontend/src/pages/TracesExplorer/Filter/Section.tsx b/frontend/src/pages/TracesExplorer/Filter/Section.tsx
new file mode 100644
index 0000000000..c95f8a77e0
--- /dev/null
+++ b/frontend/src/pages/TracesExplorer/Filter/Section.tsx
@@ -0,0 +1,81 @@
+import './Filter.styles.scss';
+
+import { Button, Collapse, Divider } from 'antd';
+import { Dispatch, MouseEvent, SetStateAction } from 'react';
+
+import { DurationSection } from './DurationSection';
+import {
+ AllTraceFilterKeys,
+ AllTraceFilterKeyValue,
+ FilterType,
+ HandleRunProps,
+} from './filterUtils';
+import { SectionBody } from './SectionContent';
+
+interface SectionProps {
+ panelName: AllTraceFilterKeys;
+ selectedFilters: FilterType | undefined;
+ setSelectedFilters: Dispatch>;
+ handleRun: (props?: HandleRunProps) => void;
+}
+export function Section(props: SectionProps): JSX.Element {
+ const { panelName, setSelectedFilters, selectedFilters, handleRun } = props;
+
+ const onClearHandler = (e: MouseEvent): void => {
+ e.stopPropagation();
+ e.preventDefault();
+
+ if (
+ selectedFilters?.[panelName] ||
+ selectedFilters?.durationNanoMin ||
+ selectedFilters?.durationNanoMax
+ ) {
+ handleRun({ clearByType: panelName });
+ }
+ };
+
+ return (
+
+
+
+
+ ),
+ label: AllTraceFilterKeyValue[panelName],
+ }
+ : {
+ key: panelName,
+ children: (
+
+ ),
+ label: AllTraceFilterKeyValue[panelName],
+ },
+ ]}
+ />
+
+
+
+ );
+}
diff --git a/frontend/src/pages/TracesExplorer/Filter/SectionContent.tsx b/frontend/src/pages/TracesExplorer/Filter/SectionContent.tsx
new file mode 100644
index 0000000000..05fc7bb1f3
--- /dev/null
+++ b/frontend/src/pages/TracesExplorer/Filter/SectionContent.tsx
@@ -0,0 +1,165 @@
+import './Filter.styles.scss';
+
+import { Button, Card, Checkbox, Input, Tooltip } from 'antd';
+import { CheckboxChangeEvent } from 'antd/es/checkbox';
+import { ParaGraph } from 'container/Trace/Filters/Panel/PanelBody/Common/styles';
+import useDebouncedFn from 'hooks/useDebouncedFunction';
+import { defaultTo, isEmpty } from 'lodash-es';
+import {
+ ChangeEvent,
+ Dispatch,
+ SetStateAction,
+ useEffect,
+ useMemo,
+ useState,
+} from 'react';
+
+import {
+ addFilter,
+ AllTraceFilterKeys,
+ FilterType,
+ HandleRunProps,
+ removeFilter,
+ statusFilterOption,
+ useGetAggregateValues,
+} from './filterUtils';
+
+interface SectionBodyProps {
+ type: AllTraceFilterKeys;
+ selectedFilters: FilterType | undefined;
+ setSelectedFilters: Dispatch>;
+ handleRun: (props?: HandleRunProps) => void;
+}
+
+export function SectionBody(props: SectionBodyProps): JSX.Element {
+ const { type, setSelectedFilters, selectedFilters, handleRun } = props;
+ const [visibleItemsCount, setVisibleItemsCount] = useState(10);
+ const [searchFilter, setSearchFilter] = useState('');
+ const [searchText, setSearchText] = useState('');
+ const [checkedItems, setCheckedItems] = useState(
+ defaultTo(selectedFilters?.[type]?.values as string[], []),
+ );
+
+ const [results, setResults] = useState([]);
+ const [isFetching, setFetching] = useState(false);
+
+ useEffect(
+ () =>
+ setCheckedItems(defaultTo(selectedFilters?.[type]?.values as string[], [])),
+ [selectedFilters, type],
+ );
+
+ const handleDebouncedSearch = useDebouncedFn((searchText): void => {
+ setSearchText(searchText as string);
+ }, 500);
+
+ const { isFetching: fetching, keys, results: res } = useGetAggregateValues({
+ value: type,
+ searchText,
+ });
+
+ useEffect(() => {
+ setResults(res);
+ setFetching(fetching);
+ }, [fetching, res]);
+
+ const handleShowMore = (): void => {
+ setVisibleItemsCount((prevCount) => prevCount + 10);
+ };
+
+ const listData = useMemo(
+ () =>
+ (type === 'hasError' ? statusFilterOption : results)
+ .filter((i) => i.length)
+ .filter((filter) => {
+ if (searchFilter.length === 0) {
+ return true;
+ }
+ return filter
+ .toLocaleLowerCase()
+ .includes(searchFilter.toLocaleLowerCase());
+ })
+ .slice(0, visibleItemsCount),
+ [results, searchFilter, type, visibleItemsCount],
+ );
+
+ const onCheckHandler = (event: CheckboxChangeEvent, value: string): void => {
+ const { checked } = event.target;
+ let newValue = value;
+ if (type === 'hasError') {
+ newValue = String(value === 'Error');
+ }
+ if (checked) {
+ addFilter(type, newValue, setSelectedFilters, keys);
+ setCheckedItems((prev) => {
+ if (!prev.includes(newValue)) {
+ prev.push(newValue);
+ }
+ return prev;
+ });
+ } else if (checkedItems.length === 1) {
+ handleRun({ clearByType: type });
+ setCheckedItems([]);
+ } else {
+ removeFilter(type, newValue, setSelectedFilters, keys);
+ setCheckedItems((prev) => prev.filter((item) => item !== newValue));
+ }
+ };
+
+ const checkboxMatcher = (item: string): boolean =>
+ checkedItems?.includes(type === 'hasError' ? String(item === 'Error') : item);
+
+ const labelClassname = (item: string): string => `${type}-${item}`;
+
+ const handleSearch = (e: ChangeEvent): void => {
+ const inputValue = e.target.value;
+ setSearchFilter(inputValue);
+ handleDebouncedSearch(inputValue || '');
+ };
+
+ return (
+
+ <>
+
+ {listData.length === 0 && isEmpty(searchFilter) ? (
+ No data found
+ ) : (
+ <>
+ {listData.map((item) => (
+ onCheckHandler(e, item)}
+ checked={checkboxMatcher(item)}
+ >
+ } placement="rightTop">
+
+ {item}
+
+
+
+
+ ))}
+ {visibleItemsCount < results.length && (
+
+ )}
+ >
+ )}
+ >
+
+ );
+}
diff --git a/frontend/src/pages/TracesExplorer/Filter/filterUtils.ts b/frontend/src/pages/TracesExplorer/Filter/filterUtils.ts
new file mode 100644
index 0000000000..ede7615e47
--- /dev/null
+++ b/frontend/src/pages/TracesExplorer/Filter/filterUtils.ts
@@ -0,0 +1,347 @@
+/* eslint-disable react-hooks/exhaustive-deps */
+import { getAttributesValues } from 'api/queryBuilder/getAttributesValues';
+import { isArray } from 'lodash-es';
+import { Dispatch, SetStateAction, useEffect, useState } from 'react';
+import {
+ BaseAutocompleteData,
+ DataTypes,
+} from 'types/api/queryBuilder/queryAutocompleteResponse';
+import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
+import { DataSource } from 'types/common/queryBuilder';
+
+export const AllTraceFilterKeyValue = {
+ durationNanoMin: 'Duration',
+ durationNano: 'Duration',
+ durationNanoMax: 'Duration',
+ hasError: 'Status',
+ serviceName: 'Service Name',
+ name: 'Operation / Name',
+ rpcMethod: 'RPC Method',
+ responseStatusCode: 'Status Code',
+ httpHost: 'HTTP Host',
+ httpMethod: 'HTTP Method',
+ httpRoute: 'HTTP Route',
+ httpUrl: 'HTTP URL',
+ traceID: 'Trace ID',
+};
+
+export type AllTraceFilterKeys = keyof typeof AllTraceFilterKeyValue;
+
+// Type for the values of AllTraceFilterKeyValue
+export type AllTraceFilterValues = typeof AllTraceFilterKeyValue[AllTraceFilterKeys];
+
+export const AllTraceFilterOptions = Object.keys(
+ AllTraceFilterKeyValue,
+) as (keyof typeof AllTraceFilterKeyValue)[];
+
+export const statusFilterOption = ['Error', 'Ok'];
+
+export type FilterType = Record<
+ AllTraceFilterKeys,
+ { values: string[] | string; keys: BaseAutocompleteData }
+>;
+
+export const addFilter = (
+ filterType: AllTraceFilterKeys,
+ value: string,
+ setSelectedFilters: Dispatch<
+ SetStateAction<
+ | Record<
+ AllTraceFilterKeys,
+ { values: string[] | string; keys: BaseAutocompleteData }
+ >
+ | undefined
+ >
+ >,
+ keys?: BaseAutocompleteData,
+): void => {
+ setSelectedFilters((prevFilters) => {
+ const isDuration = [
+ 'durationNanoMax',
+ 'durationNanoMin',
+ 'durationNano',
+ ].includes(filterType);
+
+ // If previous filters are undefined, initialize them
+ if (!prevFilters) {
+ return ({
+ [filterType]: { values: isDuration ? value : [value], keys },
+ } as unknown) as FilterType;
+ }
+ // If the filter type doesn't exist, initialize it
+ if (!prevFilters[filterType]?.values.length) {
+ return {
+ ...prevFilters,
+ [filterType]: { values: isDuration ? value : [value], keys },
+ };
+ }
+ // If the value already exists, don't add it again
+ if (prevFilters[filterType].values.includes(value)) {
+ return prevFilters;
+ }
+ // Otherwise, add the value to the existing array
+ return {
+ ...prevFilters,
+ [filterType]: {
+ values: isDuration ? value : [...prevFilters[filterType].values, value],
+ keys,
+ },
+ };
+ });
+};
+
+// Function to remove a filter
+export const removeFilter = (
+ filterType: AllTraceFilterKeys,
+ value: string,
+ setSelectedFilters: Dispatch<
+ SetStateAction<
+ | Record<
+ AllTraceFilterKeys,
+ { values: string[] | string; keys: BaseAutocompleteData }
+ >
+ | undefined
+ >
+ >,
+ keys?: BaseAutocompleteData,
+): void => {
+ setSelectedFilters((prevFilters) => {
+ if (!prevFilters || !prevFilters[filterType]?.values.length) {
+ return prevFilters;
+ }
+
+ const prevValue = prevFilters[filterType]?.values;
+ const updatedValues = !isArray(prevValue)
+ ? prevValue
+ : prevValue?.filter((item: any) => item !== value);
+
+ if (updatedValues.length === 0) {
+ const { [filterType]: item, ...remainingFilters } = prevFilters;
+ return Object.keys(remainingFilters).length > 0
+ ? (remainingFilters as FilterType)
+ : undefined;
+ }
+
+ return {
+ ...prevFilters,
+ [filterType]: { values: updatedValues, keys },
+ };
+ });
+};
+
+export const removeAllFilters = (
+ filterType: AllTraceFilterKeys,
+ setSelectedFilters: Dispatch<
+ SetStateAction<
+ | Record<
+ AllTraceFilterKeys,
+ { values: string[]; keys: BaseAutocompleteData }
+ >
+ | undefined
+ >
+ >,
+): void => {
+ setSelectedFilters((prevFilters) => {
+ if (!prevFilters || !prevFilters[filterType]) {
+ return prevFilters;
+ }
+
+ const { [filterType]: item, ...remainingFilters } = prevFilters;
+
+ return Object.keys(remainingFilters).length > 0
+ ? (remainingFilters as Record<
+ AllTraceFilterKeys,
+ { values: string[]; keys: BaseAutocompleteData }
+ >)
+ : undefined;
+ });
+};
+
+export const traceFilterKeys: Record<
+ AllTraceFilterKeys,
+ BaseAutocompleteData
+> = {
+ durationNano: {
+ key: 'durationNano',
+ dataType: DataTypes.Float64,
+ type: 'tag',
+ isColumn: true,
+ isJSON: false,
+ id: 'durationNano--float64--tag--true',
+ },
+ hasError: {
+ key: 'hasError',
+ dataType: DataTypes.bool,
+ type: 'tag',
+ isColumn: true,
+ isJSON: false,
+ id: 'hasError--bool--tag--true',
+ },
+ serviceName: {
+ key: 'serviceName',
+ dataType: DataTypes.String,
+ type: 'tag',
+ isColumn: true,
+ isJSON: false,
+ id: 'serviceName--string--tag--true',
+ },
+ name: {
+ key: 'name',
+ dataType: DataTypes.String,
+ type: 'tag',
+ isColumn: true,
+ isJSON: false,
+ id: 'name--string--tag--true',
+ },
+ rpcMethod: {
+ key: 'rpcMethod',
+ dataType: DataTypes.String,
+ type: 'tag',
+ isColumn: true,
+ isJSON: false,
+ id: 'rpcMethod--string--tag--true',
+ },
+ responseStatusCode: {
+ key: 'responseStatusCode',
+ dataType: DataTypes.String,
+ type: 'tag',
+ isColumn: true,
+ isJSON: false,
+ id: 'responseStatusCode--string--tag--true',
+ },
+ httpHost: {
+ key: 'httpHost',
+ dataType: DataTypes.String,
+ type: 'tag',
+ isColumn: true,
+ isJSON: false,
+ id: 'httpHost--string--tag--true',
+ },
+ httpMethod: {
+ key: 'httpMethod',
+ dataType: DataTypes.String,
+ type: 'tag',
+ isColumn: true,
+ isJSON: false,
+ id: 'httpMethod--string--tag--true',
+ },
+ httpRoute: {
+ key: 'httpRoute',
+ dataType: DataTypes.String,
+ type: 'tag',
+ isColumn: true,
+ isJSON: false,
+ id: 'httpRoute--string--tag--true',
+ },
+ httpUrl: {
+ key: 'httpUrl',
+ dataType: DataTypes.String,
+ type: 'tag',
+ isColumn: true,
+ isJSON: false,
+ id: 'httpUrl--string--tag--true',
+ },
+ traceID: {
+ key: 'traceID',
+ dataType: DataTypes.String,
+ type: 'tag',
+ isColumn: true,
+ isJSON: false,
+ id: 'traceID--string--tag--true',
+ },
+ durationNanoMin: {
+ key: 'durationNanoMin',
+ dataType: DataTypes.Float64,
+ type: 'tag',
+ isColumn: true,
+ isJSON: false,
+ id: 'durationNanoMin--float64--tag--true',
+ },
+ durationNanoMax: {
+ key: 'durationNanoMax',
+ dataType: DataTypes.Float64,
+ type: 'tag',
+ isColumn: true,
+ isJSON: false,
+ id: 'durationNanoMax--float64--tag--true',
+ },
+};
+
+interface AggregateValuesProps {
+ value: AllTraceFilterKeys;
+ searchText?: string;
+}
+
+type IuseGetAggregateValue = {
+ keys: BaseAutocompleteData;
+ results: string[];
+ isFetching: boolean;
+};
+
+export function useGetAggregateValues(
+ props: AggregateValuesProps,
+): IuseGetAggregateValue {
+ const { value, searchText } = props;
+ const keyData = traceFilterKeys[value];
+ const [isFetching, setFetching] = useState
(true);
+ const [results, setResults] = useState([]);
+
+ const getValues = async (): Promise => {
+ try {
+ setResults([]);
+ const { payload } = await getAttributesValues({
+ aggregateOperator: 'noop',
+ dataSource: DataSource.TRACES,
+ aggregateAttribute: '',
+ attributeKey: value,
+ filterAttributeKeyDataType: keyData ? keyData.dataType : DataTypes.EMPTY,
+ tagType: keyData.type ?? '',
+ searchText: searchText ?? '',
+ });
+
+ if (payload) {
+ const values = Object.values(payload).find((el) => !!el) || [];
+ setResults(values);
+ }
+ } catch (e) {
+ console.error(e);
+ } finally {
+ setFetching(false);
+ }
+ };
+
+ useEffect(() => {
+ getValues();
+ }, [searchText]);
+
+ if (!value) {
+ setFetching(false);
+ return { keys: keyData, results, isFetching };
+ }
+
+ return { keys: keyData, results, isFetching };
+}
+
+export function unionTagFilterItems(
+ items1: TagFilterItem[],
+ items2: TagFilterItem[],
+): TagFilterItem[] {
+ const unionMap = new Map();
+
+ items1.forEach((item) => {
+ const keyOp = `${item?.key?.key}_${item.op}`;
+ unionMap.set(keyOp, item);
+ });
+
+ items2.forEach((item) => {
+ const keyOp = `${item?.key?.key}_${item.op}`;
+ unionMap.set(keyOp, item);
+ });
+
+ return Array.from(unionMap.values());
+}
+
+export interface HandleRunProps {
+ resetAll?: boolean;
+ clearByType?: AllTraceFilterKeys;
+}
diff --git a/frontend/src/pages/TracesExplorer/TracesExplorer.styles.scss b/frontend/src/pages/TracesExplorer/TracesExplorer.styles.scss
index 5ab2bd07b2..cf6eb52b10 100644
--- a/frontend/src/pages/TracesExplorer/TracesExplorer.styles.scss
+++ b/frontend/src/pages/TracesExplorer/TracesExplorer.styles.scss
@@ -1,9 +1,27 @@
-.trace-explorer-run-query {
+.trace-explorer-header {
display: flex;
- flex-direction: row-reverse;
- align-items: center;
- margin: 8px 16px;
- gap: 8px;
+ justify-content: space-between;
+
+ .trace-explorer-run-query {
+ display: flex;
+ flex-direction: row-reverse;
+ align-items: center;
+ margin: 8px 16px;
+ gap: 8px;
+ }
+
+ .filter-outlined-btn {
+ border-radius: 0px 2px 2px 0px;
+ border-top: 1px solid var(--bg-slate-400);
+ border-right: 1px solid var(--bg-slate-400);
+ border-bottom: 1px solid var(--bg-slate-400);
+ background: var(--bg-ink-400);
+ box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
+ }
+}
+
+.trace-explorer-header.single-child {
+ justify-content: flex-end;
}
.traces-explorer-views {
@@ -11,3 +29,65 @@
padding: 0 8px;
}
}
+
+.trace-explorer-page {
+ display: flex;
+
+ .filter {
+ width: 260px;
+ height: 100vh;
+
+ border-right: 0px;
+ border: 1px solid var(--bg-slate-400);
+ background-color: var(--bg-ink-500);
+
+ > .ant-card-body {
+ padding: 0;
+ width: 258px;
+ }
+ }
+
+ .trace-explorer {
+ width: 100%;
+ border-left: 1px solid var(--bg-slate-400);
+ background: var(--bg-ink-500);
+
+ > .ant-card-body {
+ padding: 8px 8px;
+ }
+
+ border-color: var(--bg-slate-400);
+ }
+}
+
+.lightMode {
+ .trace-explorer-page {
+ .filter {
+ border: 1px solid var(--bg-vanilla-200);
+ background-color: var(--bg-vanilla-100);
+ }
+
+ .trace-explorer {
+ width: 100%;
+ border-left: 1px solid var(--bg-vanilla-200);
+ background: var(--bg-vanilla-200);
+
+ > .ant-card-body {
+ padding: 8px 8px;
+ }
+
+ border-color: var(--bg-vanilla-200);
+ }
+ }
+
+ .trace-explorer-header {
+ .filter-outlined-btn {
+ border-radius: 0px 2px 2px 0px;
+ border-top: 1px solid var(--bg-vanilla-200);
+ border-right: 1px solid var(--bg-vanilla-200);
+ border-bottom: 1px solid var(--bg-vanilla-200);
+ background: var(--bg-vanilla-100);
+ box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0);
+ }
+ }
+}
diff --git a/frontend/src/pages/TracesExplorer/index.tsx b/frontend/src/pages/TracesExplorer/index.tsx
index 99527fba98..6c4057332f 100644
--- a/frontend/src/pages/TracesExplorer/index.tsx
+++ b/frontend/src/pages/TracesExplorer/index.tsx
@@ -1,6 +1,7 @@
import './TracesExplorer.styles.scss';
-import { Tabs } from 'antd';
+import { FilterOutlined } from '@ant-design/icons';
+import { Button, Card, Tabs, Tooltip } from 'antd';
import axios from 'axios';
import ExplorerCard from 'components/ExplorerCard/ExplorerCard';
import { AVAILABLE_EXPORT_PANEL_TYPES } from 'constants/panelTypes';
@@ -19,13 +20,14 @@ import { useHandleExplorerTabChange } from 'hooks/useHandleExplorerTabChange';
import { useNotifications } from 'hooks/useNotifications';
import history from 'lib/history';
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
-import { useCallback, useEffect, useMemo } from 'react';
+import { useCallback, useEffect, useMemo, useState } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { Dashboard } from 'types/api/dashboard/getAll';
import { DataSource } from 'types/common/queryBuilder';
import { generateExportToDashboardLink } from 'utils/dashboard/generateExportToDashboardLink';
import { v4 } from 'uuid';
+import { Filter } from './Filter/Filter';
import { ActionsWrapper, Container } from './styles';
import { getTabsItems } from './utils';
@@ -180,42 +182,60 @@ function TracesExplorer(): JSX.Element {
handleExplorerTabChange,
currentPanelType,
]);
+ const [isOpen, setOpen] = useState(true);
return (
- <>
-
-
-
-
-
-
-
+
+
+
+
+
+
+ {!isOpen && (
+
+
+
+ )}
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
-
-
-
+
-
-
- >
+
+
);
}
diff --git a/frontend/src/periscope.scss b/frontend/src/periscope.scss
index 53c14deb53..93f3fc73ed 100644
--- a/frontend/src/periscope.scss
+++ b/frontend/src/periscope.scss
@@ -14,6 +14,7 @@
padding: 6px;
border: 1px solid var(--bg-slate-400, #1d212d);
+ border-radius: 3px;
background: var(--bg-ink-400, #121317);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
color: var(--bg-vanilla-400, #c0c1c3);
@@ -26,12 +27,12 @@
cursor: pointer;
&.primary {
- color: #fff;
- background-color: #4566d6;
+ color: var(--bg-vanilla-100) !important;
+ background-color: var(--bg-robin-500) !important;
+ border: none;
box-shadow: 0 2px 0 rgba(62, 86, 245, 0.09);
}
-
&:disabled {
opacity: 0.5;
}
diff --git a/frontend/src/periscope/components/Tabs/Tabs.tsx b/frontend/src/periscope/components/Tabs/Tabs.tsx
new file mode 100644
index 0000000000..219a09e3f2
--- /dev/null
+++ b/frontend/src/periscope/components/Tabs/Tabs.tsx
@@ -0,0 +1,13 @@
+/* eslint-disable react/jsx-props-no-spreading */
+import { Tabs as AntDTabs, TabsProps } from 'antd';
+import React from 'react';
+
+export interface TabProps {
+ label: string | React.ReactElement;
+ key: string;
+ children: React.ReactElement;
+}
+
+export default function Tabs(props: TabsProps): React.ReactNode {
+ return ;
+}
diff --git a/frontend/src/periscope/components/Tabs/index.tsx b/frontend/src/periscope/components/Tabs/index.tsx
new file mode 100644
index 0000000000..4b674c987b
--- /dev/null
+++ b/frontend/src/periscope/components/Tabs/index.tsx
@@ -0,0 +1,3 @@
+import Tabs from './Tabs';
+
+export default Tabs;
diff --git a/frontend/src/providers/QueryBuilder.tsx b/frontend/src/providers/QueryBuilder.tsx
index f630b13f83..77fa791b14 100644
--- a/frontend/src/providers/QueryBuilder.tsx
+++ b/frontend/src/providers/QueryBuilder.tsx
@@ -229,9 +229,6 @@ export function QueryBuilderProvider({
setCurrentQuery(
timeUpdated ? merge(currentQuery, newQueryState) : newQueryState,
);
- setSupersetQuery(
- timeUpdated ? merge(currentQuery, newQueryState) : newQueryState,
- );
setQueryType(type);
},
[prepareQueryBuilderData, currentQuery],
diff --git a/frontend/src/store/reducers/trace.ts b/frontend/src/store/reducers/trace.ts
index 5545f25eb8..9c94b2d810 100644
--- a/frontend/src/store/reducers/trace.ts
+++ b/frontend/src/store/reducers/trace.ts
@@ -57,9 +57,7 @@ const initialValue: TraceReducer = {
payload: { items: {} },
},
filterDisplayValue: new Map([
- ['component', INITIAL_FILTER_VALUE],
['duration', INITIAL_FILTER_VALUE],
- ['httpCode', INITIAL_FILTER_VALUE],
['httpHost', INITIAL_FILTER_VALUE],
['httpMethod', INITIAL_FILTER_VALUE],
['httpUrl', INITIAL_FILTER_VALUE],
diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss
index 97be4ebd5b..1684d7de2a 100644
--- a/frontend/src/styles.scss
+++ b/frontend/src/styles.scss
@@ -246,3 +246,23 @@ body {
.ant-notification-notice-message {
padding-right: 20px;
}
+
+// we want the z-index to be less than 1000 (z-index for antd drawers) as we do not want intercom to interfare when drawers are open
+.intercom-lightweight-app {
+ z-index: 980 !important;
+}
+
+/**
+
+z-index chart for components across application
+
+intercom - 980
+tooltip - 1070
+popover - 1030
+drawer - 1000
+time picker - 1050
+dropdown - 1050
+modal - 1000
+notifications - 2050
+
+*/
diff --git a/frontend/src/types/api/dashboard/getAll.ts b/frontend/src/types/api/dashboard/getAll.ts
index e7faf83023..af254e032e 100644
--- a/frontend/src/types/api/dashboard/getAll.ts
+++ b/frontend/src/types/api/dashboard/getAll.ts
@@ -54,6 +54,14 @@ export interface Dashboard {
isLocked?: boolean;
}
+export interface DashboardTemplate {
+ name: string;
+ icon: React.ReactElement;
+ id: string;
+ description: string;
+ previewImage: string;
+}
+
export interface DashboardData {
uuid?: string;
description?: string;
@@ -65,6 +73,7 @@ export interface DashboardData {
panelMap?: Record;
variables: Record;
version?: string;
+ image?: string;
}
export interface WidgetRow {
@@ -74,6 +83,9 @@ export interface WidgetRow {
description: string;
}
+export interface ColumnUnit {
+ [key: string]: string;
+}
export interface IBaseWidget {
isStacked: boolean;
id: string;
@@ -85,10 +97,14 @@ export interface IBaseWidget {
timePreferance: timePreferenceType;
stepSize?: number;
yAxisUnit?: string;
+ bucketCount?: number;
+ bucketWidth?: number;
+ mergeAllActiveQueries?: boolean;
thresholds?: ThresholdProps[];
softMin: number | null;
softMax: number | null;
fillSpans?: boolean;
+ columnUnits?: ColumnUnit;
selectedLogFields: IField[] | null;
selectedTracesFields: BaseAutocompleteData[] | null;
}
diff --git a/frontend/src/types/api/ingestionKeys/limits/types.ts b/frontend/src/types/api/ingestionKeys/limits/types.ts
new file mode 100644
index 0000000000..279ec157d5
--- /dev/null
+++ b/frontend/src/types/api/ingestionKeys/limits/types.ts
@@ -0,0 +1,55 @@
+export interface LimitProps {
+ id: string;
+ signal: string;
+ tags?: string[];
+ key_id?: string;
+ created_at?: string;
+ updated_at?: string;
+ config?: {
+ day?: {
+ size?: number;
+ };
+ second?: {
+ size?: number;
+ };
+ };
+ metric?: {
+ day?: {
+ size?: number;
+ };
+ second?: {
+ size?: number;
+ };
+ };
+}
+
+export interface AddLimitProps {
+ keyID: string;
+ signal: string;
+ config: {
+ day: {
+ size: number;
+ };
+ second: {
+ size: number;
+ };
+ };
+}
+
+export interface UpdateLimitProps {
+ limitID: string;
+ signal: string;
+ config: {
+ day: {
+ size: number;
+ };
+ second: {
+ size: number;
+ };
+ };
+}
+
+export interface LimitSuccessProps {
+ status: string;
+ response: unknown;
+}
diff --git a/frontend/src/types/api/ingestionKeys/types.ts b/frontend/src/types/api/ingestionKeys/types.ts
new file mode 100644
index 0000000000..b29c539cb1
--- /dev/null
+++ b/frontend/src/types/api/ingestionKeys/types.ts
@@ -0,0 +1,85 @@
+export interface User {
+ createdAt?: number;
+ email?: string;
+ id: string;
+ name?: string;
+ notFound?: boolean;
+ profilePictureURL?: string;
+}
+
+export interface Limit {
+ signal: string;
+ id: string;
+ config?: {
+ day?: {
+ size?: number;
+ };
+ second?: {
+ size?: number;
+ };
+ };
+ tags?: [];
+}
+
+export interface IngestionKeyProps {
+ name: string;
+ expires_at?: string;
+ value: string;
+ workspace_id: string;
+ id: string;
+ created_at: string;
+ updated_at: string;
+ tags?: string[];
+ limits?: Limit[];
+}
+
+export interface GetIngestionKeyProps {
+ page: number;
+ per_page: number;
+ search?: string;
+}
+
+export interface CreateIngestionKeyProps {
+ name: string;
+ expires_at: string;
+ tags: string[];
+}
+
+export interface PaginationProps {
+ page: number;
+ per_page: number;
+ pages?: number;
+ total?: number;
+}
+
+export interface AllIngestionKeyProps {
+ status: string;
+ data: IngestionKeyProps[];
+ _pagination: PaginationProps;
+}
+
+export interface CreateIngestionKeyProp {
+ data: IngestionKeyProps;
+}
+
+export interface DeleteIngestionKeyPayloadProps {
+ status: string;
+}
+
+export interface UpdateIngestionKeyProps {
+ id: string;
+ data: {
+ name: string;
+ expires_at: string;
+ tags: string[];
+ };
+}
+
+export type IngestionKeysPayloadProps = {
+ status: string;
+ data: string;
+};
+
+export type GetIngestionKeyPayloadProps = {
+ id: string;
+};
diff --git a/frontend/src/types/api/trace/getTraceItem.ts b/frontend/src/types/api/trace/getTraceItem.ts
index 2e541df929..4a6def3896 100644
--- a/frontend/src/types/api/trace/getTraceItem.ts
+++ b/frontend/src/types/api/trace/getTraceItem.ts
@@ -14,6 +14,7 @@ export interface PayloadProps {
events: Span[];
segmentID: string;
columns: string[];
+ isSubTree: boolean;
};
}
diff --git a/frontend/src/types/api/widgets/getQuery.ts b/frontend/src/types/api/widgets/getQuery.ts
index 5f455698dd..52d2f18d80 100644
--- a/frontend/src/types/api/widgets/getQuery.ts
+++ b/frontend/src/types/api/widgets/getQuery.ts
@@ -22,6 +22,7 @@ export interface SeriesItem {
labels: {
[key: string]: string;
};
+ labelsArray: { [key: string]: string }[];
values: { timestamp: number; value: string }[];
}
diff --git a/frontend/src/types/reducer/trace.ts b/frontend/src/types/reducer/trace.ts
index cc35cbc44a..ef10c8e4fb 100644
--- a/frontend/src/types/reducer/trace.ts
+++ b/frontend/src/types/reducer/trace.ts
@@ -72,9 +72,7 @@ export type OperatorValues =
| 'NotStartsWith';
export type TraceFilterEnum =
- | 'component'
| 'duration'
- | 'httpCode'
| 'httpHost'
| 'httpMethod'
| 'httpRoute'
@@ -90,18 +88,10 @@ export const AllPanelHeading: {
key: TraceFilterEnum;
displayValue: string;
}[] = [
- {
- displayValue: 'Component',
- key: 'component',
- },
{
key: 'duration',
displayValue: 'Duration',
},
- {
- displayValue: 'HTTP Code',
- key: 'httpCode',
- },
{
key: 'httpHost',
displayValue: 'HTTP Host',
diff --git a/frontend/src/utils/getGraphType.ts b/frontend/src/utils/getGraphType.ts
index 8f1ba43da3..9c3ded97e8 100644
--- a/frontend/src/utils/getGraphType.ts
+++ b/frontend/src/utils/getGraphType.ts
@@ -2,7 +2,7 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
export const getGraphType = (panelType: PANEL_TYPES): PANEL_TYPES => {
// backend don't support graphType as bar, as we consume time series data, sending graphType as time_series whenever we use bar as panel_type
- if (panelType === PANEL_TYPES.BAR) {
+ if (panelType === PANEL_TYPES.BAR || panelType === PANEL_TYPES.HISTOGRAM) {
return PANEL_TYPES.TIME_SERIES;
}
if (panelType === PANEL_TYPES.PIE) {
diff --git a/frontend/src/utils/timeZoneUtil.ts b/frontend/src/utils/timeZoneUtil.ts
new file mode 100644
index 0000000000..30330f4912
--- /dev/null
+++ b/frontend/src/utils/timeZoneUtil.ts
@@ -0,0 +1,595 @@
+export const ALL_TIME_ZONES = [
+ 'Africa/Abidjan',
+ 'Africa/Accra',
+ 'Africa/Addis_Ababa',
+ 'Africa/Algiers',
+ 'Africa/Asmara',
+ 'Africa/Asmera',
+ 'Africa/Bamako',
+ 'Africa/Bangui',
+ 'Africa/Banjul',
+ 'Africa/Bissau',
+ 'Africa/Blantyre',
+ 'Africa/Brazzaville',
+ 'Africa/Bujumbura',
+ 'Africa/Cairo',
+ 'Africa/Casablanca',
+ 'Africa/Ceuta',
+ 'Africa/Conakry',
+ 'Africa/Dakar',
+ 'Africa/Dar_es_Salaam',
+ 'Africa/Djibouti',
+ 'Africa/Douala',
+ 'Africa/El_Aaiun',
+ 'Africa/Freetown',
+ 'Africa/Gaborone',
+ 'Africa/Harare',
+ 'Africa/Johannesburg',
+ 'Africa/Juba',
+ 'Africa/Kampala',
+ 'Africa/Khartoum',
+ 'Africa/Kigali',
+ 'Africa/Kinshasa',
+ 'Africa/Lagos',
+ 'Africa/Libreville',
+ 'Africa/Lome',
+ 'Africa/Luanda',
+ 'Africa/Lubumbashi',
+ 'Africa/Lusaka',
+ 'Africa/Malabo',
+ 'Africa/Maputo',
+ 'Africa/Maseru',
+ 'Africa/Mbabane',
+ 'Africa/Mogadishu',
+ 'Africa/Monrovia',
+ 'Africa/Nairobi',
+ 'Africa/Ndjamena',
+ 'Africa/Niamey',
+ 'Africa/Nouakchott',
+ 'Africa/Ouagadougou',
+ 'Africa/Porto-Novo',
+ 'Africa/Sao_Tome',
+ 'Africa/Timbuktu',
+ 'Africa/Tripoli',
+ 'Africa/Tunis',
+ 'Africa/Windhoek',
+ 'America/Adak',
+ 'America/Anchorage',
+ 'America/Anguilla',
+ 'America/Antigua',
+ 'America/Araguaina',
+ 'America/Argentina/Buenos_Aires',
+ 'America/Argentina/Catamarca',
+ 'America/Argentina/ComodRivadavia',
+ 'America/Argentina/Cordoba',
+ 'America/Argentina/Jujuy',
+ 'America/Argentina/La_Rioja',
+ 'America/Argentina/Mendoza',
+ 'America/Argentina/Rio_Gallegos',
+ 'America/Argentina/Salta',
+ 'America/Argentina/San_Juan',
+ 'America/Argentina/San_Luis',
+ 'America/Argentina/Tucuman',
+ 'America/Argentina/Ushuaia',
+ 'America/Aruba',
+ 'America/Asuncion',
+ 'America/Atikokan',
+ 'America/Atka',
+ 'America/Bahia',
+ 'America/Bahia_Banderas',
+ 'America/Barbados',
+ 'America/Belem',
+ 'America/Belize',
+ 'America/Blanc-Sablon',
+ 'America/Boa_Vista',
+ 'America/Bogota',
+ 'America/Boise',
+ 'America/Buenos_Aires',
+ 'America/Cambridge_Bay',
+ 'America/Campo_Grande',
+ 'America/Cancun',
+ 'America/Caracas',
+ 'America/Catamarca',
+ 'America/Cayenne',
+ 'America/Cayman',
+ 'America/Chicago',
+ 'America/Chihuahua',
+ 'America/Coral_Harbour',
+ 'America/Cordoba',
+ 'America/Costa_Rica',
+ 'America/Creston',
+ 'America/Cuiaba',
+ 'America/Curacao',
+ 'America/Danmarkshavn',
+ 'America/Dawson',
+ 'America/Dawson_Creek',
+ 'America/Denver',
+ 'America/Detroit',
+ 'America/Dominica',
+ 'America/Edmonton',
+ 'America/Eirunepe',
+ 'America/El_Salvador',
+ 'America/Ensenada',
+ 'America/Fort_Nelson',
+ 'America/Fort_Wayne',
+ 'America/Fortaleza',
+ 'America/Glace_Bay',
+ 'America/Godthab',
+ 'America/Goose_Bay',
+ 'America/Grand_Turk',
+ 'America/Grenada',
+ 'America/Guadeloupe',
+ 'America/Guatemala',
+ 'America/Guayaquil',
+ 'America/Guyana',
+ 'America/Halifax',
+ 'America/Havana',
+ 'America/Hermosillo',
+ 'America/Indiana/Indianapolis',
+ 'America/Indiana/Knox',
+ 'America/Indiana/Marengo',
+ 'America/Indiana/Petersburg',
+ 'America/Indiana/Tell_City',
+ 'America/Indiana/Vevay',
+ 'America/Indiana/Vincennes',
+ 'America/Indiana/Winamac',
+ 'America/Indianapolis',
+ 'America/Inuvik',
+ 'America/Iqaluit',
+ 'America/Jamaica',
+ 'America/Jujuy',
+ 'America/Juneau',
+ 'America/Kentucky/Louisville',
+ 'America/Kentucky/Monticello',
+ 'America/Knox_IN',
+ 'America/Kralendijk',
+ 'America/La_Paz',
+ 'America/Lima',
+ 'America/Los_Angeles',
+ 'America/Louisville',
+ 'America/Lower_Princes',
+ 'America/Maceio',
+ 'America/Managua',
+ 'America/Manaus',
+ 'America/Marigot',
+ 'America/Martinique',
+ 'America/Matamoros',
+ 'America/Mazatlan',
+ 'America/Mendoza',
+ 'America/Menominee',
+ 'America/Merida',
+ 'America/Metlakatla',
+ 'America/Mexico_City',
+ 'America/Miquelon',
+ 'America/Moncton',
+ 'America/Monterrey',
+ 'America/Montevideo',
+ 'America/Montreal',
+ 'America/Montserrat',
+ 'America/Nassau',
+ 'America/New_York',
+ 'America/Nipigon',
+ 'America/Nome',
+ 'America/Noronha',
+ 'America/North_Dakota/Beulah',
+ 'America/North_Dakota/Center',
+ 'America/North_Dakota/New_Salem',
+ 'America/Nuuk',
+ 'America/Ojinaga',
+ 'America/Panama',
+ 'America/Pangnirtung',
+ 'America/Paramaribo',
+ 'America/Phoenix',
+ 'America/Port-au-Prince',
+ 'America/Port_of_Spain',
+ 'America/Porto_Acre',
+ 'America/Porto_Velho',
+ 'America/Puerto_Rico',
+ 'America/Punta_Arenas',
+ 'America/Rainy_River',
+ 'America/Rankin_Inlet',
+ 'America/Recife',
+ 'America/Regina',
+ 'America/Resolute',
+ 'America/Rio_Branco',
+ 'America/Rosario',
+ 'America/Santa_Isabel',
+ 'America/Santarem',
+ 'America/Santiago',
+ 'America/Santo_Domingo',
+ 'America/Sao_Paulo',
+ 'America/Scoresbysund',
+ 'America/Shiprock',
+ 'America/Sitka',
+ 'America/St_Barthelemy',
+ 'America/St_Johns',
+ 'America/St_Kitts',
+ 'America/St_Lucia',
+ 'America/St_Thomas',
+ 'America/St_Vincent',
+ 'America/Swift_Current',
+ 'America/Tegucigalpa',
+ 'America/Thule',
+ 'America/Thunder_Bay',
+ 'America/Tijuana',
+ 'America/Toronto',
+ 'America/Tortola',
+ 'America/Vancouver',
+ 'America/Virgin',
+ 'America/Whitehorse',
+ 'America/Winnipeg',
+ 'America/Yakutat',
+ 'America/Yellowknife',
+ 'Antarctica/Casey',
+ 'Antarctica/Davis',
+ 'Antarctica/DumontDUrville',
+ 'Antarctica/Macquarie',
+ 'Antarctica/Mawson',
+ 'Antarctica/McMurdo',
+ 'Antarctica/Palmer',
+ 'Antarctica/Rothera',
+ 'Antarctica/South_Pole',
+ 'Antarctica/Syowa',
+ 'Antarctica/Troll',
+ 'Antarctica/Vostok',
+ 'Arctic/Longyearbyen',
+ 'Asia/Aden',
+ 'Asia/Almaty',
+ 'Asia/Amman',
+ 'Asia/Anadyr',
+ 'Asia/Aqtau',
+ 'Asia/Aqtobe',
+ 'Asia/Ashgabat',
+ 'Asia/Ashkhabad',
+ 'Asia/Atyrau',
+ 'Asia/Baghdad',
+ 'Asia/Bahrain',
+ 'Asia/Baku',
+ 'Asia/Bangkok',
+ 'Asia/Barnaul',
+ 'Asia/Beirut',
+ 'Asia/Bishkek',
+ 'Asia/Brunei',
+ 'Asia/Calcutta',
+ 'Asia/Chita',
+ 'Asia/Choibalsan',
+ 'Asia/Chongqing',
+ 'Asia/Chungking',
+ 'Asia/Colombo',
+ 'Asia/Dacca',
+ 'Asia/Damascus',
+ 'Asia/Dhaka',
+ 'Asia/Dili',
+ 'Asia/Dubai',
+ 'Asia/Dushanbe',
+ 'Asia/Famagusta',
+ 'Asia/Gaza',
+ 'Asia/Harbin',
+ 'Asia/Hebron',
+ 'Asia/Ho_Chi_Minh',
+ 'Asia/Hong_Kong',
+ 'Asia/Hovd',
+ 'Asia/Irkutsk',
+ 'Asia/Istanbul',
+ 'Asia/Jakarta',
+ 'Asia/Jayapura',
+ 'Asia/Jerusalem',
+ 'Asia/Kabul',
+ 'Asia/Kamchatka',
+ 'Asia/Karachi',
+ 'Asia/Kashgar',
+ 'Asia/Kathmandu',
+ 'Asia/Katmandu',
+ 'Asia/Khandyga',
+ 'Asia/Kolkata',
+ 'Asia/Krasnoyarsk',
+ 'Asia/Kuala_Lumpur',
+ 'Asia/Kuching',
+ 'Asia/Kuwait',
+ 'Asia/Macao',
+ 'Asia/Macau',
+ 'Asia/Magadan',
+ 'Asia/Makassar',
+ 'Asia/Manila',
+ 'Asia/Muscat',
+ 'Asia/Nicosia',
+ 'Asia/Novokuznetsk',
+ 'Asia/Novosibirsk',
+ 'Asia/Omsk',
+ 'Asia/Oral',
+ 'Asia/Phnom_Penh',
+ 'Asia/Pontianak',
+ 'Asia/Pyongyang',
+ 'Asia/Qatar',
+ 'Asia/Qostanay',
+ 'Asia/Qyzylorda',
+ 'Asia/Rangoon',
+ 'Asia/Riyadh',
+ 'Asia/Saigon',
+ 'Asia/Sakhalin',
+ 'Asia/Samarkand',
+ 'Asia/Seoul',
+ 'Asia/Shanghai',
+ 'Asia/Singapore',
+ 'Asia/Srednekolymsk',
+ 'Asia/Taipei',
+ 'Asia/Tashkent',
+ 'Asia/Tbilisi',
+ 'Asia/Tehran',
+ 'Asia/Tel_Aviv',
+ 'Asia/Thimbu',
+ 'Asia/Thimphu',
+ 'Asia/Tokyo',
+ 'Asia/Tomsk',
+ 'Asia/Ujung_Pandang',
+ 'Asia/Ulaanbaatar',
+ 'Asia/Ulan_Bator',
+ 'Asia/Urumqi',
+ 'Asia/Ust-Nera',
+ 'Asia/Vientiane',
+ 'Asia/Vladivostok',
+ 'Asia/Yakutsk',
+ 'Asia/Yangon',
+ 'Asia/Yekaterinburg',
+ 'Asia/Yerevan',
+ 'Atlantic/Azores',
+ 'Atlantic/Bermuda',
+ 'Atlantic/Canary',
+ 'Atlantic/Cape_Verde',
+ 'Atlantic/Faeroe',
+ 'Atlantic/Faroe',
+ 'Atlantic/Jan_Mayen',
+ 'Atlantic/Madeira',
+ 'Atlantic/Reykjavik',
+ 'Atlantic/South_Georgia',
+ 'Atlantic/St_Helena',
+ 'Atlantic/Stanley',
+ 'Australia/ACT',
+ 'Australia/Adelaide',
+ 'Australia/Brisbane',
+ 'Australia/Broken_Hill',
+ 'Australia/Canberra',
+ 'Australia/Currie',
+ 'Australia/Darwin',
+ 'Australia/Eucla',
+ 'Australia/Hobart',
+ 'Australia/LHI',
+ 'Australia/Lindeman',
+ 'Australia/Lord_Howe',
+ 'Australia/Melbourne',
+ 'Australia/NSW',
+ 'Australia/North',
+ 'Australia/Perth',
+ 'Australia/Queensland',
+ 'Australia/South',
+ 'Australia/Sydney',
+ 'Australia/Tasmania',
+ 'Australia/Victoria',
+ 'Australia/West',
+ 'Australia/Yancowinna',
+ 'Brazil/Acre',
+ 'Brazil/DeNoronha',
+ 'Brazil/East',
+ 'Brazil/West',
+ 'CET',
+ 'CST6CDT',
+ 'Canada/Atlantic',
+ 'Canada/Central',
+ 'Canada/Eastern',
+ 'Canada/Mountain',
+ 'Canada/Newfoundland',
+ 'Canada/Pacific',
+ 'Canada/Saskatchewan',
+ 'Canada/Yukon',
+ 'Chile/Continental',
+ 'Chile/EasterIsland',
+ 'Cuba',
+ 'EET',
+ 'EST',
+ 'EST5EDT',
+ 'Egypt',
+ 'Eire',
+ 'Etc/GMT',
+ 'Etc/GMT+0',
+ 'Etc/GMT+1',
+ 'Etc/GMT+10',
+ 'Etc/GMT+11',
+ 'Etc/GMT+12',
+ 'Etc/GMT+2',
+ 'Etc/GMT+3',
+ 'Etc/GMT+4',
+ 'Etc/GMT+5',
+ 'Etc/GMT+6',
+ 'Etc/GMT+7',
+ 'Etc/GMT+8',
+ 'Etc/GMT+9',
+ 'Etc/GMT-0',
+ 'Etc/GMT-1',
+ 'Etc/GMT-10',
+ 'Etc/GMT-11',
+ 'Etc/GMT-12',
+ 'Etc/GMT-13',
+ 'Etc/GMT-14',
+ 'Etc/GMT-2',
+ 'Etc/GMT-3',
+ 'Etc/GMT-4',
+ 'Etc/GMT-5',
+ 'Etc/GMT-6',
+ 'Etc/GMT-7',
+ 'Etc/GMT-8',
+ 'Etc/GMT-9',
+ 'Etc/GMT0',
+ 'Etc/Greenwich',
+ 'Etc/UCT',
+ 'Etc/UTC',
+ 'Etc/Universal',
+ 'Etc/Zulu',
+ 'Europe/Amsterdam',
+ 'Europe/Andorra',
+ 'Europe/Astrakhan',
+ 'Europe/Athens',
+ 'Europe/Belfast',
+ 'Europe/Belgrade',
+ 'Europe/Berlin',
+ 'Europe/Bratislava',
+ 'Europe/Brussels',
+ 'Europe/Bucharest',
+ 'Europe/Budapest',
+ 'Europe/Busingen',
+ 'Europe/Chisinau',
+ 'Europe/Copenhagen',
+ 'Europe/Dublin',
+ 'Europe/Gibraltar',
+ 'Europe/Guernsey',
+ 'Europe/Helsinki',
+ 'Europe/Isle_of_Man',
+ 'Europe/Istanbul',
+ 'Europe/Jersey',
+ 'Europe/Kaliningrad',
+ 'Europe/Kiev',
+ 'Europe/Kirov',
+ 'Europe/Lisbon',
+ 'Europe/Ljubljana',
+ 'Europe/London',
+ 'Europe/Luxembourg',
+ 'Europe/Madrid',
+ 'Europe/Malta',
+ 'Europe/Mariehamn',
+ 'Europe/Minsk',
+ 'Europe/Monaco',
+ 'Europe/Moscow',
+ 'Europe/Nicosia',
+ 'Europe/Oslo',
+ 'Europe/Paris',
+ 'Europe/Podgorica',
+ 'Europe/Prague',
+ 'Europe/Riga',
+ 'Europe/Rome',
+ 'Europe/Samara',
+ 'Europe/San_Marino',
+ 'Europe/Sarajevo',
+ 'Europe/Saratov',
+ 'Europe/Simferopol',
+ 'Europe/Skopje',
+ 'Europe/Sofia',
+ 'Europe/Stockholm',
+ 'Europe/Tallinn',
+ 'Europe/Tirane',
+ 'Europe/Tiraspol',
+ 'Europe/Ulyanovsk',
+ 'Europe/Uzhgorod',
+ 'Europe/Vaduz',
+ 'Europe/Vatican',
+ 'Europe/Vienna',
+ 'Europe/Vilnius',
+ 'Europe/Volgograd',
+ 'Europe/Warsaw',
+ 'Europe/Zagreb',
+ 'Europe/Zaporozhye',
+ 'Europe/Zurich',
+ 'GB',
+ 'GB-Eire',
+ 'GMT',
+ 'GMT+0',
+ 'GMT-0',
+ 'GMT0',
+ 'Greenwich',
+ 'HST',
+ 'Hongkong',
+ 'Iceland',
+ 'Indian/Antananarivo',
+ 'Indian/Chagos',
+ 'Indian/Christmas',
+ 'Indian/Cocos',
+ 'Indian/Comoro',
+ 'Indian/Kerguelen',
+ 'Indian/Mahe',
+ 'Indian/Maldives',
+ 'Indian/Mauritius',
+ 'Indian/Mayotte',
+ 'Indian/Reunion',
+ 'Iran',
+ 'Israel',
+ 'Jamaica',
+ 'Japan',
+ 'Kwajalein',
+ 'Libya',
+ 'MET',
+ 'MST',
+ 'MST7MDT',
+ 'Mexico/BajaNorte',
+ 'Mexico/BajaSur',
+ 'Mexico/General',
+ 'NZ',
+ 'NZ-CHAT',
+ 'Navajo',
+ 'PRC',
+ 'PST8PDT',
+ 'Pacific/Apia',
+ 'Pacific/Auckland',
+ 'Pacific/Bougainville',
+ 'Pacific/Chatham',
+ 'Pacific/Chuuk',
+ 'Pacific/Easter',
+ 'Pacific/Efate',
+ 'Pacific/Enderbury',
+ 'Pacific/Fakaofo',
+ 'Pacific/Fiji',
+ 'Pacific/Funafuti',
+ 'Pacific/Galapagos',
+ 'Pacific/Gambier',
+ 'Pacific/Guadalcanal',
+ 'Pacific/Guam',
+ 'Pacific/Honolulu',
+ 'Pacific/Johnston',
+ 'Pacific/Kiritimati',
+ 'Pacific/Kosrae',
+ 'Pacific/Kwajalein',
+ 'Pacific/Majuro',
+ 'Pacific/Marquesas',
+ 'Pacific/Midway',
+ 'Pacific/Nauru',
+ 'Pacific/Niue',
+ 'Pacific/Norfolk',
+ 'Pacific/Noumea',
+ 'Pacific/Pago_Pago',
+ 'Pacific/Palau',
+ 'Pacific/Pitcairn',
+ 'Pacific/Pohnpei',
+ 'Pacific/Ponape',
+ 'Pacific/Port_Moresby',
+ 'Pacific/Rarotonga',
+ 'Pacific/Saipan',
+ 'Pacific/Samoa',
+ 'Pacific/Tahiti',
+ 'Pacific/Tarawa',
+ 'Pacific/Tongatapu',
+ 'Pacific/Truk',
+ 'Pacific/Wake',
+ 'Pacific/Wallis',
+ 'Pacific/Yap',
+ 'Poland',
+ 'Portugal',
+ 'ROC',
+ 'ROK',
+ 'Singapore',
+ 'Turkey',
+ 'UCT',
+ 'US/Alaska',
+ 'US/Aleutian',
+ 'US/Arizona',
+ 'US/Central',
+ 'US/East-Indiana',
+ 'US/Eastern',
+ 'US/Hawaii',
+ 'US/Indiana-Starke',
+ 'US/Michigan',
+ 'US/Mountain',
+ 'US/Pacific',
+ 'US/Samoa',
+ 'UTC',
+ 'Universal',
+ 'W-SU',
+ 'WET',
+ 'Zulu',
+];
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index af8d30616c..c717a16507 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -6430,6 +6430,13 @@ ccount@^2.0.0:
resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5"
integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==
+centra@^2.7.0:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/centra/-/centra-2.7.0.tgz#4c8312a58436e8a718302011561db7e6a2b0ec18"
+ integrity sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==
+ dependencies:
+ follow-redirects "^1.15.6"
+
chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
@@ -6755,16 +6762,16 @@ comma-separated-tokens@^2.0.0:
resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee"
integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==
+commander@2, commander@^2.20.0, commander@^2.20.3:
+ version "2.20.3"
+ resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz"
+ integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
+
commander@^10.0.0:
version "10.0.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06"
integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==
-commander@^2.20.0, commander@^2.20.3:
- version "2.20.3"
- resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz"
- integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
-
commander@^3.0.2:
version "3.0.2"
resolved "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz"
@@ -7325,6 +7332,11 @@ d3-array@3.2.1:
dependencies:
internmap "1 - 2"
+d3-array@^1.2.0:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f"
+ integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==
+
d3-binarytree@1:
version "1.0.2"
resolved "https://registry.npmjs.org/d3-binarytree/-/d3-binarytree-1.0.2.tgz"
@@ -7400,6 +7412,11 @@ d3-path@1, d3-path@^1.0.5:
resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf"
integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==
+d3-polygon@^1.0.3:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-1.0.6.tgz#0bf8cb8180a6dc107f518ddf7975e12abbfbd38e"
+ integrity sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ==
+
"d3-quadtree@1 - 3":
version "3.0.1"
resolved "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz"
@@ -7892,7 +7909,7 @@ duplexer@^0.1.2:
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
-earcut@^2.2.3:
+earcut@^2.1.1, earcut@^2.2.3:
version "2.2.4"
resolved "https://registry.yarnpkg.com/earcut/-/earcut-2.2.4.tgz#6d02fd4d68160c114825d06890a92ecaae60343a"
integrity sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==
@@ -8891,7 +8908,19 @@ flatten-vertex-data@^1.0.0:
dependencies:
dtype "^2.0.0"
-follow-redirects@^1.0.0, follow-redirects@^1.14.0, follow-redirects@^1.15.4:
+flubber@^0.4.2:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/flubber/-/flubber-0.4.2.tgz#14452d4a838cc3b9f2fb6175da94e35acd55fbaa"
+ integrity sha512-79RkJe3rA4nvRCVc2uXjj7U/BAUq84TS3KHn6c0Hr9K64vhj83ZNLUziNx4pJoBumSPhOl5VjH+Z0uhi+eE8Uw==
+ dependencies:
+ d3-array "^1.2.0"
+ d3-polygon "^1.0.3"
+ earcut "^2.1.1"
+ svg-path-properties "^0.2.1"
+ svgpath "^2.2.1"
+ topojson-client "^3.0.0"
+
+follow-redirects@^1.0.0, follow-redirects@^1.14.0, follow-redirects@^1.15.4, follow-redirects@^1.15.6:
version "1.15.6"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
@@ -11555,10 +11584,10 @@ lru-cache@^6.0.0:
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3"
integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==
-lucide-react@0.321.0:
- version "0.321.0"
- resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.321.0.tgz#05a2600e0a6551c117fb4e7b2676b1286389d949"
- integrity sha512-Fi9VahIna6642U+2nAGSjnXwUBV3WyfFFPQq4yi3w30jtqxDLfSyiYCtCYCYQZ2KWNZc1MDI+rcsa0t+ChdYpw==
+lucide-react@0.379.0:
+ version "0.379.0"
+ resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.379.0.tgz#29e34eeffae7fb241b64b09868cbe3ab888ef7cc"
+ integrity sha512-KcdeVPqmhRldldAAgptb8FjIunM2x2Zy26ZBh1RsEUcdLIvsEmbcw7KpzFYUy5BbpGeWhPu9Z9J5YXfStiXwhg==
lz-string@^1.4.4:
version "1.5.0"
@@ -13310,6 +13339,11 @@ pbf@3.2.1:
ieee754 "^1.1.12"
resolve-protobuf-schema "^2.1.0"
+performance-now@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
+ integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==
+
periscopic@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/periscopic/-/periscopic-3.1.0.tgz#7e9037bf51c5855bd33b48928828db4afa79d97a"
@@ -13319,10 +13353,12 @@ periscopic@^3.0.0:
estree-walker "^3.0.0"
is-reference "^3.0.0"
-phin@^2.9.1:
- version "2.9.3"
- resolved "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz"
- integrity sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==
+phin@^2.9.1, phin@^3.7.1:
+ version "3.7.1"
+ resolved "https://registry.yarnpkg.com/phin/-/phin-3.7.1.tgz#bf841da75ee91286691b10e41522a662aa628fd6"
+ integrity sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==
+ dependencies:
+ centra "^2.7.0"
picocolors@^1.0.0:
version "1.0.0"
@@ -13891,6 +13927,13 @@ raf-schd@^4.0.2:
resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a"
integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==
+raf@^3.4.1:
+ version "3.4.1"
+ resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
+ integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==
+ dependencies:
+ performance-now "^2.1.0"
+
randombytes@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz"
@@ -14269,6 +14312,15 @@ rc-tree@~5.8.1, rc-tree@~5.8.2:
rc-util "^5.16.1"
rc-virtual-list "^3.5.1"
+rc-tween-one@3.0.6:
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/rc-tween-one/-/rc-tween-one-3.0.6.tgz#74e09cdd9da00c27082c8b6f1606dc3bae67797b"
+ integrity sha512-5zTSXyyv7bahDBQ/kJw/kNxxoBqTouttoelw8FOVOyWqmTMndizJEpvaj1N+yES5Xjss6Y2iVw+9vSJQZE8Z6g==
+ dependencies:
+ "@babel/runtime" "^7.11.1"
+ style-utils "^0.3.4"
+ tween-one "^1.0.50"
+
rc-upload@~4.3.5:
version "4.3.5"
resolved "https://registry.yarnpkg.com/rc-upload/-/rc-upload-4.3.5.tgz#12fc69b2af74d08646a104828831bcaf44076eda"
@@ -15990,6 +16042,11 @@ style-to-object@^0.4.0, style-to-object@^0.4.1:
dependencies:
inline-style-parser "0.1.1"
+style-utils@^0.3.4, style-utils@^0.3.6:
+ version "0.3.8"
+ resolved "https://registry.yarnpkg.com/style-utils/-/style-utils-0.3.8.tgz#6ba4271bcc766dee4730bd51b3ef2552908dc111"
+ integrity sha512-RmGftIhY4tqtD1ERwKsVEDlt/M6UyxN/rcr95UmlooWmhtL0RwVUYJkpo1kSx3ppd9/JZzbknhy742zbMAawjQ==
+
styled-components@^5.3.11:
version "5.3.11"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.11.tgz#9fda7bf1108e39bf3f3e612fcc18170dedcd57a8"
@@ -16079,6 +16136,16 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+svg-path-properties@^0.2.1:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/svg-path-properties/-/svg-path-properties-0.2.2.tgz#b073d81be7292eae0e233ab8a83f58dc27113296"
+ integrity sha512-GmrB+b6woz6CCdQe6w1GHs/1lt25l7SR5hmhF8jRdarpv/OgjLyuQygLu1makJapixeb1aQhP/Oa1iKi93o/aQ==
+
+svg-path-properties@^1.0.4:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/svg-path-properties/-/svg-path-properties-1.3.0.tgz#7f47e61dcac380c9f4d04f642df7e69b127274fa"
+ integrity sha512-R1+z37FrqyS3UXDhajNfvMxKI0smuVdedqOo4YbAQUfGqA86B9mGvr2IEXrwjjvGzCtdIKy/ad9N8m6YclaKAw==
+
svgo@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/svgo/-/svgo-3.0.2.tgz#5e99eeea42c68ee0dc46aa16da093838c262fe0a"
@@ -16091,6 +16158,11 @@ svgo@^3.0.2:
csso "^5.0.5"
picocolors "^1.0.0"
+svgpath@^2.2.1:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/svgpath/-/svgpath-2.6.0.tgz#5b160ef3d742b7dfd2d721bf90588d3450d7a90d"
+ integrity sha512-OIWR6bKzXvdXYyO4DK/UWa1VA1JeKq8E+0ug2DG98Y/vOmMpfZNj+TIG988HjfYSqtcy/hFOtZq/n/j5GSESNg==
+
symbol-tree@^3.2.4:
version "3.2.4"
resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz"
@@ -16315,6 +16387,13 @@ toidentifier@1.0.1:
resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz"
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
+topojson-client@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/topojson-client/-/topojson-client-3.1.0.tgz#22e8b1ed08a2b922feeb4af6f53b6ef09a467b99"
+ integrity sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==
+ dependencies:
+ commander "2"
+
totalist@^1.0.0:
version "1.1.0"
resolved "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz"
@@ -16450,6 +16529,23 @@ tsutils@^3.21.0:
dependencies:
tslib "^1.8.1"
+tween-functions@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/tween-functions/-/tween-functions-1.2.0.tgz#1ae3a50e7c60bb3def774eac707acbca73bbc3ff"
+ integrity sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==
+
+tween-one@^1.0.50:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/tween-one/-/tween-one-1.2.7.tgz#80051e9434f145c0e31623790378af0f23fe3d00"
+ integrity sha512-F+Z9LO9GsYqf0j5bgNhAF98RDrAZ7QjQrujJ2lVYSHl4+dBPW/atHluL2bwclZf8Vo0Yo96f6pw2uq1OGzpC/Q==
+ dependencies:
+ "@babel/runtime" "^7.11.1"
+ flubber "^0.4.2"
+ raf "^3.4.1"
+ style-utils "^0.3.6"
+ svg-path-properties "^1.0.4"
+ tween-functions "^1.2.0"
+
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz"
diff --git a/go.mod b/go.mod
index 51d72be2f8..a8de8d1c41 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ require (
github.com/ClickHouse/clickhouse-go/v2 v2.20.0
github.com/DATA-DOG/go-sqlmock v1.5.2
github.com/SigNoz/govaluate v0.0.0-20240203125216-988004ccc7fd
- github.com/SigNoz/signoz-otel-collector v0.88.24
+ github.com/SigNoz/signoz-otel-collector v0.88.26
github.com/SigNoz/zap_otlp/zap_otlp_encoder v0.0.0-20230822164844-1b861a431974
github.com/SigNoz/zap_otlp/zap_otlp_sync v0.0.0-20230822164844-1b861a431974
github.com/antonmedv/expr v1.15.3
@@ -77,6 +77,14 @@ require (
k8s.io/apimachinery v0.28.2
)
+require (
+ github.com/emicklei/go-restful/v3 v3.11.0 // indirect
+ golang.org/x/tools v0.16.1 // indirect
+ k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
+ sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
+ sigs.k8s.io/yaml v1.4.0 // indirect
+)
+
require (
contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 // indirect
@@ -139,6 +147,7 @@ require (
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
+ github.com/onsi/gomega v1.19.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.88.0 // indirect
github.com/paulmach/orb v0.11.1 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
@@ -198,7 +207,7 @@ require (
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
- k8s.io/klog/v2 v2.100.1 // indirect
+ k8s.io/klog/v2 v2.110.1 // indirect
k8s.io/utils v0.0.0-20230711102312-30195339c3c7 // indirect
)
diff --git a/go.sum b/go.sum
index e0a7e14e85..e6d22788a4 100644
--- a/go.sum
+++ b/go.sum
@@ -98,8 +98,8 @@ github.com/SigNoz/govaluate v0.0.0-20240203125216-988004ccc7fd h1:Bk43AsDYe0fhkb
github.com/SigNoz/govaluate v0.0.0-20240203125216-988004ccc7fd/go.mod h1:nxRcH/OEdM8QxzH37xkGzomr1O0JpYBRS6pwjsWW6Pc=
github.com/SigNoz/prometheus v1.11.0 h1:toX7fU2wqY1TnzvPzDglIYx6OxpqrZ0NNlM/H5S5+u8=
github.com/SigNoz/prometheus v1.11.0/go.mod h1:MffmFu2qFILQrOHehx3D0XjYtaZMVfI+Ppeiv98x4Ww=
-github.com/SigNoz/signoz-otel-collector v0.88.24 h1:6ESLmQtYPHmik9ZZFSJSbfuj4VQ1/0IC3v1qV9hm5Nk=
-github.com/SigNoz/signoz-otel-collector v0.88.24/go.mod h1:sT1EM9PFDaOJLbAz5npWpgXK6OhpWJ9PpSwyhHWs9rU=
+github.com/SigNoz/signoz-otel-collector v0.88.26 h1:+dbBOzIN6nKWD6DSAbsTtm9fcsUC5dSkhDLk6IfQuxg=
+github.com/SigNoz/signoz-otel-collector v0.88.26/go.mod h1:sT1EM9PFDaOJLbAz5npWpgXK6OhpWJ9PpSwyhHWs9rU=
github.com/SigNoz/zap_otlp v0.1.0 h1:T7rRcFN87GavY8lDGZj0Z3Xv6OhJA6Pj3I9dNPmqvRc=
github.com/SigNoz/zap_otlp v0.1.0/go.mod h1:lcHvbDbRgvDnPxo9lDlaL1JK2PyOyouP/C3ynnYIvyo=
github.com/SigNoz/zap_otlp/zap_otlp_encoder v0.0.0-20230822164844-1b861a431974 h1:PKVgdf83Yw+lZJbFtNGBgqXiXNf3+kOXW2qZ7Ms7OaY=
@@ -204,8 +204,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
-github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE=
-github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
+github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -260,8 +260,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/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.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
@@ -636,8 +636,9 @@ github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
-github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
+github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
+github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/open-telemetry/opamp-go v0.5.0 h1:2YFbb6G4qBkq3yTRdVb5Nfz9hKHW/ldUyex352e1J7g=
github.com/open-telemetry/opamp-go v0.5.0/go.mod h1:IMdeuHGVc5CjKSu5/oNV0o+UmiXuahoHvoZ4GOmAI9M=
github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage v0.88.0 h1:9gjzrpUlzGC5BebgO1cxb/9KQ9yuIIE6B+6wLySKVCQ=
@@ -984,8 +985,8 @@ 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.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
-golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
+golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
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=
@@ -1260,8 +1261,8 @@ 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.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
-golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
+golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
+golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
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=
@@ -1504,10 +1505,10 @@ k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ=
k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU=
k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY=
k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY=
-k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
-k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
-k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ=
-k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM=
+k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
+k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
+k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
+k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc=
k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
@@ -1515,8 +1516,8 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
-sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk=
-sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
-sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
-sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
+sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
+sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
diff --git a/pkg/query-service/app/clickhouseReader/reader.go b/pkg/query-service/app/clickhouseReader/reader.go
index b7e1ec6a67..c4a3de87eb 100644
--- a/pkg/query-service/app/clickhouseReader/reader.go
+++ b/pkg/query-service/app/clickhouseReader/reader.go
@@ -1075,9 +1075,6 @@ func (r *ClickHouseReader) GetSpanFilters(ctx context.Context, queryParams *mode
if len(queryParams.HttpRoute) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpRoute, constants.HttpRoute, &query, args)
}
- if len(queryParams.HttpCode) > 0 {
- args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpCode, constants.HttpCode, &query, args)
- }
if len(queryParams.HttpHost) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpHost, constants.HttpHost, &query, args)
}
@@ -1087,9 +1084,6 @@ func (r *ClickHouseReader) GetSpanFilters(ctx context.Context, queryParams *mode
if len(queryParams.HttpUrl) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpUrl, constants.HttpUrl, &query, args)
}
- if len(queryParams.Component) > 0 {
- args = buildFilterArrayQuery(ctx, excludeMap, queryParams.Component, constants.Component, &query, args)
- }
if len(queryParams.Operation) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.Operation, constants.OperationDB, &query, args)
}
@@ -1123,12 +1117,10 @@ func (r *ClickHouseReader) GetSpanFilters(ctx context.Context, queryParams *mode
Operation: map[string]uint64{},
ResponseStatusCode: map[string]uint64{},
RPCMethod: map[string]uint64{},
- HttpCode: map[string]uint64{},
HttpMethod: map[string]uint64{},
HttpUrl: map[string]uint64{},
HttpRoute: map[string]uint64{},
HttpHost: map[string]uint64{},
- Component: map[string]uint64{},
}
for _, e := range queryParams.GetFilters {
@@ -1152,23 +1144,6 @@ func (r *ClickHouseReader) GetSpanFilters(ctx context.Context, queryParams *mode
traceFilterReponse.ServiceName[service.ServiceName] = service.Count
}
}
- case constants.HttpCode:
- finalQuery := fmt.Sprintf("SELECT httpCode, count() as count FROM %s.%s WHERE timestamp >= @timestampL AND timestamp <= @timestampU", r.TraceDB, r.indexTable)
- finalQuery += query
- finalQuery += " GROUP BY httpCode"
- var dBResponse []model.DBResponseHttpCode
- err := r.db.Select(ctx, &dBResponse, finalQuery, args...)
- zap.L().Info(finalQuery)
-
- if err != nil {
- zap.L().Error("Error in processing sql query", zap.Error(err))
- return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("Error in processing sql query: %s", err)}
- }
- for _, service := range dBResponse {
- if service.HttpCode != "" {
- traceFilterReponse.HttpCode[service.HttpCode] = service.Count
- }
- }
case constants.HttpRoute:
finalQuery := fmt.Sprintf("SELECT httpRoute, count() as count FROM %s.%s WHERE timestamp >= @timestampL AND timestamp <= @timestampU", r.TraceDB, r.indexTable)
finalQuery += query
@@ -1254,23 +1229,6 @@ func (r *ClickHouseReader) GetSpanFilters(ctx context.Context, queryParams *mode
traceFilterReponse.Operation[service.Operation] = service.Count
}
}
- case constants.Component:
- finalQuery := fmt.Sprintf("SELECT component, count() as count FROM %s.%s WHERE timestamp >= @timestampL AND timestamp <= @timestampU", r.TraceDB, r.indexTable)
- finalQuery += query
- finalQuery += " GROUP BY component"
- var dBResponse []model.DBResponseComponent
- err := r.db.Select(ctx, &dBResponse, finalQuery, args...)
- zap.L().Info(finalQuery)
-
- if err != nil {
- zap.L().Error("Error in processing sql query", zap.Error(err))
- return nil, &model.ApiError{Typ: model.ErrorExec, Err: fmt.Errorf("Error in processing sql query: %s", err)}
- }
- for _, service := range dBResponse {
- if service.Component != "" {
- traceFilterReponse.Component[service.Component] = service.Count
- }
- }
case constants.Status:
finalQuery := fmt.Sprintf("SELECT COUNT(*) as numTotal FROM %s.%s WHERE timestamp >= @timestampL AND timestamp <= @timestampU AND hasError = true", r.TraceDB, r.indexTable)
finalQuery += query
@@ -1441,9 +1399,6 @@ func (r *ClickHouseReader) GetFilteredSpans(ctx context.Context, queryParams *mo
if len(queryParams.HttpRoute) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpRoute, constants.HttpRoute, &query, args)
}
- if len(queryParams.HttpCode) > 0 {
- args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpCode, constants.HttpCode, &query, args)
- }
if len(queryParams.HttpHost) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpHost, constants.HttpHost, &query, args)
}
@@ -1453,9 +1408,6 @@ func (r *ClickHouseReader) GetFilteredSpans(ctx context.Context, queryParams *mo
if len(queryParams.HttpUrl) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpUrl, constants.HttpUrl, &query, args)
}
- if len(queryParams.Component) > 0 {
- args = buildFilterArrayQuery(ctx, excludeMap, queryParams.Component, constants.Component, &query, args)
- }
if len(queryParams.Operation) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.Operation, constants.OperationDB, &query, args)
}
@@ -1736,9 +1688,6 @@ func (r *ClickHouseReader) GetTagFilters(ctx context.Context, queryParams *model
if len(queryParams.HttpRoute) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpRoute, constants.HttpRoute, &query, args)
}
- if len(queryParams.HttpCode) > 0 {
- args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpCode, constants.HttpCode, &query, args)
- }
if len(queryParams.HttpHost) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpHost, constants.HttpHost, &query, args)
}
@@ -1748,9 +1697,6 @@ func (r *ClickHouseReader) GetTagFilters(ctx context.Context, queryParams *model
if len(queryParams.HttpUrl) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpUrl, constants.HttpUrl, &query, args)
}
- if len(queryParams.Component) > 0 {
- args = buildFilterArrayQuery(ctx, excludeMap, queryParams.Component, constants.Component, &query, args)
- }
if len(queryParams.Operation) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.Operation, constants.OperationDB, &query, args)
}
@@ -1811,7 +1757,6 @@ func excludeTags(ctx context.Context, tags []string) []string {
"http.host": true,
"messaging.system": true,
"messaging.operation": true,
- "component": true,
"error": true,
"service.name": true,
}
@@ -1861,9 +1806,6 @@ func (r *ClickHouseReader) GetTagValues(ctx context.Context, queryParams *model.
if len(queryParams.HttpRoute) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpRoute, constants.HttpRoute, &query, args)
}
- if len(queryParams.HttpCode) > 0 {
- args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpCode, constants.HttpCode, &query, args)
- }
if len(queryParams.HttpHost) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpHost, constants.HttpHost, &query, args)
}
@@ -1873,9 +1815,6 @@ func (r *ClickHouseReader) GetTagValues(ctx context.Context, queryParams *model.
if len(queryParams.HttpUrl) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpUrl, constants.HttpUrl, &query, args)
}
- if len(queryParams.Component) > 0 {
- args = buildFilterArrayQuery(ctx, excludeMap, queryParams.Component, constants.Component, &query, args)
- }
if len(queryParams.Operation) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.Operation, constants.OperationDB, &query, args)
}
@@ -2014,7 +1953,39 @@ func (r *ClickHouseReader) GetUsage(ctx context.Context, queryParams *model.GetU
return &usageItems, nil
}
-func (r *ClickHouseReader) SearchTraces(ctx context.Context, traceId string, spanId string, levelUp int, levelDown int, spanLimit int, smartTraceAlgorithm func(payload []model.SearchSpanResponseItem, targetSpanId string, levelUp int, levelDown int, spanLimit int) ([]model.SearchSpansResult, error)) (*[]model.SearchSpansResult, error) {
+func (r *ClickHouseReader) SearchTraces(ctx context.Context, params *model.SearchTracesParams,
+ smartTraceAlgorithm func(payload []model.SearchSpanResponseItem, targetSpanId string,
+ levelUp int, levelDown int, spanLimit int) ([]model.SearchSpansResult, error)) (*[]model.SearchSpansResult, error) {
+
+ var countSpans uint64
+ countQuery := fmt.Sprintf("SELECT count() as count from %s.%s WHERE traceID=$1", r.TraceDB, r.SpansTable)
+ err := r.db.QueryRow(ctx, countQuery, params.TraceID).Scan(&countSpans)
+ if err != nil {
+ zap.L().Error("Error in processing sql query", zap.Error(err))
+ return nil, fmt.Errorf("error in processing sql query")
+ }
+
+ if countSpans > uint64(params.MaxSpansInTrace) {
+ zap.L().Error("Max spans allowed in a trace limit reached", zap.Int("MaxSpansInTrace", params.MaxSpansInTrace),
+ zap.Uint64("Count", countSpans))
+ userEmail, err := auth.GetEmailFromJwt(ctx)
+ if err == nil {
+ data := map[string]interface{}{
+ "traceSize": countSpans,
+ "maxSpansInTraceLimit": params.MaxSpansInTrace,
+ }
+ telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_MAX_SPANS_ALLOWED_LIMIT_REACHED, data, userEmail, true, false)
+ }
+ return nil, fmt.Errorf("Max spans allowed in trace limit reached, please contact support for more details")
+ }
+
+ userEmail, err := auth.GetEmailFromJwt(ctx)
+ if err == nil {
+ data := map[string]interface{}{
+ "traceSize": countSpans,
+ }
+ telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_TRACE_DETAIL_API, data, userEmail, true, false)
+ }
var searchScanResponses []model.SearchSpanDBResponseItem
@@ -2022,7 +1993,7 @@ func (r *ClickHouseReader) SearchTraces(ctx context.Context, traceId string, spa
start := time.Now()
- err := r.db.Select(ctx, &searchScanResponses, query, traceId)
+ err = r.db.Select(ctx, &searchScanResponses, query, params.TraceID)
zap.L().Info(query)
@@ -2033,8 +2004,9 @@ func (r *ClickHouseReader) SearchTraces(ctx context.Context, traceId string, spa
end := time.Now()
zap.L().Debug("getTraceSQLQuery took: ", zap.Duration("duration", end.Sub(start)))
searchSpansResult := []model.SearchSpansResult{{
- Columns: []string{"__time", "SpanId", "TraceId", "ServiceName", "Name", "Kind", "DurationNano", "TagsKeys", "TagsValues", "References", "Events", "HasError"},
- Events: make([][]interface{}, len(searchScanResponses)),
+ Columns: []string{"__time", "SpanId", "TraceId", "ServiceName", "Name", "Kind", "DurationNano", "TagsKeys", "TagsValues", "References", "Events", "HasError"},
+ Events: make([][]interface{}, len(searchScanResponses)),
+ IsSubTree: false,
},
}
@@ -2051,14 +2023,22 @@ func (r *ClickHouseReader) SearchTraces(ctx context.Context, traceId string, spa
err = r.featureFlags.CheckFeature(model.SmartTraceDetail)
smartAlgoEnabled := err == nil
- if len(searchScanResponses) > spanLimit && spanId != "" && smartAlgoEnabled {
+ if len(searchScanResponses) > params.SpansRenderLimit && smartAlgoEnabled {
start = time.Now()
- searchSpansResult, err = smartTraceAlgorithm(searchSpanResponses, spanId, levelUp, levelDown, spanLimit)
+ searchSpansResult, err = smartTraceAlgorithm(searchSpanResponses, params.SpanID, params.LevelUp, params.LevelDown, params.SpansRenderLimit)
if err != nil {
return nil, err
}
end = time.Now()
zap.L().Debug("smartTraceAlgo took: ", zap.Duration("duration", end.Sub(start)))
+ userEmail, err := auth.GetEmailFromJwt(ctx)
+ if err == nil {
+ data := map[string]interface{}{
+ "traceSize": len(searchScanResponses),
+ "spansRenderLimit": params.SpansRenderLimit,
+ }
+ telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_LARGE_TRACE_OPENED, data, userEmail, true, false)
+ }
} else {
for i, item := range searchSpanResponses {
spanEvents := item.GetValues()
@@ -2194,9 +2174,6 @@ func (r *ClickHouseReader) GetFilteredSpansAggregates(ctx context.Context, query
if len(queryParams.HttpRoute) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpRoute, constants.HttpRoute, &query, args)
}
- if len(queryParams.HttpCode) > 0 {
- args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpCode, constants.HttpCode, &query, args)
- }
if len(queryParams.HttpHost) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpHost, constants.HttpHost, &query, args)
}
@@ -2206,9 +2183,6 @@ func (r *ClickHouseReader) GetFilteredSpansAggregates(ctx context.Context, query
if len(queryParams.HttpUrl) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.HttpUrl, constants.HttpUrl, &query, args)
}
- if len(queryParams.Component) > 0 {
- args = buildFilterArrayQuery(ctx, excludeMap, queryParams.Component, constants.Component, &query, args)
- }
if len(queryParams.Operation) > 0 {
args = buildFilterArrayQuery(ctx, excludeMap, queryParams.Operation, constants.OperationDB, &query, args)
}
@@ -4459,7 +4433,7 @@ func (r *ClickHouseReader) GetLogAttributeValues(ctx context.Context, req *v3.Fi
}
-func readRow(vars []interface{}, columnNames []string) ([]string, map[string]string, []map[string]string, v3.Point) {
+func readRow(vars []interface{}, columnNames []string, countOfNumberCols int) ([]string, map[string]string, []map[string]string, v3.Point) {
// Each row will have a value and a timestamp, and an optional list of label values
// example: {Timestamp: ..., Value: ...}
// The timestamp may also not present in some cases where the time series is reduced to single value
@@ -4503,7 +4477,7 @@ func readRow(vars []interface{}, columnNames []string) ([]string, map[string]str
case *time.Time:
point.Timestamp = v.UnixMilli()
case *float64, *float32:
- if _, ok := constants.ReservedColumnTargetAliases[colName]; ok {
+ if _, ok := constants.ReservedColumnTargetAliases[colName]; ok || countOfNumberCols == 1 {
point.Value = float64(reflect.ValueOf(v).Elem().Float())
} else {
groupBy = append(groupBy, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Float()))
@@ -4512,8 +4486,8 @@ func readRow(vars []interface{}, columnNames []string) ([]string, map[string]str
}
groupAttributes[colName] = fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Float())
}
- case *uint8, *uint64, *uint16, *uint32:
- if _, ok := constants.ReservedColumnTargetAliases[colName]; ok {
+ case *uint, *uint8, *uint64, *uint16, *uint32:
+ if _, ok := constants.ReservedColumnTargetAliases[colName]; ok || countOfNumberCols == 1 {
point.Value = float64(reflect.ValueOf(v).Elem().Uint())
} else {
groupBy = append(groupBy, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Uint()))
@@ -4522,8 +4496,8 @@ func readRow(vars []interface{}, columnNames []string) ([]string, map[string]str
}
groupAttributes[colName] = fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Uint())
}
- case *int8, *int16, *int32, *int64:
- if _, ok := constants.ReservedColumnTargetAliases[colName]; ok {
+ case *int, *int8, *int16, *int32, *int64:
+ if _, ok := constants.ReservedColumnTargetAliases[colName]; ok || countOfNumberCols == 1 {
point.Value = float64(reflect.ValueOf(v).Elem().Int())
} else {
groupBy = append(groupBy, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Int()))
@@ -4546,7 +4520,7 @@ func readRow(vars []interface{}, columnNames []string) ([]string, map[string]str
return groupBy, groupAttributes, groupAttributesArray, point
}
-func readRowsForTimeSeriesResult(rows driver.Rows, vars []interface{}, columnNames []string) ([]*v3.Series, error) {
+func readRowsForTimeSeriesResult(rows driver.Rows, vars []interface{}, columnNames []string, countOfNumberCols int) ([]*v3.Series, error) {
// when groupBy is applied, each combination of cartesian product
// of attribute values is a separate series. Each item in seriesToPoints
// represent a unique series where the key is sorted attribute values joined
@@ -4581,7 +4555,7 @@ func readRowsForTimeSeriesResult(rows driver.Rows, vars []interface{}, columnNam
if err := rows.Scan(vars...); err != nil {
return nil, err
}
- groupBy, groupAttributes, groupAttributesArray, metricPoint := readRow(vars, columnNames)
+ groupBy, groupAttributes, groupAttributesArray, metricPoint := readRow(vars, columnNames, countOfNumberCols)
// skip the point if the value is NaN or Inf
// are they ever useful enough to be returned?
if math.IsNaN(metricPoint.Value) || math.IsInf(metricPoint.Value, 0) {
@@ -4600,20 +4574,7 @@ func readRowsForTimeSeriesResult(rows driver.Rows, vars []interface{}, columnNam
var seriesList []*v3.Series
for _, key := range keys {
points := seriesToPoints[key]
- // find the grouping sets point for the series
- // this is the point with the zero timestamp
- // if there is no such point, then the series is not grouped
- // and we can skip this step
- var groupingSetsPoint *v3.Point
- for idx, point := range points {
- if point.Timestamp <= 0 {
- groupingSetsPoint = &point
- // remove the grouping sets point from the list of points
- points = append(points[:idx], points[idx+1:]...)
- break
- }
- }
- series := v3.Series{Labels: seriesToAttrs[key], Points: points, GroupingSetsPoint: groupingSetsPoint, LabelsArray: labelsArray[key]}
+ series := v3.Series{Labels: seriesToAttrs[key], Points: points, LabelsArray: labelsArray[key]}
seriesList = append(seriesList, &series)
}
return seriesList, getPersonalisedError(rows.Err())
@@ -4653,11 +4614,28 @@ func (r *ClickHouseReader) GetTimeSeriesResultV3(ctx context.Context, query stri
columnNames = rows.Columns()
vars = make([]interface{}, len(columnTypes))
)
+ var countOfNumberCols int
+
for i := range columnTypes {
vars[i] = reflect.New(columnTypes[i].ScanType()).Interface()
+ switch columnTypes[i].ScanType().Kind() {
+ case reflect.Float32,
+ reflect.Float64,
+ reflect.Uint,
+ reflect.Uint8,
+ reflect.Uint16,
+ reflect.Uint32,
+ reflect.Uint64,
+ reflect.Int,
+ reflect.Int8,
+ reflect.Int16,
+ reflect.Int32,
+ reflect.Int64:
+ countOfNumberCols++
+ }
}
- return readRowsForTimeSeriesResult(rows, vars, columnNames)
+ return readRowsForTimeSeriesResult(rows, vars, columnNames, countOfNumberCols)
}
// GetListResultV3 runs the query and returns list of rows
diff --git a/pkg/query-service/app/dashboards/model.go b/pkg/query-service/app/dashboards/model.go
index e7f48f8f87..64e4abcf3e 100644
--- a/pkg/query-service/app/dashboards/model.go
+++ b/pkg/query-service/app/dashboards/model.go
@@ -83,6 +83,22 @@ func InitDB(dataSourceName string) (*sqlx.DB, error) {
return nil, fmt.Errorf("error in creating notification_channles table: %s", err.Error())
}
+ tableSchema := `CREATE TABLE IF NOT EXISTS planned_maintenance (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ name TEXT NOT NULL,
+ description TEXT,
+ alert_ids TEXT,
+ schedule TEXT NOT NULL,
+ created_at datetime NOT NULL,
+ created_by TEXT NOT NULL,
+ updated_at datetime NOT NULL,
+ updated_by TEXT NOT NULL
+ );`
+ _, err = db.Exec(tableSchema)
+ if err != nil {
+ return nil, fmt.Errorf("error in creating planned_maintenance table: %s", err.Error())
+ }
+
table_schema = `CREATE TABLE IF NOT EXISTS ttl_status (
id INTEGER PRIMARY KEY AUTOINCREMENT,
transaction_id TEXT NOT NULL,
diff --git a/pkg/query-service/app/http_handler.go b/pkg/query-service/app/http_handler.go
index e3f7c5a165..6792e58008 100644
--- a/pkg/query-service/app/http_handler.go
+++ b/pkg/query-service/app/http_handler.go
@@ -16,7 +16,6 @@ import (
"text/template"
"time"
- "github.com/SigNoz/govaluate"
"github.com/gorilla/mux"
jsoniter "github.com/json-iterator/go"
_ "github.com/mattn/go-sqlite3"
@@ -38,6 +37,7 @@ import (
"go.signoz.io/signoz/pkg/query-service/cache"
"go.signoz.io/signoz/pkg/query-service/constants"
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
+ "go.signoz.io/signoz/pkg/query-service/postprocess"
"go.uber.org/multierr"
"go.uber.org/zap"
@@ -375,6 +375,12 @@ func (aH *APIHandler) RegisterRoutes(router *mux.Router, am *AuthMiddleware) {
router.HandleFunc("/api/v1/rules/{id}", am.EditAccess(aH.patchRule)).Methods(http.MethodPatch)
router.HandleFunc("/api/v1/testRule", am.EditAccess(aH.testRule)).Methods(http.MethodPost)
+ router.HandleFunc("/api/v1/downtime_schedules", am.OpenAccess(aH.listDowntimeSchedules)).Methods(http.MethodGet)
+ router.HandleFunc("/api/v1/downtime_schedules/{id}", am.OpenAccess(aH.getDowntimeSchedule)).Methods(http.MethodGet)
+ router.HandleFunc("/api/v1/downtime_schedules", am.OpenAccess(aH.createDowntimeSchedule)).Methods(http.MethodPost)
+ router.HandleFunc("/api/v1/downtime_schedules/{id}", am.OpenAccess(aH.editDowntimeSchedule)).Methods(http.MethodPut)
+ router.HandleFunc("/api/v1/downtime_schedules/{id}", am.OpenAccess(aH.deleteDowntimeSchedule)).Methods(http.MethodDelete)
+
router.HandleFunc("/api/v1/dashboards", am.ViewAccess(aH.getDashboards)).Methods(http.MethodGet)
router.HandleFunc("/api/v1/dashboards", am.EditAccess(aH.createDashboards)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/dashboards/grafana", am.EditAccess(aH.createDashboardsTransform)).Methods(http.MethodPost)
@@ -535,6 +541,102 @@ func (aH *APIHandler) populateTemporality(ctx context.Context, qp *v3.QueryRange
return nil
}
+func (aH *APIHandler) listDowntimeSchedules(w http.ResponseWriter, r *http.Request) {
+ schedules, err := aH.ruleManager.RuleDB().GetAllPlannedMaintenance(r.Context())
+ if err != nil {
+ RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
+ return
+ }
+
+ // The schedules are stored as JSON in the database, so we need to filter them here
+ // Since the number of schedules is expected to be small, this should be fine
+
+ if r.URL.Query().Get("active") != "" {
+ activeSchedules := make([]rules.PlannedMaintenance, 0)
+ active, _ := strconv.ParseBool(r.URL.Query().Get("active"))
+ for _, schedule := range schedules {
+ now := time.Now().In(time.FixedZone(schedule.Schedule.Timezone, 0))
+ if schedule.IsActive(now) == active {
+ activeSchedules = append(activeSchedules, schedule)
+ }
+ }
+ schedules = activeSchedules
+ }
+
+ if r.URL.Query().Get("recurring") != "" {
+ recurringSchedules := make([]rules.PlannedMaintenance, 0)
+ recurring, _ := strconv.ParseBool(r.URL.Query().Get("recurring"))
+ for _, schedule := range schedules {
+ if schedule.IsRecurring() == recurring {
+ recurringSchedules = append(recurringSchedules, schedule)
+ }
+ }
+ schedules = recurringSchedules
+ }
+
+ aH.Respond(w, schedules)
+}
+
+func (aH *APIHandler) getDowntimeSchedule(w http.ResponseWriter, r *http.Request) {
+ id := mux.Vars(r)["id"]
+ schedule, err := aH.ruleManager.RuleDB().GetPlannedMaintenanceByID(r.Context(), id)
+ if err != nil {
+ RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
+ return
+ }
+ aH.Respond(w, schedule)
+}
+
+func (aH *APIHandler) createDowntimeSchedule(w http.ResponseWriter, r *http.Request) {
+ var schedule rules.PlannedMaintenance
+ err := json.NewDecoder(r.Body).Decode(&schedule)
+ if err != nil {
+ RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
+ return
+ }
+ if err := schedule.Validate(); err != nil {
+ RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
+ return
+ }
+
+ _, err = aH.ruleManager.RuleDB().CreatePlannedMaintenance(r.Context(), schedule)
+ if err != nil {
+ RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
+ return
+ }
+ aH.Respond(w, nil)
+}
+
+func (aH *APIHandler) editDowntimeSchedule(w http.ResponseWriter, r *http.Request) {
+ id := mux.Vars(r)["id"]
+ var schedule rules.PlannedMaintenance
+ err := json.NewDecoder(r.Body).Decode(&schedule)
+ if err != nil {
+ RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
+ return
+ }
+ if err := schedule.Validate(); err != nil {
+ RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, nil)
+ return
+ }
+ _, err = aH.ruleManager.RuleDB().EditPlannedMaintenance(r.Context(), schedule, id)
+ if err != nil {
+ RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
+ return
+ }
+ aH.Respond(w, nil)
+}
+
+func (aH *APIHandler) deleteDowntimeSchedule(w http.ResponseWriter, r *http.Request) {
+ id := mux.Vars(r)["id"]
+ _, err := aH.ruleManager.RuleDB().DeletePlannedMaintenance(r.Context(), id)
+ if err != nil {
+ RespondError(w, &model.ApiError{Typ: model.ErrorInternal, Err: err}, nil)
+ return
+ }
+ aH.Respond(w, nil)
+}
+
func (aH *APIHandler) listRules(w http.ResponseWriter, r *http.Request) {
rules, err := aH.ruleManager.ListRuleStates(r.Context())
@@ -1321,13 +1423,13 @@ func (aH *APIHandler) getServicesList(w http.ResponseWriter, r *http.Request) {
func (aH *APIHandler) SearchTraces(w http.ResponseWriter, r *http.Request) {
- traceId, spanId, levelUpInt, levelDownInt, err := ParseSearchTracesParams(r)
+ params, err := ParseSearchTracesParams(r)
if err != nil {
RespondError(w, &model.ApiError{Typ: model.ErrorBadData, Err: err}, "Error reading params")
return
}
- result, err := aH.reader.SearchTraces(r.Context(), traceId, spanId, levelUpInt, levelDownInt, 0, nil)
+ result, err := aH.reader.SearchTraces(r.Context(), params, nil)
if aH.HandleError(w, err, http.StatusBadRequest) {
return
}
@@ -3160,13 +3262,13 @@ func (aH *APIHandler) queryRangeV3(ctx context.Context, queryRangeParams *v3.Que
return
}
- applyMetricLimit(result, queryRangeParams)
+ postprocess.ApplyMetricLimit(result, queryRangeParams)
sendQueryResultEvents(r, result, queryRangeParams)
// only adding applyFunctions instead of postProcess since experssion are
// are executed in clickhouse directly and we wanted to add support for timeshift
if queryRangeParams.CompositeQuery.QueryType == v3.QueryTypeBuilder {
- applyFunctions(result, queryRangeParams)
+ postprocess.ApplyFunctions(result, queryRangeParams)
}
resp := v3.QueryRangeResponse{
@@ -3418,7 +3520,7 @@ func (aH *APIHandler) queryRangeV4(ctx context.Context, queryRangeParams *v3.Que
if queryRangeParams.CompositeQuery.QueryType == v3.QueryTypeBuilder {
- result, err = postProcessResult(result, queryRangeParams)
+ result, err = postprocess.PostProcessResult(result, queryRangeParams)
}
if err != nil {
@@ -3453,105 +3555,3 @@ func (aH *APIHandler) QueryRangeV4(w http.ResponseWriter, r *http.Request) {
aH.queryRangeV4(r.Context(), queryRangeParams, w, r)
}
-
-// postProcessResult applies having clause, metric limit, reduce function to the result
-// This function is effective for metrics data source for now, but it can be extended to other data sources
-// if needed
-// Much of this work can be done in the ClickHouse query, but we decided to do it here because:
-// 1. Effective use of caching
-// 2. Easier to add new functions
-func postProcessResult(result []*v3.Result, queryRangeParams *v3.QueryRangeParamsV3) ([]*v3.Result, error) {
- // Having clause is not part of the clickhouse query, so we need to apply it here
- // It's not included in the query because it doesn't work nicely with caching
- // With this change, if you have a query with a having clause, and then you change the having clause
- // to something else, the query will still be cached.
- applyHavingClause(result, queryRangeParams)
- // We apply the metric limit here because it's not part of the clickhouse query
- // The limit in the context of the time series query is the number of time series
- // So for the limit to work, we need to know what series to keep and what to discard
- // For us to know that, we need to execute the query first, and then apply the limit
- // which we found expensive, because we are executing the query twice on the same data
- // So we decided to apply the limit here, after the query is executed
- // The function is named applyMetricLimit because it only applies to metrics data source
- // In traces and logs, the limit is achieved using subqueries
- applyMetricLimit(result, queryRangeParams)
- // Each series in the result produces N number of points, where N is (end - start) / step
- // For the panel type table, we need to show one point for each series in the row
- // We do that by applying a reduce function to each series
- applyReduceTo(result, queryRangeParams)
- // We apply the functions here it's easier to add new functions
- applyFunctions(result, queryRangeParams)
-
- // expressions are executed at query serivce so the value of time.now in the invdividual
- // queries will be different so for table panel we are making it same.
- if queryRangeParams.CompositeQuery.PanelType == v3.PanelTypeTable {
- tablePanelResultProcessor(result)
- }
-
- for _, query := range queryRangeParams.CompositeQuery.BuilderQueries {
- // The way we distinguish between a formula and a query is by checking if the expression
- // is the same as the query name
- // TODO(srikanthccv): Update the UI to send a flag to distinguish between a formula and a query
- if query.Expression != query.QueryName {
- expression, err := govaluate.NewEvaluableExpressionWithFunctions(query.Expression, evalFuncs())
- // This shouldn't happen here, because it should have been caught earlier in validation
- if err != nil {
- zap.L().Error("error in expression", zap.Error(err))
- return nil, err
- }
- formulaResult, err := processResults(result, expression)
- if err != nil {
- zap.L().Error("error in expression", zap.Error(err))
- return nil, err
- }
- formulaResult.QueryName = query.QueryName
- result = append(result, formulaResult)
- }
- }
- // we are done with the formula calculations, only send the results for enabled queries
- removeDisabledQueries := func(result []*v3.Result) []*v3.Result {
- var newResult []*v3.Result
- for _, res := range result {
- if queryRangeParams.CompositeQuery.BuilderQueries[res.QueryName].Disabled {
- continue
- }
- newResult = append(newResult, res)
- }
- return newResult
- }
- if queryRangeParams.CompositeQuery.QueryType == v3.QueryTypeBuilder {
- result = removeDisabledQueries(result)
- }
- return result, nil
-}
-
-// applyFunctions applies functions for each query in the composite query
-// The functions can be more than one, and they are applied in the order they are defined
-func applyFunctions(results []*v3.Result, queryRangeParams *v3.QueryRangeParamsV3) {
- for idx, result := range results {
- builderQueries := queryRangeParams.CompositeQuery.BuilderQueries
-
- if builderQueries != nil {
- functions := builderQueries[result.QueryName].Functions
-
- for _, function := range functions {
- results[idx] = queryBuilder.ApplyFunction(function, result)
- }
- }
- }
-}
-
-func tablePanelResultProcessor(results []*v3.Result) {
- var ts int64
- for ridx := range results {
- for sidx := range results[ridx].Series {
- for pidx := range results[ridx].Series[sidx].Points {
- if ts == 0 {
- ts = results[ridx].Series[sidx].Points[pidx].Timestamp
- } else {
- results[ridx].Series[sidx].Points[pidx].Timestamp = ts
- }
- }
- }
- }
-}
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/assets/dashboards/overview.json b/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/assets/dashboards/overview.json
new file mode 100644
index 0000000000..62099bdfb2
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/assets/dashboards/overview.json
@@ -0,0 +1,2078 @@
+{
+ "id": "elasticache-redis-overview",
+ "description": "Overview of ElastiCache CloudWatch metrics. Provides both host-level metrics (for example, CPU usage) and redis engine metrics",
+ "layout": [
+ {
+ "h": 5,
+ "i": "00d78996-1ba9-42d9-b22b-5818fc3bde4c",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 0
+ },
+ {
+ "h": 5,
+ "i": "96c23215-c494-4650-9dc3-ae20858ce1f7",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 0
+ },
+ {
+ "h": 5,
+ "i": "6a56afd1-6205-4afe-90fe-86befc3fb55e",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 5
+ },
+ {
+ "h": 5,
+ "i": "af269a1c-95a3-46b3-8d3b-322c194450e2",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 5
+ },
+ {
+ "h": 5,
+ "i": "f9b0f03a-8d78-4c26-a037-daae69650eb6",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 10
+ },
+ {
+ "h": 5,
+ "i": "18798789-b67a-4c90-8127-f6bb63f012b2",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 10
+ },
+ {
+ "h": 5,
+ "i": "b3cdeb88-6988-419c-9e94-4a6bccfdd467",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 15
+ },
+ {
+ "h": 5,
+ "i": "3604137c-12fe-4205-b7fc-f10d6143583b",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 15
+ },
+ {
+ "h": 5,
+ "i": "5e69ac87-580f-4dc2-becd-943296e5cd1d",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 20
+ },
+ {
+ "h": 5,
+ "i": "e5c9ccb6-31de-4b80-8f4c-220ea2e874d0",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 20
+ },
+ {
+ "h": 5,
+ "i": "dccdd9c3-3864-4aef-a98f-6fb0e30baf0c",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 25
+ },
+ {
+ "h": 5,
+ "i": "79723065-b871-4c79-83eb-b32f025c7642",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 25
+ },
+ {
+ "h": 5,
+ "i": "8eba8049-2af5-4998-b0e1-cbc2235f9b40",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 30
+ }
+ ],
+ "panelMap": {},
+ "tags": [
+ "aws",
+ "cache",
+ "redis"
+ ],
+ "title": "AWS ElastiCache Redis",
+ "uploadedGrafana": false,
+ "uuid": "5c4832b2-7035-436e-a1c2-cb1f88d238ed",
+ "variables": {
+ "50910278-a96b-4bae-a3b4-4c5b9e7cdefc": {
+ "allSelected": true,
+ "customValue": "",
+ "description": "",
+ "id": "50910278-a96b-4bae-a3b4-4c5b9e7cdefc",
+ "modificationUUID": "635019d8-0e8f-48bc-8912-240c995a5251",
+ "multiSelect": true,
+ "name": "cache_cluster_id",
+ "order": 0,
+ "queryValue": "SELECT JSONExtractString(labels, 'cache_cluster_id') as cache_cluster_id\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name like 'aws_elasticache_%'\nGROUP BY cache_cluster_id",
+ "selectedValue": [
+ ""
+ ],
+ "showALLOption": true,
+ "sort": "DISABLED",
+ "textboxValue": "",
+ "type": "QUERY"
+ }
+ },
+ "version": "v4",
+ "widgets": [
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "96c23215-c494-4650-9dc3-ae20858ce1f7",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_elasticache_engine_cpuutilization_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_elasticache_engine_cpuutilization_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "18ac6939",
+ "key": {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.cache_cluster_id}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{cache_cluster_id}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "f31a92eb-aefb-4468-b163-95c2d29e3eaa",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Engine CPU Utilization",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "b3cdeb88-6988-419c-9e94-4a6bccfdd467",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_elasticache_database_memory_usage_percentage_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_elasticache_database_memory_usage_percentage_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "6f82522a",
+ "key": {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.cache_cluster_id}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{cache_cluster_id}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "c863166f-7958-4f6c-a956-d5044c846973",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Database Memory Usage Percentage",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "18798789-b67a-4c90-8127-f6bb63f012b2",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_elasticache_database_capacity_usage_percentage_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_elasticache_database_capacity_usage_percentage_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "80632329",
+ "key": {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.cache_cluster_id}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "b659e4ed-5b6b-4ec8-911c-b906580b1ab5",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Database Capacity Usage Percentage",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "af269a1c-95a3-46b3-8d3b-322c194450e2",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_elasticache_cache_hits_sum--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_elasticache_cache_hits_sum",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "dd856067",
+ "key": {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.cache_cluster_id}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "",
+ "id": "cache_cluster_id------false",
+ "isColumn": false,
+ "key": "cache_cluster_id",
+ "type": ""
+ }
+ ],
+ "having": [],
+ "legend": "{{cache_cluster_id}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "avg",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "f2bc46b8-8d90-4d31-8e38-df61f7b58f55",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Cache Hit Rate",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "f9b0f03a-8d78-4c26-a037-daae69650eb6",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_elasticache_memory_fragmentation_ratio_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_elasticache_memory_fragmentation_ratio_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "76d19eac",
+ "key": {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.cache_cluster_id}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "avg",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "50b499c5-36dd-49e9-aae7-f1c225219434",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Memory Fragmentation Ratio",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "dccdd9c3-3864-4aef-a98f-6fb0e30baf0c",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_elasticache_swap_usage_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_elasticache_swap_usage_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "27530337",
+ "key": {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.cache_cluster_id}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{cache_cluster_id}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "221b1817-b059-439e-bfaf-39089520344d",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Swap Usage",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "3604137c-12fe-4205-b7fc-f10d6143583b",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_elasticache_freeable_memory_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_elasticache_freeable_memory_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "5f333785",
+ "key": {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.cache_cluster_id}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "cb158f83-72aa-4c36-bd26-9efc03d6ad15",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Freeable Memory",
+ "yAxisUnit": "decbytes"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "5e69ac87-580f-4dc2-becd-943296e5cd1d",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_elasticache_network_bytes_in_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_elasticache_network_bytes_in_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "5c18156a",
+ "key": {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.cache_cluster_id}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{cache_cluster_id}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "a0114277-cb86-40b2-b002-71b021f81e39",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Network Bytes In",
+ "yAxisUnit": "decbytes"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "e5c9ccb6-31de-4b80-8f4c-220ea2e874d0",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_elasticache_network_bytes_out_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_elasticache_network_bytes_out_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "6f0c2153",
+ "key": {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.cache_cluster_id}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{cache_cluster_id}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "51fd65b6-84f3-4ffd-81c3-5d581892cbad",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Network Bytes Out",
+ "yAxisUnit": "decbytes"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "6a56afd1-6205-4afe-90fe-86befc3fb55e",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_elasticache_curr_connections_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_elasticache_curr_connections_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "58582d67",
+ "key": {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.cache_cluster_id}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{cache_cluster_id}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "1ee12dc9-a2f0-4c19-90ec-269cbece6fee",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Current Connections",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "8eba8049-2af5-4998-b0e1-cbc2235f9b40",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_elasticache_replication_lag_maximum--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_elasticache_replication_lag_maximum",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "69a98f19",
+ "key": {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.cache_cluster_id}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{cache_cluster_id}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "95afdad6-29c3-4248-859f-bf142ad68f6a",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Replication Lag",
+ "yAxisUnit": "s"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "79723065-b871-4c79-83eb-b32f025c7642",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_elasticache_evictions_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_elasticache_evictions_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "ea75b479",
+ "key": {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.cache_cluster_id}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{cache_cluster_id}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "713cd286-0072-4c2b-b3cf-6631ca7c4958",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Evictions",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "00d78996-1ba9-42d9-b22b-5818fc3bde4c",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_elasticache_cpuutilization_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_elasticache_cpuutilization_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "028cb504",
+ "key": {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.cache_cluster_id}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "cache_cluster_id--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "cache_cluster_id",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{cache_cluster_id}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "794f841f-4281-4e02-8b2d-97641b356e60",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "CPU Utilization",
+ "yAxisUnit": "none"
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/config/collect-logs.md b/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/config/collect-logs.md
new file mode 100644
index 0000000000..af3daafb1f
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/config/collect-logs.md
@@ -0,0 +1,79 @@
+### Collect ElastiCache Logs
+
+Use the [log delivery](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/Log_Delivery.html) instructions to send redis logs to CloudWatch Logs
+
+#### Find the list of log group names for ElastiCache instance
+
+Collecting logs from an ElastiCache instance requires specifying the list of log group names. From the AWS CloudWatch console, find the log group(s) relevant to the integration.
+
+#### Create collector config file
+
+Save the following configuration for collecting ElastiCache logs in a file named `redis-logs-collection-config.yaml` and set the `region` key with the relevant value.
+
+```yaml
+receivers:
+ awscloudwatch:
+ region: us-east-1
+ logs:
+ poll_interval: 1m
+ groups:
+ named:
+ # replace the following name with your log group for elasticache logs
+ /aws/elasticache/:
+
+processors:
+ attributes/add_source:
+ actions:
+ - key: source
+ value: "elasticache_redis"
+ action: insert
+ batch:
+ send_batch_size: 10000
+ send_batch_max_size: 11000
+ timeout: 10s
+
+exporters:
+ # export to SigNoz cloud
+ otlp/redis-logs:
+ endpoint: "${env:OTLP_DESTINATION_ENDPOINT}"
+ tls:
+ insecure: false
+ headers:
+ "signoz-access-token": "${env:SIGNOZ_INGESTION_KEY}"
+
+ # export to local collector
+ otlp/local:
+ endpoint: "localhost:4317"
+ tls:
+ insecure: true
+
+service:
+ pipelines:
+ logs/redis:
+ receivers: [awscloudwatch]
+ processors: [attributes/add_source, batch]
+ exporters: [otlp/redis-logs]
+```
+
+#### Set Environment Variables
+
+Set the following environment variables in your otel-collector environment:
+
+```bash
+
+# region specific SigNoz cloud ingestion endpoint
+export OTLP_DESTINATION_ENDPOINT="ingest.us.signoz.cloud:443"
+
+# your SigNoz ingestion key
+export SIGNOZ_INGESTION_KEY="signoz-ingestion-key"
+
+```
+
+#### Use collector config file
+
+Make the collector config file available to your otel collector and use it by adding the following flag to the command for running your collector
+```bash
+--config redis-logs-collection-config.yaml
+```
+Note: the collector can use multiple config files, specified by multiple occurrences of the --config flag.
+
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/config/collect-metrics.md b/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/config/collect-metrics.md
new file mode 100644
index 0000000000..a7766c9746
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/config/collect-metrics.md
@@ -0,0 +1,237 @@
+### Collect ElastiCache Metrics
+
+The ElastiCache (redis) metrics collection is a two-step process.
+
+#### Set up the Prometheus CloudWatch exporter
+
+The [CloudWatch Exporter](https://github.com/prometheus/cloudwatch_exporter) is A Prometheus exporter for collecting CloudWatch metrics. This section describes the steps for downloading and configuring the Prometheus CloudWatch exporter.
+
+1. Download the Prometheus CloudWatch exporter JAR file, and run the following command:
+
+```sh
+curl -sLSO https://github.com/prometheus/cloudwatch_exporter/releases/download/v0.15.5/cloudwatch_exporter-0.15.5-jar-with-dependencies.jar
+```
+
+2. Configure the Prometheus exporter
+
+Save the following config for collecting AWS ElastiCache metrics in a file named `aws-elasticache-metrics.yaml` and set the `region` with the relevant value.
+
+```yaml
+---
+region: us-east-1
+metrics:
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: CPUUtilization
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: FreeableMemory
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: NetworkBytesIn
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Sum, Average]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: NetworkBytesOut
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Sum, Average]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: NetworkPacketsIn
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Sum, Average]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: NetworkPacketsOut
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Sum, Average]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: SwapUsage
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: BytesUsedForCache
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Sum, Maximum]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: CacheHits
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Sum]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: CacheMisses
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Sum]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: CacheHitRate
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: CurrConnections
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: CurrItems
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: CurrVolatileItems
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: ReplicationLag
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Maximum]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: ReplicationLag
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Maximum]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: SaveInProgress
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: TrafficManagementActive
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: DatabaseCapacityUsagePercentage
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: DatabaseMemoryUsagePercentage
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: EngineCPUUtilization
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: Evictions
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Sum, Average]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: GlobalDatastoreReplicationLag
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: MemoryFragmentationRatio
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/ElastiCache
+ aws_metric_name: MemoryFragmentationRatio
+ aws_dimensions: [CacheClusterId, CacheNodeId]
+ aws_statistics: [Sum, Average]
+```
+
+3. Run the following command
+
+```sh
+java -jar cloudwatch_exporter-0.15.5-jar-with-dependencies.jar 9106 aws-elasticache-metrics.yaml
+```
+
+#### Set up the OTEL Collector
+
+Save the following config for collecting Redis native metrics in a file named `redis-metrics-collection-config.yaml`
+
+```yaml
+receivers:
+ redis:
+ # The hostname and port of the Redis instance, separated by a colon.
+ endpoint: ${env:REDIS_ENDPOINT}
+ # The frequency at which to collect metrics from the Redis instance.
+ collection_interval: 60s
+ # The password used to access the Redis instance; must match the password specified in the requirepass server configuration option.
+ password: ${env:REDIS_PASSWORD}
+ # # Defines the network to use for connecting to the server. Valid Values are `tcp` or `Unix`
+ # transport: tcp
+ # tls:
+ # insecure: false
+ # ca_file: /etc/ssl/certs/ca-certificates.crt
+ # cert_file: /etc/ssl/certs/redis.crt
+ # key_file: /etc/ssl/certs/redis.key
+ metrics:
+ redis.maxmemory:
+ enabled: true
+ redis.cmd.latency:
+ enabled: true
+
+ prometheus:
+ config:
+ scrape_configs:
+ - job_name: 'aws-cloudwatch-metrics'
+ scrape_timeout: 120s
+ scrape_interval: 120s
+ static_configs:
+ - targets: ['0.0.0.0:9106']
+
+exporters:
+ # export to local collector
+ otlp/local:
+ endpoint: "localhost:4317"
+ tls:
+ insecure: true
+ # export to SigNoz cloud
+ otlp/signoz:
+ endpoint: "${env:OTLP_DESTINATION_ENDPOINT}"
+ tls:
+ insecure: false
+ headers:
+ "signoz-access-token": "${env:SIGNOZ_INGESTION_KEY}"
+
+service:
+ pipelines:
+ metrics/redis:
+ receivers: [redis, prometheus]
+ processors: []
+ exporters: [otlp/signoz]
+```
+
+#### Set Environment Variables
+
+Set the following environment variables in your otel-collector environment:
+
+```bash
+
+# The accessible endpoint where redis server is running.
+# The hostname and port of the Redis instance, separated by a colon.
+export REDIS_ENDPOINT=""
+
+# The password to use for accessing redis instance
+export REDIS_PASSWORD=""
+
+# region specific SigNoz cloud ingestion endpoint
+export OTLP_DESTINATION_ENDPOINT="ingest.us.signoz.cloud:443"
+
+# your SigNoz ingestion key
+export SIGNOZ_INGESTION_KEY="signoz-ingestion-key"
+
+```
+
+#### Use collector config file
+
+Make the collector config file available to your otel collector and use it by adding the following flag to the command for running your collector
+```bash
+--config redis-metrics-collection-config.yaml
+```
+Note: the collector can use multiple config files, specified by multiple occurrences of the --config flag.
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/config/prerequisites.md b/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/config/prerequisites.md
new file mode 100644
index 0000000000..cdc541c78b
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/config/prerequisites.md
@@ -0,0 +1,24 @@
+## Before You Begin
+
+To configure metrics and logs collection for an AWS ElastiCache server, you need the following.
+
+
+- **Ensure Credentials and permissions are set correctly**
+ The components used for this integration relies on AWS SDKs, which offer a variety of ways to provide credentials, including the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables.
+ The following IAM permissions are required:
+ - `cloudwatch:ListMetrics`
+ - `cloudwatch:GetMetricStatistics`
+ - `cloudwatch:GetMetricData`
+ - `tag:GetResources` (if aws_tag_select feature is used)
+ - `logs:DescribeLogGroups`
+ - `logs:FilterLogEvents`
+
+- **Ensure Java Runtime Environment (JRE), version 11 or newer**
+ The CloudWatch Exporter used to collect the metrics requires a Java runtime environment version 11 or newer. This is not required if you can run the docker container.
+
+- **Ensure that an OTEL collector is running in your deployment environment**
+ If needed, please [install an OTEL Collector](https://signoz.io/docs/tutorial/opentelemetry-binary-usage-in-virtual-machine/) If already installed, ensure that the collector version is v0.88.0 or newer. Also, ensure that you can provide config files to the collector and that you can set environment variables and command line flags used for running it.
+
+
+- **Ensure that the OTEL collector can access the Redis server**
+ To collect Redis native metrics, the collector must be able to access the Redis server as a client. This step is optional.
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/icon.svg b/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/icon.svg
new file mode 100644
index 0000000000..293907995b
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/icon.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/integration.json b/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/integration.json
new file mode 100644
index 0000000000..4ece40dec0
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/integration.json
@@ -0,0 +1,522 @@
+{
+ "id": "aws_elasticache_redis",
+ "title": "AWS ElastiCache (redis)",
+ "description": "Monitor AWS ElastiCache with metrics and logs",
+ "author": {
+ "name": "SigNoz",
+ "email": "integrations@signoz.io",
+ "homepage": "https://signoz.io"
+ },
+ "icon": "file://icon.svg",
+ "categories": [
+ "Database"
+ ],
+ "overview": "file://overview.md",
+ "configuration": [
+ {
+ "title": "Prerequisites",
+ "instructions": "file://config/prerequisites.md"
+ },
+ {
+ "title": "Collect Metrics",
+ "instructions": "file://config/collect-metrics.md"
+ },
+ {
+ "title": "Collect Logs",
+ "instructions": "file://config/collect-logs.md"
+ }
+ ],
+ "assets": {
+ "logs": {
+ "pipelines": []
+ },
+ "dashboards": [
+ "file://assets/dashboards/overview.json"
+ ],
+ "alerts": []
+ },
+ "connection_tests": {
+ "logs": {
+ "attribute_key": "source",
+ "attribute_value": "elasticache_redis"
+ }
+ },
+ "data_collected": {
+ "logs": [
+ {
+ "name": "Timestamp",
+ "path": "timestamp",
+ "type": "timestamp"
+ },
+ {
+ "name": "Body",
+ "path": "body",
+ "type": "string"
+ }
+ ],
+ "metrics": [
+ {
+ "name": "aws_elasticache_bytes_used_for_cache_maximum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache BytesUsedForCache Dimensions: [CacheClusterId, CacheNodeId] Statistic: Maximum Unit: Bytes"
+ },
+ {
+ "name": "aws_elasticache_bytes_used_for_cache_sum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache BytesUsedForCache Dimensions: [CacheClusterId, CacheNodeId] Statistic: Sum Unit: Bytes"
+ },
+ {
+ "name": "aws_elasticache_cache_hits_sum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache CacheHits Dimensions: [CacheClusterId, CacheNodeId] Statistic: Sum Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_cache_misses_sum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache CacheMisses Dimensions: [CacheClusterId, CacheNodeId] Statistic: Sum Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_cpuutilization_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache CPUUtilization Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: Percent"
+ },
+ {
+ "name": "aws_elasticache_cpuutilization_maximum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache CPUUtilization Dimensions: [CacheClusterId, CacheNodeId] Statistic: Maximum Unit: Percent"
+ },
+ {
+ "name": "aws_elasticache_curr_connections_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache CurrConnections Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_curr_connections_maximum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache CurrConnections Dimensions: [CacheClusterId, CacheNodeId] Statistic: Maximum Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_curr_items_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache CurrItems Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_curr_items_maximum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache CurrItems Dimensions: [CacheClusterId, CacheNodeId] Statistic: Maximum Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_curr_volatile_items_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache CurrVolatileItems Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_curr_volatile_items_maximum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache CurrVolatileItems Dimensions: [CacheClusterId, CacheNodeId] Statistic: Maximum Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_database_capacity_usage_percentage_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache DatabaseCapacityUsagePercentage Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: Percent"
+ },
+ {
+ "name": "aws_elasticache_database_capacity_usage_percentage_maximum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache DatabaseCapacityUsagePercentage Dimensions: [CacheClusterId, CacheNodeId] Statistic: Maximum Unit: Percent"
+ },
+ {
+ "name": "aws_elasticache_database_memory_usage_percentage_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache DatabaseMemoryUsagePercentage Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: Percent"
+ },
+ {
+ "name": "aws_elasticache_database_memory_usage_percentage_maximum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache DatabaseMemoryUsagePercentage Dimensions: [CacheClusterId, CacheNodeId] Statistic: Maximum Unit: Percent"
+ },
+ {
+ "name": "aws_elasticache_engine_cpuutilization_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache EngineCPUUtilization Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: Percent"
+ },
+ {
+ "name": "aws_elasticache_engine_cpuutilization_maximum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache EngineCPUUtilization Dimensions: [CacheClusterId, CacheNodeId] Statistic: Maximum Unit: Percent"
+ },
+ {
+ "name": "aws_elasticache_evictions_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache Evictions Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_evictions_sum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache Evictions Dimensions: [CacheClusterId, CacheNodeId] Statistic: Sum Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_freeable_memory_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache FreeableMemory Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_elasticache_freeable_memory_maximum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache FreeableMemory Dimensions: [CacheClusterId, CacheNodeId] Statistic: Maximum Unit: Bytes"
+ },
+ {
+ "name": "aws_elasticache_memory_fragmentation_ratio_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache MemoryFragmentationRatio Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: None"
+ },
+ {
+ "name": "aws_elasticache_memory_fragmentation_ratio_maximum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache MemoryFragmentationRatio Dimensions: [CacheClusterId, CacheNodeId] Statistic: Maximum Unit: None"
+ },
+ {
+ "name": "aws_elasticache_memory_fragmentation_ratio_sum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache MemoryFragmentationRatio Dimensions: [CacheClusterId, CacheNodeId] Statistic: Sum Unit: None"
+ },
+ {
+ "name": "aws_elasticache_network_bytes_in_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache NetworkBytesIn Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_elasticache_network_bytes_in_sum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache NetworkBytesIn Dimensions: [CacheClusterId, CacheNodeId] Statistic: Sum Unit: Bytes"
+ },
+ {
+ "name": "aws_elasticache_network_bytes_out_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache NetworkBytesOut Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_elasticache_network_bytes_out_sum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache NetworkBytesOut Dimensions: [CacheClusterId, CacheNodeId] Statistic: Sum Unit: Bytes"
+ },
+ {
+ "name": "aws_elasticache_network_packets_in_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache NetworkPacketsIn Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_network_packets_in_sum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache NetworkPacketsIn Dimensions: [CacheClusterId, CacheNodeId] Statistic: Sum Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_network_packets_out_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache NetworkPacketsOut Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_network_packets_out_sum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache NetworkPacketsOut Dimensions: [CacheClusterId, CacheNodeId] Statistic: Sum Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_replication_lag_maximum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache ReplicationLag Dimensions: [CacheClusterId, CacheNodeId] Statistic: Maximum Unit: Seconds"
+ },
+ {
+ "name": "aws_elasticache_save_in_progress_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache SaveInProgress Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_save_in_progress_maximum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache SaveInProgress Dimensions: [CacheClusterId, CacheNodeId] Statistic: Maximum Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_save_in_progress_minimum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache SaveInProgress Dimensions: [CacheClusterId, CacheNodeId] Statistic: Minimum Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_save_in_progress_sample_count",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache SaveInProgress Dimensions: [CacheClusterId, CacheNodeId] Statistic: SampleCount Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_save_in_progress_sum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache SaveInProgress Dimensions: [CacheClusterId, CacheNodeId] Statistic: Sum Unit: Count"
+ },
+ {
+ "name": "aws_elasticache_swap_usage_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache SwapUsage Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_elasticache_swap_usage_maximum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache SwapUsage Dimensions: [CacheClusterId, CacheNodeId] Statistic: Maximum Unit: Bytes"
+ },
+ {
+ "name": "aws_elasticache_traffic_management_active_average",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache TrafficManagementActive Dimensions: [CacheClusterId, CacheNodeId] Statistic: Average Unit: None"
+ },
+ {
+ "name": "aws_elasticache_traffic_management_active_maximum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache TrafficManagementActive Dimensions: [CacheClusterId, CacheNodeId] Statistic: Maximum Unit: None"
+ },
+ {
+ "name": "aws_elasticache_traffic_management_active_minimum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache TrafficManagementActive Dimensions: [CacheClusterId, CacheNodeId] Statistic: Minimum Unit: None"
+ },
+ {
+ "name": "aws_elasticache_traffic_management_active_sample_count",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache TrafficManagementActive Dimensions: [CacheClusterId, CacheNodeId] Statistic: SampleCount Unit: None"
+ },
+ {
+ "name": "aws_elasticache_traffic_management_active_sum",
+ "type": "Gauge",
+ "unit": "",
+ "description": "CloudWatch metric AWS/ElastiCache TrafficManagementActive Dimensions: [CacheClusterId, CacheNodeId] Statistic: Sum Unit: None"
+ },
+ {
+ "name": "redis_commands_processed",
+ "type": "Sum",
+ "unit": "number",
+ "description": "Total number of commands processed by the server"
+ },
+ {
+ "name": "redis_cpu_time",
+ "type": "Sum",
+ "unit": "s",
+ "description": "System CPU consumed by the Redis server in seconds since server start"
+ },
+ {
+ "name": "redis_keys_expired",
+ "type": "Sum",
+ "unit": "number",
+ "description": "Total number of key expiration events"
+ },
+ {
+ "name": "redis_db_expires",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "Number of keyspace keys with an expiration"
+ },
+ {
+ "name": "redis_commands",
+ "type": "Gauge",
+ "unit": "ops/s",
+ "description": "Number of commands processed per second"
+ },
+ {
+ "name": "redis_replication_offset",
+ "type": "Gauge",
+ "unit": "Bytes",
+ "description": "The server's current replication offset"
+ },
+ {
+ "name": "redis_net_input",
+ "type": "Sum",
+ "unit": "Bytes",
+ "description": "The total number of bytes read from the network"
+ },
+ {
+ "name": "redis_clients_connected",
+ "type": "Sum",
+ "unit": "number",
+ "description": "Number of client connections (excluding connections from replicas)"
+ },
+ {
+ "name": "redis_keys_evicted",
+ "type": "Sum",
+ "unit": "number",
+ "description": "Number of evicted keys due to maxmemory limit"
+ },
+ {
+ "name": "redis_maxmemory",
+ "type": "Gauge",
+ "unit": "Bytes",
+ "description": "The value of the maxmemory configuration directive"
+ },
+ {
+ "name": "redis_clients_max_input_buffer",
+ "type": "Gauge",
+ "unit": "Bytes",
+ "description": "Biggest input buffer among current client connections"
+ },
+ {
+ "name": "redis_cmd_latency",
+ "type": "Gauge",
+ "unit": "s",
+ "description": "Command execution latency"
+ },
+ {
+ "name": "redis_memory_lua",
+ "type": "Gauge",
+ "unit": "Bytes",
+ "description": "Number of bytes used by the Lua engine"
+ },
+ {
+ "name": "redis_replication_backlog_first_byte_offset",
+ "type": "Gauge",
+ "unit": "Bytes",
+ "description": "The master offset of the replication backlog buffer"
+ },
+ {
+ "name": "redis_keyspace_hits",
+ "type": "Sum",
+ "unit": "number",
+ "description": "Number of successful lookup of keys in the main dictionary"
+ },
+ {
+ "name": "redis_clients_blocked",
+ "type": "Sum",
+ "unit": "number",
+ "description": "Number of clients pending on a blocking call"
+ },
+ {
+ "name": "redis_connections_rejected",
+ "type": "Sum",
+ "unit": "number",
+ "description": "Number of connections rejected because of maxclients limit"
+ },
+ {
+ "name": "redis_latest_fork",
+ "type": "Gauge",
+ "unit": "us",
+ "description": "Duration of the latest fork operation in microseconds"
+ },
+ {
+ "name": "redis_clients_max_output_buffer",
+ "type": "Gauge",
+ "unit": "Bytes",
+ "description": "Longest output list among current client connections"
+ },
+ {
+ "name": "redis_slaves_connected",
+ "type": "Sum",
+ "unit": "number",
+ "description": "Number of connected replicas"
+ },
+ {
+ "name": "redis_db_keys",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "Number of keyspace keys"
+ },
+ {
+ "name": "redis_keyspace_misses",
+ "type": "Sum",
+ "unit": "number",
+ "description": "Number of failed lookup of keys in the main dictionary"
+ },
+ {
+ "name": "redis_uptime",
+ "type": "Sum",
+ "unit": "s",
+ "description": "Number of seconds since Redis server start"
+ },
+ {
+ "name": "redis_memory_used",
+ "type": "Gauge",
+ "unit": "Bytes",
+ "description": "Total number of bytes allocated by Redis using its allocator"
+ },
+ {
+ "name": "redis_net_output",
+ "type": "Sum",
+ "unit": "Bytes",
+ "description": "The total number of bytes written to the network"
+ },
+ {
+ "name": "redis_connections_received",
+ "type": "Sum",
+ "unit": "number",
+ "description": "Total number of connections accepted by the server"
+ },
+ {
+ "name": "redis_rdb_changes_since_last_save",
+ "type": "Sum",
+ "unit": "number",
+ "description": "Number of changes since the last dump"
+ },
+ {
+ "name": "redis_memory_rss",
+ "type": "Gauge",
+ "unit": "Bytes",
+ "description": "Number of bytes that Redis allocated as seen by the operating system"
+ },
+ {
+ "name": "redis_db_avg_ttl",
+ "type": "Gauge",
+ "unit": "ms",
+ "description": "Average keyspace keys TTL"
+ },
+ {
+ "name": "redis_memory_peak",
+ "type": "Gauge",
+ "unit": "Bytes",
+ "description": "Peak memory consumed by Redis (in bytes)"
+ },
+ {
+ "name": "redis_memory_fragmentation_ratio",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "Ratio between used_memory_rss and used_memory"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/overview.md b/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/overview.md
new file mode 100644
index 0000000000..a92943c39d
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_elasticache/overview.md
@@ -0,0 +1,5 @@
+### Monitor AWS ElastiCache (redis) with SigNoz
+
+Collect key AWS ElastiCache (redis) metrics and view them with an out of the box dashboard.
+
+Collect and parse AWS ElastiCache (redis) logs to populate timestamp, severity, and other log attributes for better querying and aggregation.
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/assets/dashboards/db_metrics.json b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/assets/dashboards/db_metrics.json
new file mode 100644
index 0000000000..9473a95a2f
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/assets/dashboards/db_metrics.json
@@ -0,0 +1,2935 @@
+{
+ "id": "aws_rds_mysql_db_metrics",
+ "description": "",
+ "layout": [
+ {
+ "h": 1,
+ "i": "a1da815a-c8b8-4e86-8630-a3265e3be002",
+ "maxH": 1,
+ "minH": 1,
+ "minW": 12,
+ "moved": false,
+ "static": false,
+ "w": 12,
+ "x": 0,
+ "y": 0
+ },
+ {
+ "h": 6,
+ "i": "121f2894-dd86-423a-8bb8-93f853aad93e",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 1
+ },
+ {
+ "h": 6,
+ "i": "0dc8699d-35d7-4c73-b25e-ce2c05e1574b",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 1
+ },
+ {
+ "h": 6,
+ "i": "19da4480-77f3-4999-9cd5-f76c02cb4e8d",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 7
+ },
+ {
+ "h": 6,
+ "i": "864ac52b-87aa-423a-aafb-975207baa3af",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 7
+ },
+ {
+ "h": 6,
+ "i": "11d5c39c-d780-4752-a868-a88d95e2a264",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 13
+ },
+ {
+ "h": 6,
+ "i": "c65eccc5-568b-4da3-8dee-90cf46cfbdcb",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 13
+ },
+ {
+ "h": 6,
+ "i": "b0ccb2fd-865a-422c-821f-4c8e4058e575",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 19
+ },
+ {
+ "h": 6,
+ "i": "942b5e3c-733a-454a-b7f7-b4256696483a",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 19
+ },
+ {
+ "h": 6,
+ "i": "ee89777a-111f-4c4e-bef5-3348b6a07b45",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 25
+ },
+ {
+ "h": 6,
+ "i": "b1e49f1a-8f97-4174-9cc7-0e4e4d2309f6",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 25
+ },
+ {
+ "h": 1,
+ "i": "52d4e290-ebe9-4e17-9e0d-57c4537996a2",
+ "maxH": 1,
+ "minH": 1,
+ "minW": 12,
+ "moved": false,
+ "static": false,
+ "w": 12,
+ "x": 0,
+ "y": 31
+ },
+ {
+ "h": 6,
+ "i": "26d0b9f5-9dee-49ff-a8b5-baad92bd85ee",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 32
+ },
+ {
+ "h": 6,
+ "i": "2c1421c3-6d09-43d3-b5fc-bea817595786",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 32
+ },
+ {
+ "h": 1,
+ "i": "2b3c134c-ef8e-40a3-be5b-1c2b31f5f774",
+ "maxH": 1,
+ "minH": 1,
+ "minW": 12,
+ "moved": false,
+ "static": false,
+ "w": 12,
+ "x": 0,
+ "y": 38
+ },
+ {
+ "h": 5,
+ "i": "9f188ac9-7b6c-4f23-85df-442c90fb1e98",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 39
+ },
+ {
+ "h": 5,
+ "i": "bc6a7150-bb0b-4fb5-b132-217f20b4cd06",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 39
+ },
+ {
+ "h": 5,
+ "i": "b99182d7-efd4-43a5-bd61-3a35d9f88a0e",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 44
+ },
+ {
+ "h": 5,
+ "i": "18f8b51f-074c-45e3-8f25-6e70cb8ad222",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 44
+ }
+ ],
+ "panelMap": {
+ "2b3c134c-ef8e-40a3-be5b-1c2b31f5f774": {
+ "collapsed": false,
+ "widgets": [
+ {
+ "h": 5,
+ "i": "9f188ac9-7b6c-4f23-85df-442c90fb1e98",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 23
+ },
+ {
+ "h": 5,
+ "i": "bc6a7150-bb0b-4fb5-b132-217f20b4cd06",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 23
+ },
+ {
+ "h": 5,
+ "i": "b99182d7-efd4-43a5-bd61-3a35d9f88a0e",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 28
+ },
+ {
+ "h": 5,
+ "i": "18f8b51f-074c-45e3-8f25-6e70cb8ad222",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 28
+ }
+ ]
+ },
+ "52d4e290-ebe9-4e17-9e0d-57c4537996a2": {
+ "collapsed": false,
+ "widgets": [
+ {
+ "h": 6,
+ "i": "26d0b9f5-9dee-49ff-a8b5-baad92bd85ee",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 43
+ },
+ {
+ "h": 5,
+ "i": "18f8b51f-074c-45e3-8f25-6e70cb8ad222",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 43
+ },
+ {
+ "h": 6,
+ "i": "2c1421c3-6d09-43d3-b5fc-bea817595786",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 48
+ }
+ ]
+ },
+ "a1da815a-c8b8-4e86-8630-a3265e3be002": {
+ "collapsed": false,
+ "widgets": [
+ {
+ "h": 6,
+ "i": "942b5e3c-733a-454a-b7f7-b4256696483a",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 0
+ },
+ {
+ "h": 6,
+ "i": "19da4480-77f3-4999-9cd5-f76c02cb4e8d",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 6
+ },
+ {
+ "h": 6,
+ "i": "b0ccb2fd-865a-422c-821f-4c8e4058e575",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 12
+ },
+ {
+ "h": 6,
+ "i": "0dc8699d-35d7-4c73-b25e-ce2c05e1574b",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 18
+ },
+ {
+ "h": 6,
+ "i": "ee89777a-111f-4c4e-bef5-3348b6a07b45",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 24
+ },
+ {
+ "h": 6,
+ "i": "c65eccc5-568b-4da3-8dee-90cf46cfbdcb",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 30
+ },
+ {
+ "h": 6,
+ "i": "121f2894-dd86-423a-8bb8-93f853aad93e",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 36
+ },
+ {
+ "h": 6,
+ "i": "b1e49f1a-8f97-4174-9cc7-0e4e4d2309f6",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 42
+ },
+ {
+ "h": 6,
+ "i": "864ac52b-87aa-423a-aafb-975207baa3af",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 48
+ },
+ {
+ "h": 6,
+ "i": "11d5c39c-d780-4752-a868-a88d95e2a264",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 54
+ }
+ ]
+ }
+ },
+ "tags": [
+ "mysql"
+ ],
+ "title": "MySQL",
+ "uploadedGrafana": false,
+ "variables": {
+ "31d3f13b-27d5-4291-9fb3-d5d5708a72f3": {
+ "allSelected": false,
+ "customValue": "",
+ "description": "",
+ "id": "31d3f13b-27d5-4291-9fb3-d5d5708a72f3",
+ "modificationUUID": "e4a9edf1-acd0-48b7-8a35-1b4bb668408d",
+ "multiSelect": false,
+ "name": "mysql_instance_endpoint",
+ "order": 0,
+ "queryValue": "SELECT JSONExtractString(labels, 'mysql_instance_endpoint') as mysql_instance_endpoint\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'mysql_uptime'\nGROUP BY mysql_instance_endpoint",
+ "selectedValue": "",
+ "showALLOption": false,
+ "sort": "ASC",
+ "textboxValue": "",
+ "type": "QUERY"
+ }
+ },
+ "version": "v4",
+ "widgets": [
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "9f188ac9-7b6c-4f23-85df-442c90fb1e98",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_buffer_pool_usage--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_buffer_pool_usage",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "d0ece7c5",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "status--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "status",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{status}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "avg",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "41139bf9-846d-4aff-b31b-43c8d42f6aea",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Buffer pool usage by status",
+ "yAxisUnit": "bytes"
+ },
+ {
+ "description": "",
+ "id": "2b3c134c-ef8e-40a3-be5b-1c2b31f5f774",
+ "panelTypes": "row",
+ "title": "Buffer pool"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "b99182d7-efd4-43a5-bd61-3a35d9f88a0e",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_buffer_pool_pages--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_buffer_pool_pages",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "5a3714e3",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "kind--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "kind",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{kind}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "0fe54f66-5f01-4468-9681-b0fd52ea7d01",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Buffer pool pages by kind",
+ "yAxisUnit": "short"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "bc6a7150-bb0b-4fb5-b132-217f20b4cd06",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_buffer_pool_data_pages--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_buffer_pool_data_pages",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "fb2c8b1f",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "status--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "status",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{status}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "ce9c23bd-8a9d-4bce-af85-9696360d4431",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Data pages by status",
+ "yAxisUnit": "short"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "18f8b51f-074c-45e3-8f25-6e70cb8ad222",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_buffer_pool_page_flushes--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_buffer_pool_page_flushes",
+ "type": "Sum"
+ },
+ "aggregateOperator": "increase",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "aaed0865",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [],
+ "having": [],
+ "legend": "Count",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "increase"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "0a94bead-a3e4-4ae8-a500-77d50a4c6b17",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Total buffer pool page flushes",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "id": "52d4e290-ebe9-4e17-9e0d-57c4537996a2",
+ "panelTypes": "row",
+ "title": "Table"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "ca688417-3ded-4482-aa4d-73dd9ce4e715",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "table",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_table_io_wait_count--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_table_io_wait_count",
+ "type": "Sum"
+ },
+ "aggregateOperator": "increase",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "416ad837",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "table--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "table",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "Count",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "rate"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "6608d3ce-0058-44ed-9f76-3474ab0765aa",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "count of I/O wait events",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "26d0b9f5-9dee-49ff-a8b5-baad92bd85ee",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "table",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_table_io_wait_count--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_table_io_wait_count",
+ "type": "Sum"
+ },
+ "aggregateOperator": "increase",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "3773e4f8",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "table--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "table",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "count",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "increase"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "f02c5c6d-d5c0-4fb5-9d9d-5e8037a7824e",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "count of table I/O wait events",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "2c1421c3-6d09-43d3-b5fc-bea817595786",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "table",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_table_io_wait_count--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_table_io_wait_count",
+ "type": "Sum"
+ },
+ "aggregateOperator": "increase",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "3773e4f8",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "table--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "table",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "count",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "increase"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "f02c5c6d-d5c0-4fb5-9d9d-5e8037a7824e",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "count of table I/O wait events",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "11d5c39c-d780-4752-a868-a88d95e2a264",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_handlers--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_handlers",
+ "type": "Sum"
+ },
+ "aggregateOperator": "increase",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "ac5632dc",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "kind--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "kind",
+ "type": "tag"
+ }
+ ],
+ "having": [
+ {
+ "columnName": "SUM(mysql_handlers)",
+ "op": ">",
+ "value": 0
+ }
+ ],
+ "legend": "{{kind}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "increase"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "d30af321-a7f6-49da-81a9-ba9577606dfd",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Count by handlers",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "864ac52b-87aa-423a-aafb-975207baa3af",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_locks--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_locks",
+ "type": "Sum"
+ },
+ "aggregateOperator": "increase",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "e2692b23",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "kind--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "kind",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{kind}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "increase"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "71dbfc3f-10e3-4a23-b5c8-dd2c15ae800a",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "MySQL locks",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "b1e49f1a-8f97-4174-9cc7-0e4e4d2309f6",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "table",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_log_operations--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_log_operations",
+ "type": "Sum"
+ },
+ "aggregateOperator": "increase",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "b2ce5aae",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "operation--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "operation",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "count",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "increase"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "c31ca2ae-8a6e-4293-a8e1-c544c093dcfd",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "InnoDB log operations",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "121f2894-dd86-423a-8bb8-93f853aad93e",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_connection_count--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_connection_count",
+ "type": "Sum"
+ },
+ "aggregateOperator": "increase",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "7ba56364",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [],
+ "having": [],
+ "legend": "Connection count",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "increase"
+ },
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_connection_errors--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_connection_errors",
+ "type": "Sum"
+ },
+ "aggregateOperator": "increase",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "B",
+ "filters": {
+ "items": [
+ {
+ "id": "ed85e243",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "error--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "error",
+ "type": "tag"
+ }
+ ],
+ "having": [
+ {
+ "columnName": "SUM(mysql_connection_errors)",
+ "op": ">",
+ "value": 0
+ }
+ ],
+ "legend": "Error count: {{error}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "B",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "increase"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "bde94864-1375-4617-9e62-2767981b57fc",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Connection/Errors",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "c65eccc5-568b-4da3-8dee-90cf46cfbdcb",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_opened_resources--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_opened_resources",
+ "type": "Sum"
+ },
+ "aggregateOperator": "increase",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "517c903b",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "kind--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "kind",
+ "type": "tag"
+ }
+ ],
+ "having": [
+ {
+ "columnName": "SUM(mysql_opened_resources)",
+ "op": ">",
+ "value": 0
+ }
+ ],
+ "legend": "{{kind}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "increase"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "62325340-e5db-4717-a55b-a0ff2dff77be",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Open resources count",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "ee89777a-111f-4c4e-bef5-3348b6a07b45",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "table",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_operations--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_operations",
+ "type": "Sum"
+ },
+ "aggregateOperator": "increase",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "99fe0131",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "operation--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "operation",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "increase"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "2825eb5d-e03e-42d7-980b-d2e4ded149a4",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Count of operations",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "0dc8699d-35d7-4c73-b25e-ce2c05e1574b",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_row_locks--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_row_locks",
+ "type": "Sum"
+ },
+ "aggregateOperator": "increase",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "7ed07e24",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "kind--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "kind",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{kind}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "increase"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "8598c0ff-d274-445f-8a3c-53c02595e0ff",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Row locks",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "b0ccb2fd-865a-422c-821f-4c8e4058e575",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "table",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_threads--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_threads",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "93e5a9ee",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "kind--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "kind",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "count",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "5970ac20-a757-4d1b-80da-b6ec01fbe553",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Thread type count",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "19da4480-77f3-4999-9cd5-f76c02cb4e8d",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_row_operations--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_row_operations",
+ "type": "Sum"
+ },
+ "aggregateOperator": "increase",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "bd45ea2f",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "operation--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "operation",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{operation}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "increase"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "68287f23-55e3-4d02-9ce3-0107abb17412",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Row operations",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "942b5e3c-733a-454a-b7f7-b4256696483a",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "table",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "mysql_prepared_statements--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "mysql_prepared_statements",
+ "type": "Sum"
+ },
+ "aggregateOperator": "increase",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "32634e42",
+ "key": {
+ "dataType": "string",
+ "id": "mysql_instance_endpoint--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mysql_instance_endpoint",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "{{.mysql_instance_endpoint}}"
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "command--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "command",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "count",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "increase"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "3fa25e4b-30f9-41d8-8acc-a97aab8a18cd",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Prepared statement count",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "id": "a1da815a-c8b8-4e86-8630-a3265e3be002",
+ "panelTypes": "row",
+ "title": "Resources"
+ }
+ ],
+ "uuid": "0a5a35a0-01f8-4597-8ece-74824c5e9e80"
+ }
\ No newline at end of file
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/assets/dashboards/overview.json b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/assets/dashboards/overview.json
new file mode 100644
index 0000000000..0e89b8a957
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/assets/dashboards/overview.json
@@ -0,0 +1,2602 @@
+{
+ "id": "aws_rds_mysql",
+ "description": "",
+ "layout": [
+ {
+ "h": 5,
+ "i": "8d22c6a7-b22e-4ad2-b242-e15de32ddc0f",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 0
+ },
+ {
+ "h": 5,
+ "i": "94fe032e-3ffc-4cdc-aae6-f851fa47d957",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 0
+ },
+ {
+ "h": 5,
+ "i": "6807e631-4894-4de8-8a55-686c8fa08d4b",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 5
+ },
+ {
+ "h": 5,
+ "i": "d599a942-4dbf-4e29-a3ac-a3142399b557",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 5
+ },
+ {
+ "h": 5,
+ "i": "d16d8683-8c69-4526-a9cd-cc21ae5c60af",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 10
+ },
+ {
+ "h": 5,
+ "i": "845ee717-bbd1-424c-8293-f49e76aa43b3",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 10
+ },
+ {
+ "h": 5,
+ "i": "31c78945-ea1e-4ae1-b0fb-6f1c9de2c016",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 15
+ },
+ {
+ "h": 5,
+ "i": "ae099f6e-5d6c-4127-ac70-2da9741837d7",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 15
+ },
+ {
+ "h": 5,
+ "i": "03c1f0bd-6713-4355-b8e3-6ef781af32c2",
+ "moved": false,
+ "static": false,
+ "w": 4,
+ "x": 0,
+ "y": 20
+ },
+ {
+ "h": 5,
+ "i": "37aabb43-fd8b-47c5-9444-0cd77f9ac435",
+ "moved": false,
+ "static": false,
+ "w": 4,
+ "x": 4,
+ "y": 20
+ },
+ {
+ "h": 5,
+ "i": "c6939628-3c4c-48fb-a2cf-46f6cb358359",
+ "moved": false,
+ "static": false,
+ "w": 4,
+ "x": 8,
+ "y": 20
+ },
+ {
+ "h": 5,
+ "i": "7854afc7-0cd5-4792-a760-be98a2e2f96b",
+ "moved": false,
+ "static": false,
+ "w": 4,
+ "x": 0,
+ "y": 25
+ },
+ {
+ "h": 5,
+ "i": "8126584b-eaa9-4b79-ba8e-a00c394544d8",
+ "moved": false,
+ "static": false,
+ "w": 4,
+ "x": 4,
+ "y": 25
+ },
+ {
+ "h": 5,
+ "i": "3d0a6717-1fd0-4810-b0e9-fe5190d5809f",
+ "moved": false,
+ "static": false,
+ "w": 4,
+ "x": 8,
+ "y": 25
+ },
+ {
+ "h": 5,
+ "i": "ffc39591-288f-4b28-87ee-43456d5d0667",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 30
+ },
+ {
+ "h": 5,
+ "i": "c5189b72-1055-4d6a-b18d-fa23bd9c28d6",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 30
+ }
+ ],
+ "panelMap": {},
+ "tags": [
+ "aws",
+ "rds",
+ "mysql"
+ ],
+ "title": "AWS RDS MySQL",
+ "uploadedGrafana": false,
+ "uuid": "7799e6c9-9b37-4617-9b01-3033665e6605",
+ "variables": {
+ "5ae02d7b-d201-4481-ad6f-ffb9d53e1b3e": {
+ "allSelected": false,
+ "customValue": "",
+ "description": "This is the unique key that identifies a DB instance",
+ "id": "5ae02d7b-d201-4481-ad6f-ffb9d53e1b3e",
+ "modificationUUID": "1ecf21e3-488a-41e7-92f2-7dc75c9de49a",
+ "multiSelect": true,
+ "name": "dbinstance_identifier",
+ "order": 0,
+ "queryValue": "SELECT JSONExtractString(labels, 'dbinstance_identifier') as dbinstance_identifier\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name like 'aws_rds_database_connections_average'\nGROUP BY dbinstance_identifier",
+ "selectedValue": "",
+ "showALLOption": true,
+ "sort": "ASC",
+ "textboxValue": "",
+ "type": "QUERY"
+ }
+ },
+ "version": "v4",
+ "widgets": [
+ {
+ "description": "The number of client network connections to the database instance.",
+ "fillSpans": false,
+ "id": "94fe032e-3ffc-4cdc-aae6-f851fa47d957",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_database_connections_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_database_connections_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "4e451ffc",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "b6816e82-3e9b-4dc6-9fc0-047ef50e47d4",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "DatabaseConnections",
+ "yAxisUnit": "short"
+ },
+ {
+ "description": "The percentage of CPU utilization.",
+ "fillSpans": false,
+ "id": "8d22c6a7-b22e-4ad2-b242-e15de32ddc0f",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_cpuutilization_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_cpuutilization_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "f0a48ddc",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "0318116a-ba6b-405c-b2c0-8dfb321f3ad0",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "CPUUtilization",
+ "yAxisUnit": "percent"
+ },
+ {
+ "description": "The amount of available random access memory. This metric reports the value of the MemAvailable field of /proc/meminfo",
+ "fillSpans": false,
+ "id": "d599a942-4dbf-4e29-a3ac-a3142399b557",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_freeable_memory_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_freeable_memory_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "b738d056",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "5a1e0e0d-3190-4a38-8030-b48d24ebe0f1",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "FreeableMemory",
+ "yAxisUnit": "decbytes"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "c6939628-3c4c-48fb-a2cf-46f6cb358359",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_read_latency_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_read_latency_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "d0ac5956",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "794a5db3-b75c-4354-a509-ab24b5daeba4",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "ReadLatency",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "03c1f0bd-6713-4355-b8e3-6ef781af32c2",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_read_throughput_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_read_throughput_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "bdc062ed",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "avg",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "6915105d-17eb-4863-8ccd-88c6a56d9ad7",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": "aws_rds_read_throughput_average"
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "ReadThroughput",
+ "yAxisUnit": "decbytes"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "37aabb43-fd8b-47c5-9444-0cd77f9ac435",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_read_iops_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_read_iops_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "74504cdf",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "avg",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "0ab52186-6617-4f8b-a3fc-3778c09b6faf",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "ReadIOPS",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "The amount of available storage space.",
+ "fillSpans": false,
+ "id": "6807e631-4894-4de8-8a55-686c8fa08d4b",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_free_storage_space_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_free_storage_space_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "3cfa657c",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "b7f7c9e9-0fdf-462e-b465-57025785e98f",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "FreeStorageSpace",
+ "yAxisUnit": "decbytes"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "7854afc7-0cd5-4792-a760-be98a2e2f96b",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_write_throughput_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_write_throughput_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "05330793",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "d6be5165-c686-412f-80f7-4a81a28cae7d",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "WriteThroughput",
+ "yAxisUnit": "decbytes"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "8126584b-eaa9-4b79-ba8e-a00c394544d8",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_write_iops_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_write_iops_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "0606e3a2",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "253e440a-b13d-411c-a069-d4da1f4c84d7",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "WriteIOPS",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "ffc39591-288f-4b28-87ee-43456d5d0667",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "table",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_network_transmit_throughput_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_network_transmit_throughput_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "sum",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "d5e2f293",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "n/w transmit",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "sum"
+ },
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_network_receive_throughput_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_network_receive_throughput_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "sum",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "B",
+ "filters": {
+ "items": [
+ {
+ "id": "e968f079",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "n/w receive",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "B",
+ "reduceTo": "sum",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "sum"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "2c6be01b-25d9-4480-80c9-f180edad6bf9",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Network transmit/receive",
+ "yAxisUnit": "Bps"
+ },
+ {
+ "description": "The number of outstanding I/Os (read/write requests) waiting to access the disk.",
+ "fillSpans": false,
+ "id": "845ee717-bbd1-424c-8293-f49e76aa43b3",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_disk_queue_depth_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_disk_queue_depth_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "96c73381",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "avg",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "afe73a96-1c56-451e-bca6-2c41c62d47a8",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "DiskQueueDepth",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "The percentage of throughput credits remaining in the burst bucket of your RDS database. ",
+ "fillSpans": false,
+ "id": "ae099f6e-5d6c-4127-ac70-2da9741837d7",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_ebsiobalance__average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_ebsiobalance__average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "e88eb970",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "avg",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "1d8b8b67-0646-4ebc-aa8b-1c10643ddfa0",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "EBSByteBalance%",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "The percentage of I/O credits remaining in the burst bucket of your RDS database.",
+ "fillSpans": false,
+ "id": "31c78945-ea1e-4ae1-b0fb-6f1c9de2c016",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_ebsiobalance__average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_ebsiobalance__average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "c8d78684",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "a0f7c676-ae5f-4db9-bb73-26dbb9db7fab",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "EBSIOBalance%",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "The amount of disk space occupied by binary logs. If automatic backups are enabled for MySQL and MariaDB instances, including read replicas, binary logs are created.",
+ "fillSpans": false,
+ "id": "d16d8683-8c69-4526-a9cd-cc21ae5c60af",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_bin_log_disk_usage_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_bin_log_disk_usage_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "1707f954",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "dbinstance_identifier",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "334d7c5d-4851-419a-90b2-86ebe21befff",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "BinLogDiskUsage",
+ "yAxisUnit": "decbytes"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "3d0a6717-1fd0-4810-b0e9-fe5190d5809f",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_write_latency_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_write_latency_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "5b97fb87",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "7533cf12-7ee3-49e8-8fcd-c1f82ea317ab",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "WriteLatency",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "c5189b72-1055-4d6a-b18d-fa23bd9c28d6",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_swap_usage_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_swap_usage_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "afabe318",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "avg",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "61ecb019-0fbf-44f1-a9db-995b86ee4805",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "SwapUsage",
+ "yAxisUnit": "decbytes"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/config/collect-logs.md b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/config/collect-logs.md
new file mode 100644
index 0000000000..ced23e4b89
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/config/collect-logs.md
@@ -0,0 +1,84 @@
+### Collect RDS Logs
+
+#### Find the list of log group names for RDS instance
+
+The log collection of RDS instance requires specifying the list of log group names. From the AWS CloudWatch console, please find the log group(s) relevant to the integration.
+
+#### Create collector config file
+
+Save the following config for collecting RDS logs in a file named `mysql-logs-collection-config.yaml` and set the `region` key with relevant value.
+
+```yaml
+receivers:
+ awscloudwatch/rds_mysql_logs:
+ region: us-east-1
+ logs:
+ poll_interval: 1m
+ groups:
+ named:
+ # replace the following name with your log group for RDS logs
+ /aws/rds/:
+
+processors:
+ attributes/add_source_mysql:
+ actions:
+ - key: source
+ value: "rds_mysql"
+ action: insert
+ batch:
+ send_batch_size: 10000
+ send_batch_max_size: 11000
+ timeout: 10s
+
+exporters:
+ # export to SigNoz cloud
+ otlp/mysql_logs:
+ endpoint: "${env:OTLP_DESTINATION_ENDPOINT}"
+ tls:
+ insecure: false
+ headers:
+ "signoz-access-token": "${env:SIGNOZ_INGESTION_KEY}"
+
+ # export to local collector
+ otlp/local:
+ endpoint: "localhost:4317"
+ tls:
+ insecure: true
+
+service:
+ pipelines:
+ logs/mysql:
+ receivers: [awscloudwatch/rds_mysql_logs]
+ processors: [attributes/add_source_mysql, batch]
+ exporters: [otlp/mysql_logs]
+```
+
+#### Update log group names
+
+Add the one or more log group names for the RDS under the `named` section of the awscloudwatch receiver.
+
+#### Set Environment Variables
+
+Set the following environment variables in your otel-collector environment:
+
+```bash
+
+# region specific SigNoz cloud ingestion endpoint
+export OTLP_DESTINATION_ENDPOINT="ingest.us.signoz.cloud:443"
+
+# your SigNoz ingestion key
+export SIGNOZ_INGESTION_KEY="signoz-ingestion-key"
+
+```
+
+#### Use collector config file
+
+Make the collector config file available to your otel collector and use it by adding the following flag to the command for running your collector
+```bash
+--config mysql_logs-collection-config.yaml
+```
+Note: the collector can use multiple config files, specified by multiple occurrences of the --config flag.
+
+#### Parse the logs
+
+Use the log pipelines feature to parse and structure the logs https://signoz.io/docs/logs-pipelines/introduction/
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/config/collect-metrics.md b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/config/collect-metrics.md
new file mode 100644
index 0000000000..0975c669a9
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/config/collect-metrics.md
@@ -0,0 +1,324 @@
+### Collect RDS Metrics
+
+The RDS (for MySQL) metrics collection is a two-step process.
+
+#### Set up the Prometheus CloudWatch exporter
+
+The [CloudWatch Exporter](https://github.com/prometheus/cloudwatch_exporter) is A Prometheus exporter for collecting CloudWatch metrics. This section describes the steps for downloading and configuring the Prometheus CloudWatch exporter.
+
+1. Download the Prometheus CloudWatch exporter JAR file, and run the following command:
+
+```sh
+curl -sLSO https://github.com/prometheus/cloudwatch_exporter/releases/download/v0.15.5/cloudwatch_exporter-0.15.5-jar-with-dependencies.jar
+```
+
+2. Configure the Prometheus exporter
+
+Save the following config for collecting AWS RDS metrics in a file named `aws-rds-mysql-metrics.yaml`. Update the `region` with relevant value.
+
+```yaml
+---
+region: us-east-1
+metrics:
+ - aws_namespace: AWS/RDS
+ aws_metric_name: BinLogDiskUsage
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: BurstBalance
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: CheckpointLag
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ConnectionAttempts
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: CPUUtilization
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: DatabaseConnections
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: DiskQueueDepth
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: DiskQueueDepthLogVolume
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: EBSByteBalance%
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: EBSIOBalance%
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: FreeableMemory
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: FreeLocalStorage
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: FreeStorageSpace
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: FreeStorageSpaceLogVolume
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: MaximumUsedTransactionIDs
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: NetworkReceiveThroughput
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: NetworkTransmitThroughput
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: OldestReplicationSlotLag
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReadIOPS
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReadIOPSLocalStorage
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReadIOPSLogVolume
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReadLatency
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReadLatencyLocalStorage
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReadLatencyLogVolume
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReadThroughput
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReadThroughputLogVolume
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReplicaLag
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReplicationChannelLag
+ aws_dimensions: [DBInstanceIdentifier]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReplicationSlotDiskUsage
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: TransactionLogsDiskUsage
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: TransactionLogsGeneration
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: WriteIOPS
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: WriteLatency
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: WriteThroughput
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: SwapUsage
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: DBLoad
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: DBLoadCPU
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: DBLoadNonCPU
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+```
+
+3. Run the following command
+
+```sh
+java -jar cloudwatch_exporter-0.15.5-jar-with-dependencies.jar 9106 aws-rds-mysql-metrics.yaml
+```
+
+#### Set up the OTEL Collector
+
+Save the following config for collecting MySQL metrics in a file named `mysql-metrics-collection-config.yaml`
+
+```yaml
+receivers:
+ mysql:
+ # The hostname and port of the MySQL instance, separated by a colon.
+ endpoint: ${env:MYSQL_ENDPOINT}
+ # The username used to access the MySQL instance.
+ username: ${env:MYSQL_USERNAME}
+ # The password used to access the MySQL instance.
+ password: ${env:MYSQL_PASSWORD}
+ # The frequency at which to collect metrics from the Redis instance.
+ collection_interval: 60s
+ # Additional configuration for query to build mysql.statement_events.count and mysql.statement_events.wait.time metrics
+ statement_events:
+ digest_text_limit: 120
+ time_limit: 24h
+ limit: 250
+ # tls:
+ # insecure: false
+ # ca_file: /etc/ssl/certs/ca-certificates.crt
+ # cert_file: /etc/ssl/certs/redis.crt
+ # key_file: /etc/ssl/certs/redis.key
+ metrics:
+ mysql.client.network.io:
+ enabled: true
+ mysql.commands:
+ enabled: true
+ mysql.connection.count:
+ enabled: true
+ mysql.connection.errors:
+ enabled: true
+ mysql.joins:
+ enabled: true
+ mysql.query.count:
+ enabled: true
+ mysql.query.slow.count:
+ enabled: true
+ mysql.replica.sql_delay:
+ enabled: true
+ mysql.replica.time_behind_source:
+ enabled: true
+
+ # Collecting cloudwatch metrics
+ prometheus:
+ config:
+ scrape_configs:
+ - job_name: 'aws-cloudwatch-metrics'
+ scrape_timeout: 120s
+ scrape_interval: 300s
+ static_configs:
+ - targets: ['0.0.0.0:9106']
+
+exporters:
+ # export to local collector
+ otlp/local:
+ endpoint: "localhost:4317"
+ tls:
+ insecure: true
+ # export to SigNoz cloud
+ otlp/signoz:
+ endpoint: "${env:OTLP_DESTINATION_ENDPOINT}"
+ tls:
+ insecure: false
+ headers:
+ "signoz-access-token": "${env:SIGNOZ_INGESTION_KEY}"
+
+service:
+ pipelines:
+ metrics/mysql:
+ receivers: [mysql, prometheus]
+ processors: []
+ exporters: [otlp/signoz]
+```
+
+#### Set Environment Variables
+
+Set the following environment variables in your otel-collector environment:
+
+```bash
+
+# The accessible endpoint where MySQL server is running
+export MYSQL_ENDPOINT=""
+
+export MYSQL_USERNAME=""
+
+# The password to use for accessing mysql instance
+export MYSQL_PASSWORD=""
+
+# region specific SigNoz cloud ingestion endpoint
+export OTLP_DESTINATION_ENDPOINT="ingest.us.signoz.cloud:443"
+
+# your SigNoz ingestion key
+export SIGNOZ_INGESTION_KEY="signoz-ingestion-key"
+
+```
+
+#### Use collector config file
+
+Make the collector config file available to your otel collector and use it by adding the following flag to the command for running your collector
+```bash
+--config mysql-metrics-collection-config.yaml
+```
+Note: the collector can use multiple config files, specified by multiple occurrences of the --config flag.
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/config/prerequisites.md b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/config/prerequisites.md
new file mode 100644
index 0000000000..ab80d24c49
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/config/prerequisites.md
@@ -0,0 +1,24 @@
+## Before You Begin
+
+To configure metrics and logs collection for an AWS RDS for MySQL, you need the following.
+
+
+- **Ensure Credentials and permissions are set correctly**
+ The components used for this integration relies on AWS SDKs, which offer a variety of ways to provide credentials, including the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables.
+ The following IAM permissions are required:
+ - `cloudwatch:ListMetrics`
+ - `cloudwatch:GetMetricStatistics`
+ - `cloudwatch:GetMetricData`
+ - `tag:GetResources` (if aws_tag_select feature is used)
+ - `logs:DescribeLogGroups`
+ - `logs:FilterLogEvents`
+
+- **Ensure Java Runtime Environment (JRE), version 11 or newer**
+ The CloudWatch Exporter used to collect the metrics requires a Java runtime environment version 11 or newer. This is not required if you can run the docker container.
+
+- **Ensure that an OTEL collector is running in your deployment environment**
+ If needed, please [install an OTEL Collector](https://signoz.io/docs/tutorial/opentelemetry-binary-usage-in-virtual-machine/) If already installed, ensure that the collector version is v0.88.0 or newer. Also, ensure that you can provide config files to the collector and that you can set environment variables and command line flags used for running it.
+
+
+- **Ensure that the OTEL collector can access the MySQL server**
+ To collect MySQL engine metrics, the collector must be able to access the MySQL server as a client. This step is optional.
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/icon.svg b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/icon.svg
new file mode 100644
index 0000000000..245d23725a
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/icon.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/integration.json b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/integration.json
new file mode 100644
index 0000000000..58ef8189bf
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/integration.json
@@ -0,0 +1,757 @@
+{
+ "id": "aws_rds_mysql",
+ "title": "AWS RDS (MySQL)",
+ "description": "Monitor AWS RDS (MySQL) with metrics and logs",
+ "author": {
+ "name": "SigNoz",
+ "email": "integrations@signoz.io",
+ "homepage": "https://signoz.io"
+ },
+ "icon": "file://icon.svg",
+ "categories": [
+ "Database"
+ ],
+ "overview": "file://overview.md",
+ "configuration": [
+ {
+ "title": "Prerequisites",
+ "instructions": "file://config/prerequisites.md"
+ },
+ {
+ "title": "Collect Metrics",
+ "instructions": "file://config/collect-metrics.md"
+ },
+ {
+ "title": "Collect Logs",
+ "instructions": "file://config/collect-logs.md"
+ }
+ ],
+ "assets": {
+ "logs": {
+ "pipelines": []
+ },
+ "dashboards": [
+ "file://assets/dashboards/overview.json",
+ "file://assets/dashboards/db_metrics.json"
+ ],
+ "alerts": []
+ },
+ "connection_tests": {
+ "logs": {
+ "attribute_key": "source",
+ "attribute_value": "rds_mysql"
+ }
+ },
+ "data_collected": {
+ "logs": [
+ {
+ "name": "Timestamp",
+ "path": "timestamp",
+ "type": "timestamp"
+ },
+ {
+ "name": "Body",
+ "path": "body",
+ "type": "string"
+ }
+ ],
+ "metrics": [
+ {
+ "name": "aws_rds_cpuutilization_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: null Statistic: Average Unit: Percent"
+ },
+ {
+ "name": "aws_rds_cpuutilization_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: null Statistic: Maximum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_cpuutilization_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: null Statistic: Minimum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_cpuutilization_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: null Statistic: SampleCount Unit: Percent"
+ },
+ {
+ "name": "aws_rds_cpuutilization_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: null Statistic: Sum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_checkpoint_lag_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CheckpointLag Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_checkpoint_lag_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CheckpointLag Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_cpuutilization_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Percent"
+ },
+ {
+ "name": "aws_rds_cpuutilization_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_database_connections_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DatabaseConnections Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Count"
+ },
+ {
+ "name": "aws_rds_database_connections_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DatabaseConnections Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Count"
+ },
+ {
+ "name": "aws_rds_dbload_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DBLoad Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: None"
+ },
+ {
+ "name": "aws_rds_dbload_cpu_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DBLoadCPU Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: None"
+ },
+ {
+ "name": "aws_rds_dbload_cpu_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DBLoadCPU Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: None"
+ },
+ {
+ "name": "aws_rds_dbload_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DBLoad Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: None"
+ },
+ {
+ "name": "aws_rds_dbload_non_cpu_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DBLoadNonCPU Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: None"
+ },
+ {
+ "name": "aws_rds_dbload_non_cpu_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DBLoadNonCPU Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: None"
+ },
+ {
+ "name": "aws_rds_disk_queue_depth_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DiskQueueDepth Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Count"
+ },
+ {
+ "name": "aws_rds_ebsbyte_balance__average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSByteBalance% Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Percent"
+ },
+ {
+ "name": "aws_rds_ebsiobalance__average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSIOBalance% Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Percent"
+ },
+ {
+ "name": "aws_rds_free_local_storage_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeLocalStorage Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_free_storage_space_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeStorageSpace Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_freeable_memory_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeableMemory Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_freeable_memory_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeableMemory Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_maximum_used_transaction_ids_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS MaximumUsedTransactionIDs Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Count"
+ },
+ {
+ "name": "aws_rds_network_receive_throughput_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkReceiveThroughput Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_network_receive_throughput_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkReceiveThroughput Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_network_transmit_throughput_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkTransmitThroughput Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_network_transmit_throughput_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkTransmitThroughput Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_oldest_replication_slot_lag_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS OldestReplicationSlotLag Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_oldest_replication_slot_lag_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS OldestReplicationSlotLag Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_read_iops_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadIOPS Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_read_iops_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadIOPS Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_read_iopslocal_storage_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadIOPSLocalStorage Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_read_iopslocal_storage_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadIOPSLocalStorage Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_read_latency_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadLatency Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_read_latency_local_storage_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadLatencyLocalStorage Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_read_latency_local_storage_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadLatencyLocalStorage Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_read_latency_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadLatency Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_read_throughput_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadThroughput Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_read_throughput_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadThroughput Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_replica_lag_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReplicaLag Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_replica_lag_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReplicaLag Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_replication_slot_disk_usage_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReplicationSlotDiskUsage Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_swap_usage_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS SwapUsage Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_swap_usage_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS SwapUsage Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_transaction_logs_disk_usage_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS TransactionLogsDiskUsage Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_transaction_logs_generation_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS TransactionLogsGeneration Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_write_iops_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteIOPS Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_write_iops_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteIOPS Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_write_latency_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteLatency Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_write_latency_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteLatency Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_write_throughput_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteThroughput Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_write_throughput_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteThroughput Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: null Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: null Statistic: Maximum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: null Statistic: Minimum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: null Statistic: SampleCount Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: null Statistic: Sum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_cpuutilization_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_cpuutilization_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Percent"
+ },
+ {
+ "name": "aws_rds_cpuutilization_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_database_connections_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DatabaseConnections Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Count"
+ },
+ {
+ "name": "aws_rds_database_connections_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DatabaseConnections Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Count"
+ },
+ {
+ "name": "aws_rds_database_connections_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DatabaseConnections Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Count"
+ },
+ {
+ "name": "aws_rds_disk_queue_depth_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DiskQueueDepth Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Count"
+ },
+ {
+ "name": "aws_rds_disk_queue_depth_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DiskQueueDepth Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Count"
+ },
+ {
+ "name": "aws_rds_disk_queue_depth_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DiskQueueDepth Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Count"
+ },
+ {
+ "name": "aws_rds_disk_queue_depth_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DiskQueueDepth Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Count"
+ },
+ {
+ "name": "aws_rds_ebsbyte_balance__maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSByteBalance% Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_ebsbyte_balance__minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSByteBalance% Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_ebsbyte_balance__sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSByteBalance% Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Percent"
+ },
+ {
+ "name": "aws_rds_ebsbyte_balance__sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSByteBalance% Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_ebsiobalance__maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSIOBalance% Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_ebsiobalance__minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSIOBalance% Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_ebsiobalance__sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSIOBalance% Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Percent"
+ },
+ {
+ "name": "aws_rds_ebsiobalance__sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSIOBalance% Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_free_storage_space_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeStorageSpace Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_free_storage_space_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeStorageSpace Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_free_storage_space_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeStorageSpace Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_free_storage_space_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeStorageSpace Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_freeable_memory_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeableMemory Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_freeable_memory_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeableMemory Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_freeable_memory_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeableMemory Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_network_receive_throughput_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkReceiveThroughput Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_network_receive_throughput_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkReceiveThroughput Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_network_receive_throughput_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkReceiveThroughput Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_network_transmit_throughput_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkTransmitThroughput Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_network_transmit_throughput_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkTransmitThroughput Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_network_transmit_throughput_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkTransmitThroughput Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_read_iops_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadIOPS Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_read_iops_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadIOPS Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_read_iops_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadIOPS Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_read_latency_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadLatency Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_read_latency_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadLatency Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_read_latency_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadLatency Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_read_throughput_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadThroughput Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_read_throughput_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadThroughput Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_read_throughput_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadThroughput Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_swap_usage_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS SwapUsage Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_swap_usage_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS SwapUsage Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_swap_usage_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS SwapUsage Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_write_iops_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteIOPS Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_write_iops_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteIOPS Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_write_iops_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteIOPS Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_write_latency_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteLatency Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_write_latency_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteLatency Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_write_latency_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteLatency Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_write_throughput_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteThroughput Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_write_throughput_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteThroughput Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_write_throughput_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteThroughput Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Bytes/Second"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/overview.md b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/overview.md
new file mode 100644
index 0000000000..45b982df7b
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_mysql/overview.md
@@ -0,0 +1,5 @@
+### Monitor AWS RDS for MySQL with SigNoz
+
+Collect key AWS RDS for MySQL metrics and view them with an out of the box dashboard.
+
+Collect and parse AWS RDS for MySQL logs to populate timestamp, severity, and other log attributes for better querying and aggregation.
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/assets/dashboards/db_metrics_overview.json b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/assets/dashboards/db_metrics_overview.json
new file mode 100644
index 0000000000..cd528c5c96
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/assets/dashboards/db_metrics_overview.json
@@ -0,0 +1,1820 @@
+{
+ "description": "This dashboard provides a high-level overview of your PostgreSQL databases. It includes replication, locks, and throughput etc...",
+ "id": "postgres_overview_metrics",
+ "layout": [
+ {
+ "h": 1,
+ "i": "3bd16024-b9ff-4f02-8107-1fd817604d5f",
+ "maxH": 1,
+ "minH": 1,
+ "minW": 12,
+ "moved": false,
+ "static": false,
+ "w": 12,
+ "x": 0,
+ "y": 0
+ },
+ {
+ "h": 5,
+ "i": "8638a199-20a0-4255-b0a2-3b1ba06c485b",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 1
+ },
+ {
+ "h": 1,
+ "i": "7df9b6d2-8f7f-48d4-80d6-ae07d47746d6",
+ "maxH": 1,
+ "minH": 1,
+ "minW": 12,
+ "moved": false,
+ "static": false,
+ "w": 12,
+ "x": 0,
+ "y": 6
+ },
+ {
+ "h": 5,
+ "i": "191d09a6-40b0-4de8-a5b0-aa4254454b99",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 7
+ },
+ {
+ "h": 5,
+ "i": "fa941c00-ce19-49cc-baf2-c38598767dee",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 7
+ },
+ {
+ "h": 5,
+ "i": "114fcf80-e1de-4716-b1aa-0e0738dba10e",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 12
+ },
+ {
+ "h": 5,
+ "i": "667428ef-9b9a-4e91-bd1e-938e0dc1ff32",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 12
+ },
+ {
+ "h": 5,
+ "i": "bada7864-1d23-4d49-a868-c6b8a93c738f",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 17
+ },
+ {
+ "h": 1,
+ "i": "b437186f-d112-4fb9-bed5-5bea2b5f4b60",
+ "maxH": 1,
+ "minH": 1,
+ "minW": 12,
+ "moved": false,
+ "static": false,
+ "w": 12,
+ "x": 0,
+ "y": 22
+ },
+ {
+ "h": 5,
+ "i": "6b700035-e3c2-4c48-99fa-ebfd6202eed3",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 23
+ },
+ {
+ "h": 5,
+ "i": "e9341e70-ccb3-47fc-af95-56ba8942c4f2",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 23
+ },
+ {
+ "h": 1,
+ "i": "4b94cfd8-7a28-46f9-a618-0a186908f0d5",
+ "maxH": 1,
+ "minH": 1,
+ "minW": 12,
+ "moved": false,
+ "static": false,
+ "w": 12,
+ "x": 0,
+ "y": 28
+ },
+ {
+ "h": 6,
+ "i": "9552123d-6265-48a7-8624-3f4a3fc3c9c0",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 29
+ },
+ {
+ "h": 5,
+ "i": "d7838815-4f5b-4454-86fd-f658b201f3a9",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 29
+ },
+ {
+ "h": 5,
+ "i": "f9a6f683-7455-4643-acc8-467cc5ea52cf",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 35
+ }
+ ],
+ "name": "",
+ "panelMap": {
+ "3bd16024-b9ff-4f02-8107-1fd817604d5f": {
+ "collapsed": false,
+ "widgets": []
+ },
+ "4b94cfd8-7a28-46f9-a618-0a186908f0d5": {
+ "collapsed": true,
+ "widgets": []
+ },
+ "7df9b6d2-8f7f-48d4-80d6-ae07d47746d6": {
+ "collapsed": false,
+ "widgets": [
+ {
+ "h": 5,
+ "i": "191d09a6-40b0-4de8-a5b0-aa4254454b99",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 1
+ },
+ {
+ "h": 5,
+ "i": "fa941c00-ce19-49cc-baf2-c38598767dee",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 1
+ },
+ {
+ "h": 5,
+ "i": "114fcf80-e1de-4716-b1aa-0e0738dba10e",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 6
+ },
+ {
+ "h": 5,
+ "i": "667428ef-9b9a-4e91-bd1e-938e0dc1ff32",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 6
+ },
+ {
+ "h": 5,
+ "i": "bada7864-1d23-4d49-a868-c6b8a93c738f",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 11
+ }
+ ]
+ },
+ "b437186f-d112-4fb9-bed5-5bea2b5f4b60": {
+ "collapsed": false,
+ "widgets": [
+ {
+ "h": 5,
+ "i": "6b700035-e3c2-4c48-99fa-ebfd6202eed3",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 47
+ },
+ {
+ "h": 5,
+ "i": "e9341e70-ccb3-47fc-af95-56ba8942c4f2",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 47
+ },
+ {
+ "h": 4,
+ "i": "8638a199-20a0-4255-b0a2-3b1ba06c485b",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 3,
+ "y": 52
+ },
+ {
+ "h": 5,
+ "i": "f9a6f683-7455-4643-acc8-467cc5ea52cf",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 56
+ },
+ {
+ "h": 5,
+ "i": "d7838815-4f5b-4454-86fd-f658b201f3a9",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 56
+ },
+ {
+ "h": 7,
+ "i": "9552123d-6265-48a7-8624-3f4a3fc3c9c0",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 61
+ }
+ ]
+ }
+ },
+ "tags": [
+ "postgres",
+ "database"
+ ],
+ "title": "Postgres overview",
+ "uploadedGrafana": false,
+ "variables": {
+ "8ecaee70-640f-46fd-83d9-a4fd18bc66e6": {
+ "allSelected": true,
+ "customValue": "",
+ "description": "List of tables",
+ "id": "8ecaee70-640f-46fd-83d9-a4fd18bc66e6",
+ "modificationUUID": "a51321cd-47a2-470a-8df4-372e5bb36f2c",
+ "multiSelect": true,
+ "name": "table_name",
+ "order": 0,
+ "queryValue": "SELECT JSONExtractString(labels, 'postgresql_table_name') AS table_name\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'postgresql_operations' AND JSONExtractString(labels, 'postgresql_database_name') IN {{.db_name}}\nGROUP BY table_name",
+ "selectedValue": [
+ "public.pgbench_accounts",
+ "public.pgbench_branches",
+ "public.pgbench_history",
+ "public.pgbench_tellers"
+ ],
+ "showALLOption": true,
+ "sort": "ASC",
+ "textboxValue": "",
+ "type": "QUERY"
+ },
+ "c66d1581-e5e1-440d-8ff6-ebcf078ab6dd": {
+ "allSelected": true,
+ "customValue": "",
+ "description": "List of databases",
+ "id": "c66d1581-e5e1-440d-8ff6-ebcf078ab6dd",
+ "key": "c66d1581-e5e1-440d-8ff6-ebcf078ab6dd",
+ "modificationUUID": "564a3f43-98f8-4189-b5e4-dcb518d73852",
+ "multiSelect": true,
+ "name": "db_name",
+ "order": 0,
+ "queryValue": "SELECT JSONExtractString(labels, 'postgresql_database_name') AS db_name\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name = 'postgresql_operations'\nGROUP BY db_name",
+ "selectedValue": [
+ "pgtestdb"
+ ],
+ "showALLOption": true,
+ "sort": "DISABLED",
+ "textboxValue": "",
+ "type": "QUERY"
+ }
+ },
+ "widgets": [
+ {
+ "description": "The average number of db insert operations.",
+ "fillSpans": false,
+ "id": "191d09a6-40b0-4de8-a5b0-aa4254454b99",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "postgresql_operations--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "postgresql_operations",
+ "type": "Sum"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "c1dff946",
+ "key": {
+ "dataType": "string",
+ "id": "operation--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "operation",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "ins"
+ },
+ {
+ "id": "2e60e171",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.db_name}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{postgresql_database_name}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "stepInterval": 60
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "bf48ac4c-bc0c-41a0-87f4-6f8ae7888d1f",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "softMax": null,
+ "softMin": null,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Inserts",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "The average number of db update operations.",
+ "fillSpans": false,
+ "id": "fa941c00-ce19-49cc-baf2-c38598767dee",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "postgresql_operations--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "postgresql_operations",
+ "type": "Sum"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "98463ec9",
+ "key": {
+ "dataType": "string",
+ "id": "operation--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "operation",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "upd"
+ },
+ {
+ "id": "64020332",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.db_name}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{postgresql_database_name}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "stepInterval": 60
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "34a6ac3a-b7f6-4b5f-a084-a44378033d82",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "softMax": null,
+ "softMin": null,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Updates",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "The average number of db delete operations.",
+ "fillSpans": false,
+ "id": "114fcf80-e1de-4716-b1aa-0e0738dba10e",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "postgresql_operations--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "postgresql_operations",
+ "type": "Sum"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "62738de4",
+ "key": {
+ "dataType": "string",
+ "id": "operation--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "operation",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "del"
+ },
+ {
+ "id": "9d153899",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.db_name}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{postgresql_database_name}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "stepInterval": 60
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "734393d1-76ed-4f4f-bef8-0a91d27ebec4",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "softMax": null,
+ "softMin": null,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Deleted",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "The average number of db heap-only update operations.",
+ "fillSpans": false,
+ "id": "667428ef-9b9a-4e91-bd1e-938e0dc1ff32",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "postgresql_operations--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "postgresql_operations",
+ "type": "Sum"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "a91e35c4",
+ "key": {
+ "dataType": "string",
+ "id": "operation--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "operation",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "hot_upd"
+ },
+ {
+ "id": "7b4a29a2",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.db_name}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{postgresql_database_name}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "stepInterval": 60
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "f43c2d19-4abc-4f5e-881b-db7add4a870a",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "softMax": null,
+ "softMin": null,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Heap updates",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "bada7864-1d23-4d49-a868-c6b8a93c738f",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "table",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "postgresql_operations--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "postgresql_operations",
+ "type": "Sum"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "d6aeccf7",
+ "key": {
+ "dataType": "string",
+ "id": "operation--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "operation",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "ins"
+ },
+ {
+ "id": "ee4e9344",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.db_name}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "Inserted",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "stepInterval": 60
+ },
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "postgresql_operations--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "postgresql_operations",
+ "type": "Sum"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "B",
+ "filters": {
+ "items": [
+ {
+ "id": "a12cceed",
+ "key": {
+ "dataType": "string",
+ "id": "operation--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "operation",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "upd"
+ },
+ {
+ "id": "2d542482",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.db_name}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "Updated",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "B",
+ "reduceTo": "sum",
+ "stepInterval": 60
+ },
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "postgresql_operations--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "postgresql_operations",
+ "type": "Sum"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "C",
+ "filters": {
+ "items": [
+ {
+ "id": "1bca3e46",
+ "key": {
+ "dataType": "string",
+ "id": "operation--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "operation",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "del"
+ },
+ {
+ "id": "44ffc874",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.db_name}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "Deleted",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "C",
+ "reduceTo": "sum",
+ "stepInterval": 60
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "5056105b-1c30-4d27-8187-64457f2a1ec6",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "softMax": null,
+ "softMin": null,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Operation by database",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "The number of database locks.",
+ "fillSpans": false,
+ "id": "6b700035-e3c2-4c48-99fa-ebfd6202eed3",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "postgresql_database_locks--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "postgresql_database_locks",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "sum",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [],
+ "op": "AND"
+ },
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "mode--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "mode",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{mode}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "stepInterval": 60
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "877b0df3-9ae3-455e-ad27-bc3aa40b3f4c",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "softMax": null,
+ "softMin": null,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Locks by lock mode",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "e9341e70-ccb3-47fc-af95-56ba8942c4f2",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "postgresql_deadlocks--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "postgresql_deadlocks",
+ "type": "Sum"
+ },
+ "aggregateOperator": "sum_rate",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "efb83717",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.db_name}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{postgresql_database_name}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "stepInterval": 60
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "5056105b-1c30-4d27-8187-64457f2a1ec6",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "softMax": null,
+ "softMin": null,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Deadlocks count",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "8638a199-20a0-4255-b0a2-3b1ba06c485b",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "postgresql_backends--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "postgresql_backends",
+ "type": "Sum"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "20d2a4c5",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.db_name}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{postgresql_database_name}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "stepInterval": 60
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "205b99a0-2f1c-4bd2-9ba0-cc2da6ef247a",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "softMax": null,
+ "softMin": null,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Connections per db",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "f9a6f683-7455-4643-acc8-467cc5ea52cf",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "postgresql_rows--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "postgresql_rows",
+ "type": "Sum"
+ },
+ "aggregateOperator": "sum",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "70786905",
+ "key": {
+ "dataType": "string",
+ "id": "state--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "state",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "dead"
+ },
+ {
+ "id": "3e5ef839",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.db_name}}"
+ ]
+ },
+ {
+ "id": "9e913563",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_table_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_table_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.table_name}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "groupBy": [],
+ "having": [],
+ "legend": "Dead rows",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "stepInterval": 60
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "cc7452c8-118b-4676-959e-7062bafc41ee",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "softMax": null,
+ "softMin": null,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Dead rows",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "d7838815-4f5b-4454-86fd-f658b201f3a9",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "postgresql_index_scans--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "postgresql_index_scans",
+ "type": "Sum"
+ },
+ "aggregateOperator": "sum_rate",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "590332a7",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.db_name}}"
+ ]
+ },
+ {
+ "id": "171b9516",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_table_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_table_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.table_name}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "postgresql_index_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_index_name",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{postgresql_index_name}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "sum",
+ "stepInterval": 60
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "2c6b630b-8bd9-4001-815b-f2b1f439a9dd",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "softMax": null,
+ "softMin": null,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Index scans by index",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "9552123d-6265-48a7-8624-3f4a3fc3c9c0",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "table",
+ "query": {
+ "clickhouse_sql": [
+ {
+ "name": "A",
+ "legend": "",
+ "disabled": false,
+ "query": ""
+ }
+ ],
+ "promql": [
+ {
+ "name": "A",
+ "query": "",
+ "legend": "",
+ "disabled": false
+ }
+ ],
+ "builder": {
+ "queryData": [
+ {
+ "dataSource": "metrics",
+ "queryName": "A",
+ "aggregateOperator": "avg",
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "postgresql_rows--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "postgresql_rows",
+ "type": "Sum"
+ },
+ "timeAggregation": "rate",
+ "spaceAggregation": "sum",
+ "functions": [],
+ "filters": {
+ "items": [
+ {
+ "id": "d2039662",
+ "key": {
+ "dataType": "string",
+ "id": "state--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "state",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "dead"
+ },
+ {
+ "id": "21c6d446",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.db_name}}"
+ ]
+ },
+ {
+ "id": "a44d1843",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_table_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_table_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.table_name}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "expression": "A",
+ "disabled": false,
+ "having": [],
+ "stepInterval": 840,
+ "limit": null,
+ "orderBy": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_table_name",
+ "type": "tag",
+ "id": "postgresql_table_name--string--tag--false"
+ }
+ ],
+ "legend": "Dead rows",
+ "reduceTo": "sum"
+ },
+ {
+ "dataSource": "metrics",
+ "queryName": "B",
+ "aggregateOperator": "avg",
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "postgresql_rows--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "postgresql_rows",
+ "type": "Sum"
+ },
+ "timeAggregation": "rate",
+ "spaceAggregation": "sum",
+ "functions": [],
+ "filters": {
+ "items": [
+ {
+ "id": "74888dbf",
+ "key": {
+ "dataType": "string",
+ "id": "state--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "state",
+ "type": "tag"
+ },
+ "op": "=",
+ "value": "live"
+ },
+ {
+ "id": "3e5d7976",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.db_name}}"
+ ]
+ },
+ {
+ "id": "c18ed7a3",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_table_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_table_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.table_name}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "expression": "B",
+ "disabled": false,
+ "having": [],
+ "stepInterval": 840,
+ "limit": null,
+ "orderBy": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_table_name",
+ "type": "tag",
+ "id": "postgresql_table_name--string--tag--false"
+ }
+ ],
+ "legend": "Live rows",
+ "reduceTo": "sum"
+ },
+ {
+ "dataSource": "metrics",
+ "queryName": "C",
+ "aggregateOperator": "sum_rate",
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "postgresql_index_scans--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "postgresql_index_scans",
+ "type": "Sum"
+ },
+ "timeAggregation": "rate",
+ "spaceAggregation": "sum",
+ "functions": [],
+ "filters": {
+ "items": [
+ {
+ "id": "f9355263",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.db_name}}"
+ ]
+ },
+ {
+ "id": "8807a9c4",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_table_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_table_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.table_name}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "expression": "C",
+ "disabled": false,
+ "having": [],
+ "stepInterval": 840,
+ "limit": null,
+ "orderBy": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_table_name",
+ "type": "tag",
+ "id": "postgresql_table_name--string--tag--false"
+ }
+ ],
+ "legend": "Index scans",
+ "reduceTo": "sum"
+ },
+ {
+ "dataSource": "metrics",
+ "queryName": "D",
+ "aggregateOperator": "avg",
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "postgresql_table_size--float64--Sum--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "postgresql_table_size",
+ "type": "Sum"
+ },
+ "timeAggregation": "rate",
+ "spaceAggregation": "sum",
+ "functions": [],
+ "filters": {
+ "items": [
+ {
+ "id": "4be865f1",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_database_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_database_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.db_name}}"
+ ]
+ },
+ {
+ "id": "58200638",
+ "key": {
+ "dataType": "string",
+ "id": "postgresql_table_name--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_table_name",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.table_name}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "expression": "D",
+ "disabled": true,
+ "having": [],
+ "stepInterval": 840,
+ "limit": null,
+ "orderBy": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "postgresql_table_name",
+ "type": "tag",
+ "id": "postgresql_table_name--string--tag--false"
+ }
+ ],
+ "legend": "Table size",
+ "reduceTo": "sum"
+ }
+ ],
+ "queryFormulas": [
+ {
+ "queryName": "F1",
+ "expression": "D/1024/1024/1024",
+ "disabled": false,
+ "legend": "Table size (GB)"
+ }
+ ]
+ },
+ "id": "05e9c65b-a296-47c0-a802-2fca3320b07a",
+ "queryType": "builder"
+ },
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Table stats",
+ "yAxisUnit": "none",
+ "selectedLogFields": [],
+ "selectedTracesFields": []
+ },
+ {
+ "description": "",
+ "id": "7df9b6d2-8f7f-48d4-80d6-ae07d47746d6",
+ "panelTypes": "row",
+ "title": "Operations"
+ },
+ {
+ "description": "",
+ "id": "b437186f-d112-4fb9-bed5-5bea2b5f4b60",
+ "panelTypes": "row",
+ "title": "Locks"
+ },
+ {
+ "description": "",
+ "id": "3bd16024-b9ff-4f02-8107-1fd817604d5f",
+ "panelTypes": "row",
+ "title": "Connections"
+ },
+ {
+ "description": "",
+ "id": "4b94cfd8-7a28-46f9-a618-0a186908f0d5",
+ "panelTypes": "row",
+ "title": "Stats"
+ }
+ ],
+ "uuid": "149ad467-ba1b-421f-ad87-78f943cc7530"
+ }
\ No newline at end of file
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/assets/dashboards/overview.json b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/assets/dashboards/overview.json
new file mode 100644
index 0000000000..1b28ffc043
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/assets/dashboards/overview.json
@@ -0,0 +1,2782 @@
+{
+ "id": "aws_rds_postgres",
+ "description": "",
+ "layout": [
+ {
+ "h": 5,
+ "i": "8d22c6a7-b22e-4ad2-b242-e15de32ddc0f",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 0
+ },
+ {
+ "h": 5,
+ "i": "94fe032e-3ffc-4cdc-aae6-f851fa47d957",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 0
+ },
+ {
+ "h": 5,
+ "i": "d73f2e63-33d8-40f7-a67b-861a628ba249",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 5
+ },
+ {
+ "h": 5,
+ "i": "336bca83-50be-4937-b41b-ca8fde150f4d",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 5
+ },
+ {
+ "h": 5,
+ "i": "6807e631-4894-4de8-8a55-686c8fa08d4b",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 10
+ },
+ {
+ "h": 5,
+ "i": "d599a942-4dbf-4e29-a3ac-a3142399b557",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 10
+ },
+ {
+ "h": 5,
+ "i": "31c78945-ea1e-4ae1-b0fb-6f1c9de2c016",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 15
+ },
+ {
+ "h": 5,
+ "i": "845ee717-bbd1-424c-8293-f49e76aa43b3",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 15
+ },
+ {
+ "h": 5,
+ "i": "c5189b72-1055-4d6a-b18d-fa23bd9c28d6",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 20
+ },
+ {
+ "h": 5,
+ "i": "ae099f6e-5d6c-4127-ac70-2da9741837d7",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 6,
+ "y": 20
+ },
+ {
+ "h": 5,
+ "i": "03c1f0bd-6713-4355-b8e3-6ef781af32c2",
+ "moved": false,
+ "static": false,
+ "w": 4,
+ "x": 0,
+ "y": 25
+ },
+ {
+ "h": 5,
+ "i": "37aabb43-fd8b-47c5-9444-0cd77f9ac435",
+ "moved": false,
+ "static": false,
+ "w": 4,
+ "x": 4,
+ "y": 25
+ },
+ {
+ "h": 5,
+ "i": "c6939628-3c4c-48fb-a2cf-46f6cb358359",
+ "moved": false,
+ "static": false,
+ "w": 4,
+ "x": 8,
+ "y": 25
+ },
+ {
+ "h": 5,
+ "i": "7854afc7-0cd5-4792-a760-be98a2e2f96b",
+ "moved": false,
+ "static": false,
+ "w": 4,
+ "x": 0,
+ "y": 30
+ },
+ {
+ "h": 5,
+ "i": "8126584b-eaa9-4b79-ba8e-a00c394544d8",
+ "moved": false,
+ "static": false,
+ "w": 4,
+ "x": 4,
+ "y": 30
+ },
+ {
+ "h": 5,
+ "i": "3d0a6717-1fd0-4810-b0e9-fe5190d5809f",
+ "moved": false,
+ "static": false,
+ "w": 4,
+ "x": 8,
+ "y": 30
+ },
+ {
+ "h": 5,
+ "i": "ffc39591-288f-4b28-87ee-43456d5d0667",
+ "moved": false,
+ "static": false,
+ "w": 6,
+ "x": 0,
+ "y": 35
+ }
+ ],
+ "panelMap": {},
+ "tags": [
+ "aws",
+ "rds",
+ "postgres"
+ ],
+ "title": "AWS RDS Postgres",
+ "uploadedGrafana": false,
+ "variables": {
+ "5ae02d7b-d201-4481-ad6f-ffb9d53e1b3e": {
+ "allSelected": true,
+ "customValue": "",
+ "description": "This is the unique key that identifies a DB instance",
+ "id": "5ae02d7b-d201-4481-ad6f-ffb9d53e1b3e",
+ "modificationUUID": "1ecf21e3-488a-41e7-92f2-7dc75c9de49a",
+ "multiSelect": true,
+ "name": "dbinstance_identifier",
+ "order": 0,
+ "queryValue": "SELECT JSONExtractString(labels, 'dbinstance_identifier') as dbinstance_identifier\nFROM signoz_metrics.distributed_time_series_v4_1day\nWHERE metric_name like 'aws_rds_database_connections_average'\nGROUP BY dbinstance_identifier",
+ "selectedValue": [
+ "integration-db-instance-instance-1",
+ "integration-db-instance-instance-2",
+ "integration-db-instance-instance-3",
+ "integration-test-postgres-instance-1",
+ "integration-test-postgres-instance-2",
+ "integration-test-postgres-instance-3",
+ "integration-testing-db-instance-1",
+ "integration-testing-db-instance-2",
+ "integration-testing-db-instance-3"
+ ],
+ "showALLOption": true,
+ "sort": "ASC",
+ "textboxValue": "",
+ "type": "QUERY"
+ }
+ },
+ "version": "v4",
+ "widgets": [
+ {
+ "description": "The number of client network connections to the database instance.",
+ "fillSpans": false,
+ "id": "94fe032e-3ffc-4cdc-aae6-f851fa47d957",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_database_connections_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_database_connections_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "4e451ffc",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "b6816e82-3e9b-4dc6-9fc0-047ef50e47d4",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "DatabaseConnections",
+ "yAxisUnit": "short"
+ },
+ {
+ "description": "The percentage of CPU utilization.",
+ "fillSpans": false,
+ "id": "8d22c6a7-b22e-4ad2-b242-e15de32ddc0f",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_cpuutilization_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_cpuutilization_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "f0a48ddc",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "0318116a-ba6b-405c-b2c0-8dfb321f3ad0",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "CPUUtilization",
+ "yAxisUnit": "percent"
+ },
+ {
+ "description": "The amount of available random access memory. This metric reports the value of the MemAvailable field of /proc/meminfo",
+ "fillSpans": false,
+ "id": "d599a942-4dbf-4e29-a3ac-a3142399b557",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_freeable_memory_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_freeable_memory_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "b738d056",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "5a1e0e0d-3190-4a38-8030-b48d24ebe0f1",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "FreeableMemory",
+ "yAxisUnit": "decbytes"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "c6939628-3c4c-48fb-a2cf-46f6cb358359",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_read_latency_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_read_latency_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "d0ac5956",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "794a5db3-b75c-4354-a509-ab24b5daeba4",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "ReadLatency",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "03c1f0bd-6713-4355-b8e3-6ef781af32c2",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_read_throughput_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_read_throughput_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "bdc062ed",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "avg",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "6915105d-17eb-4863-8ccd-88c6a56d9ad7",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": "aws_rds_read_throughput_average"
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "ReadThroughput",
+ "yAxisUnit": "decbytes"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "37aabb43-fd8b-47c5-9444-0cd77f9ac435",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_read_iops_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_read_iops_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "74504cdf",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "avg",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "0ab52186-6617-4f8b-a3fc-3778c09b6faf",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "ReadIOPS",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "The amount of available storage space.",
+ "fillSpans": false,
+ "id": "6807e631-4894-4de8-8a55-686c8fa08d4b",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_free_storage_space_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_free_storage_space_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "3cfa657c",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "b7f7c9e9-0fdf-462e-b465-57025785e98f",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "FreeStorageSpace",
+ "yAxisUnit": "decbytes"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "7854afc7-0cd5-4792-a760-be98a2e2f96b",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_write_throughput_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_write_throughput_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "05330793",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "d6be5165-c686-412f-80f7-4a81a28cae7d",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "WriteThroughput",
+ "yAxisUnit": "decbytes"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "8126584b-eaa9-4b79-ba8e-a00c394544d8",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_write_iops_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_write_iops_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "0606e3a2",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "253e440a-b13d-411c-a069-d4da1f4c84d7",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "WriteIOPS",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "ffc39591-288f-4b28-87ee-43456d5d0667",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "table",
+ "query": {
+ "clickhouse_sql": [
+ {
+ "name": "A",
+ "legend": "",
+ "disabled": false,
+ "query": ""
+ }
+ ],
+ "promql": [
+ {
+ "name": "A",
+ "query": "",
+ "legend": "",
+ "disabled": false
+ }
+ ],
+ "builder": {
+ "queryData": [
+ {
+ "dataSource": "metrics",
+ "queryName": "A",
+ "aggregateOperator": "sum",
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_network_transmit_throughput_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_network_transmit_throughput_average",
+ "type": "Gauge"
+ },
+ "timeAggregation": "sum",
+ "spaceAggregation": "sum",
+ "functions": [],
+ "filters": {
+ "items": [
+ {
+ "id": "9a27ef98",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "expression": "A",
+ "disabled": true,
+ "having": [],
+ "stepInterval": 60,
+ "limit": null,
+ "orderBy": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag",
+ "id": "dbinstance_identifier--string--tag--false"
+ }
+ ],
+ "legend": "n/w transmit",
+ "reduceTo": "sum"
+ },
+ {
+ "dataSource": "metrics",
+ "queryName": "B",
+ "aggregateOperator": "sum",
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_network_receive_throughput_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_network_receive_throughput_average",
+ "type": "Gauge"
+ },
+ "timeAggregation": "sum",
+ "spaceAggregation": "sum",
+ "functions": [],
+ "filters": {
+ "items": [
+ {
+ "id": "df2ee1fc",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "expression": "B",
+ "disabled": true,
+ "having": [],
+ "stepInterval": 60,
+ "limit": null,
+ "orderBy": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag",
+ "id": "dbinstance_identifier--string--tag--false"
+ }
+ ],
+ "legend": "n/w receive",
+ "reduceTo": "sum"
+ }
+ ],
+ "queryFormulas": [
+ {
+ "queryName": "F1",
+ "expression": "A/1024/1024",
+ "disabled": false,
+ "legend": "n/w transmit (mb)"
+ },
+ {
+ "queryName": "F2",
+ "expression": "B/1024/1024",
+ "disabled": false,
+ "legend": "n/w receive (mb)"
+ }
+ ]
+ },
+ "id": "60b5a712-ac27-4b2e-a8d7-a180b389c780",
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "Network transmit/receive",
+ "yAxisUnit": "Bps"
+ },
+ {
+ "description": "The number of outstanding I/Os (read/write requests) waiting to access the disk.",
+ "fillSpans": false,
+ "id": "845ee717-bbd1-424c-8293-f49e76aa43b3",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_disk_queue_depth_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_disk_queue_depth_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "96c73381",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "avg",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "afe73a96-1c56-451e-bca6-2c41c62d47a8",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "DiskQueueDepth",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "The percentage of throughput credits remaining in the burst bucket of your RDS database. ",
+ "fillSpans": false,
+ "id": "ae099f6e-5d6c-4127-ac70-2da9741837d7",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_ebsiobalance__average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_ebsiobalance__average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "e88eb970",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "avg",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "1d8b8b67-0646-4ebc-aa8b-1c10643ddfa0",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "EBSByteBalance%",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "The percentage of I/O credits remaining in the burst bucket of your RDS database.",
+ "fillSpans": false,
+ "id": "31c78945-ea1e-4ae1-b0fb-6f1c9de2c016",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_ebsiobalance__average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_ebsiobalance__average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "c8d78684",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "a0f7c676-ae5f-4db9-bb73-26dbb9db7fab",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "EBSIOBalance%",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "3d0a6717-1fd0-4810-b0e9-fe5190d5809f",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_write_latency_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_write_latency_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "5b97fb87",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "7533cf12-7ee3-49e8-8fcd-c1f82ea317ab",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "WriteLatency",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "c5189b72-1055-4d6a-b18d-fa23bd9c28d6",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_swap_usage_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_swap_usage_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "afabe318",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "avg",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "61ecb019-0fbf-44f1-a9db-995b86ee4805",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "SwapUsage",
+ "yAxisUnit": "decbytes"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "336bca83-50be-4937-b41b-ca8fde150f4d",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_checkpoint_lag_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_checkpoint_lag_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "abac3888",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "187a2eae-4fe4-4e47-b544-20404532cbb2",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "CheckpointLag",
+ "yAxisUnit": "none"
+ },
+ {
+ "description": "",
+ "fillSpans": false,
+ "id": "d73f2e63-33d8-40f7-a67b-861a628ba249",
+ "isStacked": false,
+ "nullZeroValues": "zero",
+ "opacity": "1",
+ "panelTypes": "graph",
+ "query": {
+ "builder": {
+ "queryData": [
+ {
+ "aggregateAttribute": {
+ "dataType": "float64",
+ "id": "aws_rds_replica_lag_average--float64--Gauge--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "aws_rds_replica_lag_average",
+ "type": "Gauge"
+ },
+ "aggregateOperator": "avg",
+ "dataSource": "metrics",
+ "disabled": false,
+ "expression": "A",
+ "filters": {
+ "items": [
+ {
+ "id": "47be5579",
+ "key": {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ },
+ "op": "in",
+ "value": [
+ "{{.dbinstance_identifier}}"
+ ]
+ }
+ ],
+ "op": "AND"
+ },
+ "functions": [],
+ "groupBy": [
+ {
+ "dataType": "string",
+ "id": "dbinstance_identifier--string--tag--false",
+ "isColumn": false,
+ "isJSON": false,
+ "key": "dbinstance_identifier",
+ "type": "tag"
+ }
+ ],
+ "having": [],
+ "legend": "{{dbinstance_identifier}}",
+ "limit": null,
+ "orderBy": [],
+ "queryName": "A",
+ "reduceTo": "avg",
+ "spaceAggregation": "sum",
+ "stepInterval": 60,
+ "timeAggregation": "avg"
+ }
+ ],
+ "queryFormulas": []
+ },
+ "clickhouse_sql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "id": "53e6ee05-bcbc-4f01-b061-a358371d92ff",
+ "promql": [
+ {
+ "disabled": false,
+ "legend": "",
+ "name": "A",
+ "query": ""
+ }
+ ],
+ "queryType": "builder"
+ },
+ "selectedLogFields": [
+ {
+ "dataType": "string",
+ "name": "body",
+ "type": ""
+ },
+ {
+ "dataType": "string",
+ "name": "timestamp",
+ "type": ""
+ }
+ ],
+ "selectedTracesFields": [
+ {
+ "dataType": "string",
+ "id": "serviceName--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "serviceName",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "name--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "name",
+ "type": "tag"
+ },
+ {
+ "dataType": "float64",
+ "id": "durationNano--float64--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "durationNano",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "httpMethod--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "httpMethod",
+ "type": "tag"
+ },
+ {
+ "dataType": "string",
+ "id": "responseStatusCode--string--tag--true",
+ "isColumn": true,
+ "isJSON": false,
+ "key": "responseStatusCode",
+ "type": "tag"
+ }
+ ],
+ "softMax": 0,
+ "softMin": 0,
+ "thresholds": [],
+ "timePreferance": "GLOBAL_TIME",
+ "title": "ReplicaLag",
+ "yAxisUnit": "none"
+ }
+ ],
+ "uuid": "05e473e2-5733-4877-8b7f-cb311d4e9c0a"
+}
\ No newline at end of file
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/config/collect-logs.md b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/config/collect-logs.md
new file mode 100644
index 0000000000..511d8daa5c
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/config/collect-logs.md
@@ -0,0 +1,76 @@
+### Collect RDS Logs
+
+#### Find the list of log group names for RDS instance
+
+Collecting logs from an RDS instance requires specifying the list of log group names. From the AWS CloudWatch console, please find the log group(s) relevant to the integration.
+
+#### Create collector config file
+
+Save the following configuration for collecting RDS logs in a file named `postgres-logs-collection-config.yaml`. Make sure to update the log group name(s) under the `named` section of the `awscloudwatch` receiver in the config, and set the `region` with the relevant value.
+
+```yaml
+receivers:
+ awscloudwatch/rds_postgres_logs:
+ region: us-east-1
+ logs:
+ poll_interval: 1m
+ groups:
+ named:
+ # replace the following name with your log group for RDS logs
+ /aws/rds/:
+
+processors:
+ attributes/add_source_postgres:
+ actions:
+ - key: source
+ value: "rds_postgres"
+ action: insert
+ batch:
+ send_batch_size: 10000
+ send_batch_max_size: 11000
+ timeout: 10s
+
+exporters:
+ # export to SigNoz cloud
+ otlp/postgres_logs:
+ endpoint: "${env:OTLP_DESTINATION_ENDPOINT}"
+ tls:
+ insecure: false
+ headers:
+ "signoz-access-token": "${env:SIGNOZ_INGESTION_KEY}"
+
+ # export to local collector
+ otlp/local:
+ endpoint: "localhost:4317"
+ tls:
+ insecure: true
+
+service:
+ pipelines:
+ logs/postgres:
+ receivers: [awscloudwatch/rds_postgres_logs]
+ processors: [attributes/add_source_postgres, batch]
+ exporters: [otlp/postgres_logs]
+```
+
+#### Set Environment Variables
+
+Set the following environment variables in your otel-collector environment:
+
+```bash
+
+# region specific SigNoz cloud ingestion endpoint
+export OTLP_DESTINATION_ENDPOINT="ingest.us.signoz.cloud:443"
+
+# your SigNoz ingestion key
+export SIGNOZ_INGESTION_KEY="signoz-ingestion-key"
+
+```
+
+#### Use collector config file
+
+Make the collector config file available to your OpenTelemetry (otel) collector and use it by adding the following flag to the command for running your collector:
+```bash
+--config postgres-logs-collection-config.yaml
+```
+Note: The collector can use multiple config files, specified by multiple occurrences of the --config flag.
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/config/collect-metrics.md b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/config/collect-metrics.md
new file mode 100644
index 0000000000..e5c8d00184
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/config/collect-metrics.md
@@ -0,0 +1,314 @@
+### Collect RDS Metrics
+
+Collecting RDS (for PostgreSQL) metrics is a two-step process.
+
+#### Set up the Prometheus CloudWatch exporter
+
+The [CloudWatch Exporter](https://github.com/prometheus/cloudwatch_exporter) is A Prometheus exporter for collecting CloudWatch metrics. This section describes the steps for downloading and configuring the Prometheus CloudWatch exporter.
+
+1. Download the Prometheus CloudWatch exporter JAR file, and run the following command:
+
+```sh
+curl -sLSO https://github.com/prometheus/cloudwatch_exporter/releases/download/v0.15.5/cloudwatch_exporter-0.15.5-jar-with-dependencies.jar
+```
+
+2. Configure the Prometheus exporter
+
+Save the following config for collecting AWS RDS metrics in a file named `aws-rds-postgres-metrics.yaml` and update the `region` key with relevant value.
+
+```yaml
+---
+region: us-east-1
+metrics:
+ - aws_namespace: AWS/RDS
+ aws_metric_name: BinLogDiskUsage
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: BurstBalance
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: CheckpointLag
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ConnectionAttempts
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: CPUUtilization
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: DatabaseConnections
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: DiskQueueDepth
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: DiskQueueDepthLogVolume
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: EBSByteBalance%
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: EBSIOBalance%
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: FreeableMemory
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: FreeLocalStorage
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: FreeStorageSpace
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: FreeStorageSpaceLogVolume
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: MaximumUsedTransactionIDs
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: NetworkReceiveThroughput
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: NetworkTransmitThroughput
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: OldestReplicationSlotLag
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReadIOPS
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReadIOPSLocalStorage
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReadIOPSLogVolume
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReadLatency
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReadLatencyLocalStorage
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReadLatencyLogVolume
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReadThroughput
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReadThroughputLogVolume
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReplicaLag
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReplicationChannelLag
+ aws_dimensions: [DBInstanceIdentifier]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: ReplicationSlotDiskUsage
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: TransactionLogsDiskUsage
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: TransactionLogsGeneration
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: WriteIOPS
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: WriteLatency
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: WriteThroughput
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: SwapUsage
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: DBLoad
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: DBLoadCPU
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+
+ - aws_namespace: AWS/RDS
+ aws_metric_name: DBLoadNonCPU
+ aws_dimensions: [DBInstanceIdentifier]
+ aws_statistics: [Average, Maximum]
+```
+
+3. Run the following command
+
+```sh
+java -jar cloudwatch_exporter-0.15.5-jar-with-dependencies.jar 9106 aws-rds-postgres-metrics.yaml
+```
+
+4. Verify the CloudWatch metrics
+
+Visit the http://localhost:9106/metrics and confirm the `aws_rds_*` metrics are avialable.
+
+#### Set up the OTEL Collector
+
+Save the following config for collecting Postgres metrics in a file named `postgres-metrics-collection-config.yaml`
+
+```yaml
+receivers:
+ postgresql:
+ # The endpoint of the postgresql server. Whether using TCP or Unix sockets, this value should be host:port. If transport is set to unix, the endpoint will internally be translated from host:port to /host.s.PGSQL.port
+ endpoint: ${env:POSTGRESQL_ENDPOINT}
+ # The frequency at which to collect metrics from the Postgres instance.
+ collection_interval: 60s
+ # The username used to access the postgres instance
+ username: ${env:POSTGRESQL_USERNAME}
+ # The password used to access the postgres instance
+ password: ${env:POSTGRESQL_PASSWORD}
+ # The list of databases for which the receiver will attempt to collect statistics. If an empty list is provided, the receiver will attempt to collect statistics for all non-template databases
+ databases: ["pgtestdb"]
+ # # Defines the network to use for connecting to the server. Valid Values are `tcp` or `unix`
+ # transport: tcp
+ tls:
+ insecure_skip_verify: true
+ # ca_file: /etc/ssl/certs/ca-certificates.crt
+ # cert_file: /etc/ssl/certs/postgres.crt
+ # key_file: /etc/ssl/certs/postgres.key
+ metrics:
+ postgresql.database.locks:
+ enabled: true
+ postgresql.deadlocks:
+ enabled: true
+ postgresql.sequential_scans:
+ enabled: true
+
+ prometheus:
+ config:
+ scrape_configs:
+ - job_name: 'aws-cloudwatch-metrics'
+ scrape_timeout: 120s
+ scrape_interval: 300s
+ static_configs:
+ - targets: ['0.0.0.0:9106']
+
+exporters:
+ # export to local collector
+ otlp/local:
+ endpoint: "localhost:4317"
+ tls:
+ insecure: true
+ # export to SigNoz cloud
+ otlp/signoz:
+ endpoint: "${env:OTLP_DESTINATION_ENDPOINT}"
+ tls:
+ insecure: false
+ headers:
+ "signoz-access-token": "${env:SIGNOZ_INGESTION_KEY}"
+
+service:
+ pipelines:
+ metrics/postgresql:
+ receivers: [postgresql, prometheus]
+ processors: []
+ exporters: [otlp/signoz]
+```
+
+#### Set Environment Variables
+
+Set the following environment variables in your otel-collector environment:
+
+```bash
+
+# The accessible endpoint where PostgreSQL server is running
+export POSTGRESQL_ENDPOINT=""
+
+export POSTGRESQL_USERNAME=""
+
+# The password to use for accessing postgres instance
+export POSTGRESQL_PASSWORD=""
+
+# region specific SigNoz cloud ingestion endpoint
+export OTLP_DESTINATION_ENDPOINT="ingest.us.signoz.cloud:443"
+
+# your SigNoz ingestion key
+export SIGNOZ_INGESTION_KEY="signoz-ingestion-key"
+
+```
+
+#### Use collector config file
+
+Make the collector config file available to your OpenTelemetry (OTel) collector and use it by adding the following flag to the command for running your collector:
+```bash
+--config postgres-metrics-collection-config.yaml
+```
+Note: the collector can use multiple config files, specified by multiple occurrences of the --config flag.
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/config/prerequisites.md b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/config/prerequisites.md
new file mode 100644
index 0000000000..db51fa67f3
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/config/prerequisites.md
@@ -0,0 +1,22 @@
+## Before You Begin
+
+To configure metrics and logs collection for an AWS RDS for PostgreSQL, you need the following.
+
+- **Ensure Credentials and permissions are set correctly**
+ The components used for this integration rely on AWS SDKs, which offer a variety of ways to provide credentials, including the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables.
+ The following IAM permissions are required:
+ - `cloudwatch:ListMetrics`
+ - `cloudwatch:GetMetricStatistics`
+ - `cloudwatch:GetMetricData`
+ - `logs:DescribeLogGroups`
+ - `logs:FilterLogEvents`
+
+- **Ensure Java Runtime Environment (JRE), version 11 or newer**
+ The CloudWatch Exporter used to collect the metrics requires a Java runtime environment version 11 or newer. Alternatively, you can also run a docker container https://github.com/prometheus/cloudwatch_exporter#docker-images
+
+- **Ensure that an OTEL collector is running in your deployment environment**
+ Please [install an OTEL Collector](https://signoz.io/docs/tutorial/opentelemetry-binary-usage-in-virtual-machine/) If already installed, ensure that the collector version is v0.88.0 or newer. Also, ensure that you can provide config files to the collector and that you can set environment variables and command line flags used for running it.
+
+
+- **Ensure that the OTEL collector can access the Postgres server**
+ To collect Postgres server metrics, the collector must be able to access the Postgres server as a client. This step is optional if you are only interested in working with CloudWatch metrics.
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/icon.svg b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/icon.svg
new file mode 100644
index 0000000000..245d23725a
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/icon.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/integration.json b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/integration.json
new file mode 100644
index 0000000000..8beef023be
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/integration.json
@@ -0,0 +1,919 @@
+{
+ "id": "aws_rds_postgresql",
+ "title": "AWS RDS (PostgreSQL)",
+ "description": "Monitor AWS RDS (PostgreSQL) with metrics and logs",
+ "author": {
+ "name": "SigNoz",
+ "email": "integrations@signoz.io",
+ "homepage": "https://signoz.io"
+ },
+ "icon": "file://icon.svg",
+ "categories": [
+ "Database"
+ ],
+ "overview": "file://overview.md",
+ "configuration": [
+ {
+ "title": "Prerequisites",
+ "instructions": "file://config/prerequisites.md"
+ },
+ {
+ "title": "Collect Metrics",
+ "instructions": "file://config/collect-metrics.md"
+ },
+ {
+ "title": "Collect Logs",
+ "instructions": "file://config/collect-logs.md"
+ }
+ ],
+ "assets": {
+ "logs": {
+ "pipelines": []
+ },
+ "dashboards": [
+ "file://assets/dashboards/overview.json",
+ "file://assets/dashboards/db_metrics_overview.json"
+ ],
+ "alerts": []
+ },
+ "connection_tests": {
+ "logs": {
+ "attribute_key": "source",
+ "attribute_value": "rds_postgres"
+ }
+ },
+ "data_collected": {
+ "logs": [
+ {
+ "name": "Timestamp",
+ "path": "timestamp",
+ "type": "timestamp"
+ },
+ {
+ "name": "Body",
+ "path": "body",
+ "type": "string"
+ }
+ ],
+ "metrics": [
+ {
+ "name": "aws_rds_cpuutilization_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: null Statistic: Average Unit: Percent"
+ },
+ {
+ "name": "aws_rds_cpuutilization_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: null Statistic: Maximum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_cpuutilization_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: null Statistic: Minimum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_cpuutilization_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: null Statistic: SampleCount Unit: Percent"
+ },
+ {
+ "name": "aws_rds_cpuutilization_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: null Statistic: Sum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_checkpoint_lag_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CheckpointLag Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_checkpoint_lag_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CheckpointLag Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_cpuutilization_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Percent"
+ },
+ {
+ "name": "aws_rds_cpuutilization_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_database_connections_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DatabaseConnections Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Count"
+ },
+ {
+ "name": "aws_rds_database_connections_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DatabaseConnections Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Count"
+ },
+ {
+ "name": "aws_rds_dbload_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DBLoad Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: None"
+ },
+ {
+ "name": "aws_rds_dbload_cpu_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DBLoadCPU Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: None"
+ },
+ {
+ "name": "aws_rds_dbload_cpu_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DBLoadCPU Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: None"
+ },
+ {
+ "name": "aws_rds_dbload_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DBLoad Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: None"
+ },
+ {
+ "name": "aws_rds_dbload_non_cpu_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DBLoadNonCPU Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: None"
+ },
+ {
+ "name": "aws_rds_dbload_non_cpu_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DBLoadNonCPU Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: None"
+ },
+ {
+ "name": "aws_rds_disk_queue_depth_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DiskQueueDepth Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Count"
+ },
+ {
+ "name": "aws_rds_ebsbyte_balance__average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSByteBalance% Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Percent"
+ },
+ {
+ "name": "aws_rds_ebsiobalance__average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSIOBalance% Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Percent"
+ },
+ {
+ "name": "aws_rds_free_local_storage_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeLocalStorage Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_free_storage_space_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeStorageSpace Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_freeable_memory_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeableMemory Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_freeable_memory_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeableMemory Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_maximum_used_transaction_ids_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS MaximumUsedTransactionIDs Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Count"
+ },
+ {
+ "name": "aws_rds_network_receive_throughput_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkReceiveThroughput Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_network_receive_throughput_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkReceiveThroughput Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_network_transmit_throughput_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkTransmitThroughput Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_network_transmit_throughput_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkTransmitThroughput Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_oldest_replication_slot_lag_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS OldestReplicationSlotLag Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_oldest_replication_slot_lag_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS OldestReplicationSlotLag Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_read_iops_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadIOPS Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_read_iops_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadIOPS Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_read_iopslocal_storage_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadIOPSLocalStorage Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_read_iopslocal_storage_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadIOPSLocalStorage Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_read_latency_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadLatency Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_read_latency_local_storage_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadLatencyLocalStorage Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_read_latency_local_storage_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadLatencyLocalStorage Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_read_latency_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadLatency Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_read_throughput_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadThroughput Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_read_throughput_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadThroughput Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_replica_lag_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReplicaLag Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_replica_lag_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReplicaLag Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_replication_slot_disk_usage_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReplicationSlotDiskUsage Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_swap_usage_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS SwapUsage Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_swap_usage_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS SwapUsage Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_transaction_logs_disk_usage_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS TransactionLogsDiskUsage Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_transaction_logs_generation_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS TransactionLogsGeneration Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_write_iops_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteIOPS Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_write_iops_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteIOPS Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_write_latency_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteLatency Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_write_latency_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteLatency Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_write_throughput_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteThroughput Dimensions: [DBInstanceIdentifier] Statistic: Average Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_write_throughput_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteThroughput Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_average",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: null Statistic: Average Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: null Statistic: Maximum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: null Statistic: Minimum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: null Statistic: SampleCount Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: null Statistic: Sum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_bin_log_disk_usage_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS BinLogDiskUsage Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_cpuutilization_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_cpuutilization_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Percent"
+ },
+ {
+ "name": "aws_rds_cpuutilization_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS CPUUtilization Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_database_connections_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DatabaseConnections Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Count"
+ },
+ {
+ "name": "aws_rds_database_connections_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DatabaseConnections Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Count"
+ },
+ {
+ "name": "aws_rds_database_connections_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DatabaseConnections Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Count"
+ },
+ {
+ "name": "aws_rds_disk_queue_depth_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DiskQueueDepth Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Count"
+ },
+ {
+ "name": "aws_rds_disk_queue_depth_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DiskQueueDepth Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Count"
+ },
+ {
+ "name": "aws_rds_disk_queue_depth_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DiskQueueDepth Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Count"
+ },
+ {
+ "name": "aws_rds_disk_queue_depth_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS DiskQueueDepth Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Count"
+ },
+ {
+ "name": "aws_rds_ebsbyte_balance__maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSByteBalance% Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_ebsbyte_balance__minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSByteBalance% Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_ebsbyte_balance__sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSByteBalance% Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Percent"
+ },
+ {
+ "name": "aws_rds_ebsbyte_balance__sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSByteBalance% Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_ebsiobalance__maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSIOBalance% Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_ebsiobalance__minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSIOBalance% Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_ebsiobalance__sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSIOBalance% Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Percent"
+ },
+ {
+ "name": "aws_rds_ebsiobalance__sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS EBSIOBalance% Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Percent"
+ },
+ {
+ "name": "aws_rds_free_storage_space_maximum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeStorageSpace Dimensions: [DBInstanceIdentifier] Statistic: Maximum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_free_storage_space_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeStorageSpace Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_free_storage_space_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeStorageSpace Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_free_storage_space_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeStorageSpace Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_freeable_memory_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeableMemory Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_freeable_memory_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeableMemory Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_freeable_memory_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS FreeableMemory Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_network_receive_throughput_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkReceiveThroughput Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_network_receive_throughput_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkReceiveThroughput Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_network_receive_throughput_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkReceiveThroughput Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_network_transmit_throughput_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkTransmitThroughput Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_network_transmit_throughput_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkTransmitThroughput Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_network_transmit_throughput_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS NetworkTransmitThroughput Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_read_iops_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadIOPS Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_read_iops_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadIOPS Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_read_iops_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadIOPS Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_read_latency_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadLatency Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_read_latency_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadLatency Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_read_latency_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadLatency Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_read_throughput_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadThroughput Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_read_throughput_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadThroughput Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_read_throughput_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS ReadThroughput Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_swap_usage_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS SwapUsage Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_swap_usage_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS SwapUsage Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_swap_usage_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS SwapUsage Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Bytes"
+ },
+ {
+ "name": "aws_rds_write_iops_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteIOPS Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_write_iops_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteIOPS Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_write_iops_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteIOPS Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Count/Second"
+ },
+ {
+ "name": "aws_rds_write_latency_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteLatency Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_write_latency_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteLatency Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_write_latency_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteLatency Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Seconds"
+ },
+ {
+ "name": "aws_rds_write_throughput_minimum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteThroughput Dimensions: [DBInstanceIdentifier] Statistic: Minimum Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_write_throughput_sample_count",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteThroughput Dimensions: [DBInstanceIdentifier] Statistic: SampleCount Unit: Bytes/Second"
+ },
+ {
+ "name": "aws_rds_write_throughput_sum",
+ "type": "Gauge",
+ "unit": "number",
+ "description": "CloudWatch metric AWS/RDS WriteThroughput Dimensions: [DBInstanceIdentifier] Statistic: Sum Unit: Bytes/Second"
+ },
+ {
+ "name": "postgresql_backends",
+ "type": "sum",
+ "unit": "number",
+ "description": "The number of backends."
+ },
+ {
+ "name": "postgresql_bgwriter_buffers_allocated",
+ "type": "sum",
+ "unit": "number",
+ "description": "Number of buffers allocated."
+ },
+ {
+ "name": "postgresql_bgwriter_buffers_writes",
+ "type": "sum",
+ "unit": "number",
+ "description": "Number of buffers written."
+ },
+ {
+ "name": "postgresql_bgwriter_checkpoint_count",
+ "type": "sum",
+ "unit": "number",
+ "description": "The number of checkpoints performed."
+ },
+ {
+ "name": "postgresql_bgwriter_duration",
+ "type": "sum",
+ "unit": "ms",
+ "description": "Total time spent writing and syncing files to disk by checkpoints."
+ },
+ {
+ "name": "postgresql_bgwriter_maxwritten",
+ "type": "sum",
+ "unit": "number",
+ "description": "Number of times the background writer stopped a cleaning scan because it had written too many buffers."
+ },
+ {
+ "name": "postgresql_blocks_read",
+ "type": "sum",
+ "unit": "number",
+ "description": "The number of blocks read."
+ },
+ {
+ "name": "postgresql_commits",
+ "type": "sum",
+ "unit": "number",
+ "description": "The number of commits."
+ },
+ {
+ "name": "postgresql_connection_max",
+ "type": "gauge",
+ "unit": "number",
+ "description": "Configured maximum number of client connections allowed"
+ },
+ {
+ "name": "postgresql_database_count",
+ "type": "sum",
+ "unit": "number",
+ "description": "Number of user databases."
+ },
+ {
+ "name": "postgresql_database_locks",
+ "type": "gauge",
+ "unit": "number",
+ "description": "The number of database locks."
+ },
+ {
+ "name": "postgresql_db_size",
+ "type": "sum",
+ "unit": "Bytes",
+ "description": "The database disk usage."
+ },
+ {
+ "name": "postgresql_deadlocks",
+ "type": "sum",
+ "unit": "number",
+ "description": "The number of deadlocks."
+ },
+ {
+ "name": "postgresql_index_scans",
+ "type": "sum",
+ "unit": "number",
+ "description": "The number of index scans on a table."
+ },
+ {
+ "name": "postgresql_index_size",
+ "type": "gauge",
+ "unit": "Bytes",
+ "description": "The size of the index on disk."
+ },
+ {
+ "name": "postgresql_operations",
+ "type": "sum",
+ "unit": "number",
+ "description": "The number of db row operations."
+ },
+ {
+ "name": "postgresql_replication_data_delay",
+ "type": "gauge",
+ "unit": "Bytes",
+ "description": "The amount of data delayed in replication."
+ },
+ {
+ "name": "postgresql_rollbacks",
+ "type": "sum",
+ "unit": "number",
+ "description": "The number of rollbacks."
+ },
+ {
+ "name": "postgresql_rows",
+ "type": "sum",
+ "unit": "number",
+ "description": "The number of rows in the database."
+ },
+ {
+ "name": "postgresql_sequential_scans",
+ "type": "sum",
+ "unit": "number",
+ "description": "The number of sequential scans."
+ },
+ {
+ "name": "postgresql_table_count",
+ "type": "sum",
+ "unit": "number",
+ "description": "Number of user tables in a database."
+ },
+ {
+ "name": "postgresql_table_size",
+ "type": "sum",
+ "unit": "Bytes",
+ "description": "Disk space used by a table."
+ },
+ {
+ "name": "postgresql_table_vacuum_count",
+ "type": "sum",
+ "unit": "number",
+ "description": "Number of times a table has manually been vacuumed."
+ },
+ {
+ "name": "postgresql_temp_files",
+ "type": "sum",
+ "unit": "number",
+ "description": "The number of temp files."
+ },
+ {
+ "name": "postgresql_wal_age",
+ "type": "gauge",
+ "unit": "seconds",
+ "description": "Age of the oldest WAL file."
+ },
+ {
+ "name": "postgresql_wal_delay",
+ "type": "gauge",
+ "unit": "seconds",
+ "description": "Time between flushing recent WAL locally and receiving notification that the standby server has completed an operation with it."
+ },
+ {
+ "name": "postgresql_wal_lag",
+ "type": "gauge",
+ "unit": "seconds",
+ "description": "Time between flushing recent WAL locally and receiving notification that the standby server has completed an operation with it."
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/overview.md b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/overview.md
new file mode 100644
index 0000000000..9cf2a84a49
--- /dev/null
+++ b/pkg/query-service/app/integrations/builtin_integrations/aws_rds_postgres/overview.md
@@ -0,0 +1,5 @@
+### Monitor AWS RDS for PostgreSQL with SigNoz
+
+Collect key AWS RDS for PostgreSQL metrics and view them with an out of the box dashboard.
+
+Collect and parse AWS RDS for PostgreSQL logs to populate timestamp, severity, and other log attributes for better querying and aggregation.
diff --git a/pkg/query-service/app/logs/v3/json_filter.go b/pkg/query-service/app/logs/v3/json_filter.go
index bcc4b68a14..a9acdeaab3 100644
--- a/pkg/query-service/app/logs/v3/json_filter.go
+++ b/pkg/query-service/app/logs/v3/json_filter.go
@@ -144,7 +144,8 @@ func GetJSONFilter(item v3.FilterItem) (string, error) {
fmtVal := utils.ClickHouseFormattedValue(value)
filter = fmt.Sprintf(logsOp, key, fmtVal)
case v3.FilterOperatorContains, v3.FilterOperatorNotContains:
- filter = fmt.Sprintf("%s %s '%%%s%%'", key, logsOp, item.Value)
+ val := utils.QuoteEscapedString(fmt.Sprintf("%v", item.Value))
+ filter = fmt.Sprintf("%s %s '%%%s%%'", key, logsOp, val)
default:
fmtVal := utils.ClickHouseFormattedValue(value)
filter = fmt.Sprintf("%s %s %s", key, logsOp, fmtVal)
diff --git a/pkg/query-service/app/logs/v3/json_filter_test.go b/pkg/query-service/app/logs/v3/json_filter_test.go
index 2992b1e273..ac9d8edbf4 100644
--- a/pkg/query-service/app/logs/v3/json_filter_test.go
+++ b/pkg/query-service/app/logs/v3/json_filter_test.go
@@ -300,6 +300,19 @@ var testGetJSONFilterData = []struct {
},
Filter: "JSON_EXISTS(body, '$.\"message\"') AND JSON_VALUE(body, '$.\"message\"') ILIKE '%a%'",
},
+ {
+ Name: "contains operator with quotes",
+ FilterItem: v3.FilterItem{
+ Key: v3.AttributeKey{
+ Key: "body.message",
+ DataType: "string",
+ IsJSON: true,
+ },
+ Operator: "contains",
+ Value: "hello 'world'",
+ },
+ Filter: "JSON_EXISTS(body, '$.\"message\"') AND JSON_VALUE(body, '$.\"message\"') ILIKE '%hello \\'world\\'%'",
+ },
{
Name: "exists",
FilterItem: v3.FilterItem{
diff --git a/pkg/query-service/app/logs/v3/query_builder.go b/pkg/query-service/app/logs/v3/query_builder.go
index 75cacaa2ed..06cacc8f60 100644
--- a/pkg/query-service/app/logs/v3/query_builder.go
+++ b/pkg/query-service/app/logs/v3/query_builder.go
@@ -192,7 +192,8 @@ func buildLogsTimeSeriesFilterQuery(fs *v3.FilterSet, groupBy []v3.AttributeKey,
conditions = append(conditions, fmt.Sprintf(logsOp, columnName, fmtVal))
case v3.FilterOperatorContains, v3.FilterOperatorNotContains:
columnName := getClickhouseColumnName(item.Key)
- conditions = append(conditions, fmt.Sprintf("%s %s '%%%s%%'", columnName, logsOp, item.Value))
+ val := utils.QuoteEscapedString(fmt.Sprintf("%v", item.Value))
+ conditions = append(conditions, fmt.Sprintf("%s %s '%%%s%%'", columnName, logsOp, val))
default:
columnName := getClickhouseColumnName(item.Key)
fmtVal := utils.ClickHouseFormattedValue(value)
diff --git a/pkg/query-service/app/logs/v3/query_builder_test.go b/pkg/query-service/app/logs/v3/query_builder_test.go
index 7a8a997be4..606ccffeef 100644
--- a/pkg/query-service/app/logs/v3/query_builder_test.go
+++ b/pkg/query-service/app/logs/v3/query_builder_test.go
@@ -187,6 +187,13 @@ var timeSeriesFilterQueryData = []struct {
}},
ExpectedFilter: "attributes_string_value[indexOf(attributes_string_key, 'host')] ILIKE '%102.%'",
},
+ {
+ Name: "Test contains with single quotes",
+ FilterSet: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{
+ {Key: v3.AttributeKey{Key: "message", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Value: "hello 'world'", Operator: "contains"},
+ }},
+ ExpectedFilter: "attributes_string_value[indexOf(attributes_string_key, 'message')] ILIKE '%hello \\'world\\'%'",
+ },
{
Name: "Test not contains",
FilterSet: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{
@@ -280,7 +287,6 @@ var timeSeriesFilterQueryData = []struct {
}},
ExpectedFilter: "`attribute_int64_status_exists`=false",
},
- // add new tests
}
func TestBuildLogsTimeSeriesFilterQuery(t *testing.T) {
diff --git a/pkg/query-service/app/metrics/v3/query_builder.go b/pkg/query-service/app/metrics/v3/query_builder.go
index b5453e97b4..9307363361 100644
--- a/pkg/query-service/app/metrics/v3/query_builder.go
+++ b/pkg/query-service/app/metrics/v3/query_builder.go
@@ -217,11 +217,7 @@ func buildMetricQuery(start, end, step int64, mq *v3.BuilderQuery) (string, erro
// `ts` is always added to the group by clause
func groupingSets(tags ...string) string {
withTs := append(tags, "ts")
- if len(withTs) > 1 {
- return fmt.Sprintf(`GROUPING SETS ( (%s), (%s) )`, strings.Join(withTs, ", "), strings.Join(tags, ", "))
- } else {
- return strings.Join(withTs, ", ")
- }
+ return strings.Join(withTs, ", ")
}
// groupBy returns a string of comma separated tags for group by clause
@@ -345,6 +341,33 @@ func PrepareMetricQuery(start, end int64, queryType v3.QueryType, panelType v3.P
adjustStep := int64(math.Min(float64(mq.StepInterval), 60))
end = end - (end % (adjustStep * 1000))
+ // if the aggregate operator is a histogram quantile, and user has not forgotten
+ // the le tag in the group by then add the le tag to the group by
+ if mq.AggregateOperator == v3.AggregateOperatorHistQuant50 ||
+ mq.AggregateOperator == v3.AggregateOperatorHistQuant75 ||
+ mq.AggregateOperator == v3.AggregateOperatorHistQuant90 ||
+ mq.AggregateOperator == v3.AggregateOperatorHistQuant95 ||
+ mq.AggregateOperator == v3.AggregateOperatorHistQuant99 {
+ found := false
+ for _, tag := range mq.GroupBy {
+ if tag.Key == "le" {
+ found = true
+ break
+ }
+ }
+ if !found {
+ mq.GroupBy = append(
+ mq.GroupBy,
+ v3.AttributeKey{
+ Key: "le",
+ DataType: v3.AttributeKeyDataTypeString,
+ Type: v3.AttributeKeyTypeTag,
+ IsColumn: false,
+ },
+ )
+ }
+ }
+
var query string
var err error
if mq.Temporality == v3.Delta {
diff --git a/pkg/query-service/app/metrics/v4/cumulative/table_test.go b/pkg/query-service/app/metrics/v4/cumulative/table_test.go
index ebdaa51182..70613c9b44 100644
--- a/pkg/query-service/app/metrics/v4/cumulative/table_test.go
+++ b/pkg/query-service/app/metrics/v4/cumulative/table_test.go
@@ -93,7 +93,7 @@ func TestPrepareTableQuery(t *testing.T) {
},
start: 1701794980000,
end: 1701796780000,
- expectedQueryContains: "SELECT service_name, ts, sum(per_series_value) as value FROM (SELECT service_name, ts, If((per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) < 0, nan, If((ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window) >= 86400, nan, (per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window))) as per_series_value FROM (SELECT fingerprint, any(service_name) as service_name, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, max(value) as per_series_value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, fingerprint FROM signoz_metrics.time_series_v4 WHERE metric_name = 'http_requests' AND temporality = 'Cumulative' AND unix_milli >= 1701792000000 AND unix_milli < 1701796780000 AND like(JSONExtractString(labels, 'service_name'), '%payment_service%')) as filtered_time_series USING fingerprint WHERE metric_name = 'http_requests' AND unix_milli >= 1701794980000 AND unix_milli < 1701796780000 GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window as (PARTITION BY fingerprint ORDER BY fingerprint, ts)) WHERE isNaN(per_series_value) = 0 GROUP BY GROUPING SETS ( (service_name, ts), (service_name) ) ORDER BY service_name ASC, ts ASC",
+ expectedQueryContains: "SELECT service_name, ts, sum(per_series_value) as value FROM (SELECT service_name, ts, If((per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) < 0, nan, If((ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window) >= 86400, nan, (per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window))) as per_series_value FROM (SELECT fingerprint, any(service_name) as service_name, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, max(value) as per_series_value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, fingerprint FROM signoz_metrics.time_series_v4 WHERE metric_name = 'http_requests' AND temporality = 'Cumulative' AND unix_milli >= 1701792000000 AND unix_milli < 1701796780000 AND like(JSONExtractString(labels, 'service_name'), '%payment_service%')) as filtered_time_series USING fingerprint WHERE metric_name = 'http_requests' AND unix_milli >= 1701794980000 AND unix_milli < 1701796780000 GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window as (PARTITION BY fingerprint ORDER BY fingerprint, ts)) WHERE isNaN(per_series_value) = 0 GROUP BY service_name, ts ORDER BY service_name ASC, ts ASC",
},
}
diff --git a/pkg/query-service/app/metrics/v4/cumulative/timeseries_test.go b/pkg/query-service/app/metrics/v4/cumulative/timeseries_test.go
index 9e31d0f0e7..ce47e10b10 100644
--- a/pkg/query-service/app/metrics/v4/cumulative/timeseries_test.go
+++ b/pkg/query-service/app/metrics/v4/cumulative/timeseries_test.go
@@ -210,7 +210,7 @@ func TestPrepareTimeseriesQuery(t *testing.T) {
},
start: 1701794980000,
end: 1701796780000,
- expectedQueryContains: "SELECT service_name, ts, sum(per_series_value) as value FROM (SELECT service_name, ts, If((per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) < 0, nan, If((ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window) >= 86400, nan, (per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window))) as per_series_value FROM (SELECT fingerprint, any(service_name) as service_name, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, max(value) as per_series_value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, fingerprint FROM signoz_metrics.time_series_v4 WHERE metric_name = 'http_requests' AND temporality = 'Cumulative' AND unix_milli >= 1701792000000 AND unix_milli < 1701796780000 AND like(JSONExtractString(labels, 'service_name'), '%payment_service%')) as filtered_time_series USING fingerprint WHERE metric_name = 'http_requests' AND unix_milli >= 1701794980000 AND unix_milli < 1701796780000 GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window as (PARTITION BY fingerprint ORDER BY fingerprint, ts)) WHERE isNaN(per_series_value) = 0 GROUP BY GROUPING SETS ( (service_name, ts), (service_name) ) ORDER BY service_name ASC, ts ASC",
+ expectedQueryContains: "SELECT service_name, ts, sum(per_series_value) as value FROM (SELECT service_name, ts, If((per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) < 0, nan, If((ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window) >= 86400, nan, (per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window))) as per_series_value FROM (SELECT fingerprint, any(service_name) as service_name, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, max(value) as per_series_value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, fingerprint FROM signoz_metrics.time_series_v4 WHERE metric_name = 'http_requests' AND temporality = 'Cumulative' AND unix_milli >= 1701792000000 AND unix_milli < 1701796780000 AND like(JSONExtractString(labels, 'service_name'), '%payment_service%')) as filtered_time_series USING fingerprint WHERE metric_name = 'http_requests' AND unix_milli >= 1701794980000 AND unix_milli < 1701796780000 GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window as (PARTITION BY fingerprint ORDER BY fingerprint, ts)) WHERE isNaN(per_series_value) = 0 GROUP BY service_name, ts ORDER BY service_name ASC, ts ASC",
},
}
diff --git a/pkg/query-service/app/metrics/v4/delta/table_test.go b/pkg/query-service/app/metrics/v4/delta/table_test.go
index 54a35e40e4..40b9297dc2 100644
--- a/pkg/query-service/app/metrics/v4/delta/table_test.go
+++ b/pkg/query-service/app/metrics/v4/delta/table_test.go
@@ -95,7 +95,7 @@ func TestPrepareTableQuery(t *testing.T) {
},
start: 1701794980000,
end: 1701796780000,
- expectedQueryContains: "SELECT service_name, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, sum(value)/60 as value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, fingerprint FROM signoz_metrics.time_series_v4 WHERE metric_name = 'http_requests' AND temporality = 'Delta' AND unix_milli >= 1701792000000 AND unix_milli < 1701796780000 AND like(JSONExtractString(labels, 'service_name'), '%payment_service%')) as filtered_time_series USING fingerprint WHERE metric_name = 'http_requests' AND unix_milli >= 1701794980000 AND unix_milli < 1701796780000 GROUP BY GROUPING SETS ( (service_name, ts), (service_name) ) ORDER BY service_name ASC, ts ASC",
+ expectedQueryContains: "SELECT service_name, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, sum(value)/60 as value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, fingerprint FROM signoz_metrics.time_series_v4 WHERE metric_name = 'http_requests' AND temporality = 'Delta' AND unix_milli >= 1701792000000 AND unix_milli < 1701796780000 AND like(JSONExtractString(labels, 'service_name'), '%payment_service%')) as filtered_time_series USING fingerprint WHERE metric_name = 'http_requests' AND unix_milli >= 1701794980000 AND unix_milli < 1701796780000 GROUP BY service_name, ts ORDER BY service_name ASC, ts ASC",
},
}
diff --git a/pkg/query-service/app/metrics/v4/delta/time_series_test.go b/pkg/query-service/app/metrics/v4/delta/time_series_test.go
index 29c2340ec4..5b6d71b3de 100644
--- a/pkg/query-service/app/metrics/v4/delta/time_series_test.go
+++ b/pkg/query-service/app/metrics/v4/delta/time_series_test.go
@@ -210,7 +210,7 @@ func TestPrepareTimeseriesQuery(t *testing.T) {
},
start: 1701794980000,
end: 1701796780000,
- expectedQueryContains: "SELECT service_name, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, sum(value)/60 as value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, fingerprint FROM signoz_metrics.time_series_v4 WHERE metric_name = 'http_requests' AND temporality = 'Delta' AND unix_milli >= 1701792000000 AND unix_milli < 1701796780000 AND like(JSONExtractString(labels, 'service_name'), '%payment_service%')) as filtered_time_series USING fingerprint WHERE metric_name = 'http_requests' AND unix_milli >= 1701794980000 AND unix_milli < 1701796780000 GROUP BY GROUPING SETS ( (service_name, ts), (service_name) ) ORDER BY service_name ASC, ts ASC",
+ expectedQueryContains: "SELECT service_name, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, sum(value)/60 as value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, fingerprint FROM signoz_metrics.time_series_v4 WHERE metric_name = 'http_requests' AND temporality = 'Delta' AND unix_milli >= 1701792000000 AND unix_milli < 1701796780000 AND like(JSONExtractString(labels, 'service_name'), '%payment_service%')) as filtered_time_series USING fingerprint WHERE metric_name = 'http_requests' AND unix_milli >= 1701794980000 AND unix_milli < 1701796780000 GROUP BY service_name, ts ORDER BY service_name ASC, ts ASC",
},
{
name: "test time aggregation = rate, space aggregation percentile99, type = ExponentialHistogram",
@@ -244,7 +244,7 @@ func TestPrepareTimeseriesQuery(t *testing.T) {
},
start: 1701794980000,
end: 1701796780000,
- expectedQueryContains: "SELECT service_name, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, quantilesDDMerge(0.01, 0.990000)(sketch)[1] as value FROM signoz_metrics.distributed_exp_hist INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, fingerprint FROM signoz_metrics.time_series_v4 WHERE metric_name = 'signoz_latency' AND temporality = 'Delta' AND unix_milli >= 1701792000000 AND unix_milli < 1701796780000) as filtered_time_series USING fingerprint WHERE metric_name = 'signoz_latency' AND unix_milli >= 1701794980000 AND unix_milli < 1701796780000 GROUP BY GROUPING SETS ( (service_name, ts), (service_name) ) ORDER BY service_name ASC, ts ASC",
+ expectedQueryContains: "SELECT service_name, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, quantilesDDMerge(0.01, 0.990000)(sketch)[1] as value FROM signoz_metrics.distributed_exp_hist INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, fingerprint FROM signoz_metrics.time_series_v4 WHERE metric_name = 'signoz_latency' AND temporality = 'Delta' AND unix_milli >= 1701792000000 AND unix_milli < 1701796780000) as filtered_time_series USING fingerprint WHERE metric_name = 'signoz_latency' AND unix_milli >= 1701794980000 AND unix_milli < 1701796780000 GROUP BY service_name, ts ORDER BY service_name ASC, ts ASC",
},
}
diff --git a/pkg/query-service/app/metrics/v4/helpers/clauses.go b/pkg/query-service/app/metrics/v4/helpers/clauses.go
index 06f4b13cea..e99951df69 100644
--- a/pkg/query-service/app/metrics/v4/helpers/clauses.go
+++ b/pkg/query-service/app/metrics/v4/helpers/clauses.go
@@ -11,11 +11,7 @@ import (
// `ts` is always added to the group by clause
func groupingSets(tags ...string) string {
withTs := append(tags, "ts")
- if len(withTs) > 1 {
- return fmt.Sprintf(`GROUPING SETS ( (%s), (%s) )`, strings.Join(withTs, ", "), strings.Join(tags, ", "))
- } else {
- return strings.Join(withTs, ", ")
- }
+ return strings.Join(withTs, ", ")
}
// GroupingSetsByAttributeKeyTags returns a string of comma separated tags for group by clause
diff --git a/pkg/query-service/app/metrics/v4/query_builder_test.go b/pkg/query-service/app/metrics/v4/query_builder_test.go
index 15e948520c..790fa670c8 100644
--- a/pkg/query-service/app/metrics/v4/query_builder_test.go
+++ b/pkg/query-service/app/metrics/v4/query_builder_test.go
@@ -193,7 +193,7 @@ func TestPrepareMetricQueryCumulativeRate(t *testing.T) {
TimeAggregation: v3.TimeAggregationRate,
SpaceAggregation: v3.SpaceAggregationSum,
},
- expectedQueryContains: "SELECT service_name, ts, sum(per_series_value) as value FROM (SELECT service_name, ts, If((per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) < 0, nan, If((ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window) >= 86400, nan, (per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window))) as per_series_value FROM (SELECT fingerprint, any(service_name) as service_name, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, max(value) as per_series_value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, fingerprint FROM signoz_metrics.time_series_v4_1day WHERE metric_name = 'signoz_calls_total' AND temporality = 'Cumulative' AND unix_milli >= 1650931200000 AND unix_milli < 1651078380000 AND like(JSONExtractString(labels, 'service_name'), '%frontend%')) as filtered_time_series USING fingerprint WHERE metric_name = 'signoz_calls_total' AND unix_milli >= 1650991920000 AND unix_milli < 1651078380000 GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window as (PARTITION BY fingerprint ORDER BY fingerprint, ts)) WHERE isNaN(per_series_value) = 0 GROUP BY GROUPING SETS ( (service_name, ts), (service_name) ) ORDER BY service_name ASC, ts ASC",
+ expectedQueryContains: "SELECT service_name, ts, sum(per_series_value) as value FROM (SELECT service_name, ts, If((per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) < 0, nan, If((ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window) >= 86400, nan, (per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window))) as per_series_value FROM (SELECT fingerprint, any(service_name) as service_name, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, max(value) as per_series_value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, fingerprint FROM signoz_metrics.time_series_v4_1day WHERE metric_name = 'signoz_calls_total' AND temporality = 'Cumulative' AND unix_milli >= 1650931200000 AND unix_milli < 1651078380000 AND like(JSONExtractString(labels, 'service_name'), '%frontend%')) as filtered_time_series USING fingerprint WHERE metric_name = 'signoz_calls_total' AND unix_milli >= 1650991920000 AND unix_milli < 1651078380000 GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window as (PARTITION BY fingerprint ORDER BY fingerprint, ts)) WHERE isNaN(per_series_value) = 0 GROUP BY service_name, ts ORDER BY service_name ASC, ts ASC",
},
{
name: "test time aggregation = rate, space aggregation = sum, temporality = cumulative, multiple group by",
@@ -226,7 +226,7 @@ func TestPrepareMetricQueryCumulativeRate(t *testing.T) {
TimeAggregation: v3.TimeAggregationRate,
SpaceAggregation: v3.SpaceAggregationSum,
},
- expectedQueryContains: "SELECT service_name, endpoint, ts, sum(per_series_value) as value FROM (SELECT service_name, endpoint, ts, If((per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) < 0, nan, If((ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window) >= 86400, nan, (per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window))) as per_series_value FROM (SELECT fingerprint, any(service_name) as service_name, any(endpoint) as endpoint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, max(value) as per_series_value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, JSONExtractString(labels, 'endpoint') as endpoint, fingerprint FROM signoz_metrics.time_series_v4_1day WHERE metric_name = 'signoz_calls_total' AND temporality = 'Cumulative' AND unix_milli >= 1650931200000 AND unix_milli < 1651078380000) as filtered_time_series USING fingerprint WHERE metric_name = 'signoz_calls_total' AND unix_milli >= 1650991920000 AND unix_milli < 1651078380000 GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window as (PARTITION BY fingerprint ORDER BY fingerprint, ts)) WHERE isNaN(per_series_value) = 0 GROUP BY GROUPING SETS ( (service_name, endpoint, ts), (service_name, endpoint) ) ORDER BY service_name ASC, endpoint ASC, ts ASC",
+ expectedQueryContains: "SELECT service_name, endpoint, ts, sum(per_series_value) as value FROM (SELECT service_name, endpoint, ts, If((per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) < 0, nan, If((ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window) >= 86400, nan, (per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window))) as per_series_value FROM (SELECT fingerprint, any(service_name) as service_name, any(endpoint) as endpoint, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, max(value) as per_series_value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, JSONExtractString(labels, 'endpoint') as endpoint, fingerprint FROM signoz_metrics.time_series_v4_1day WHERE metric_name = 'signoz_calls_total' AND temporality = 'Cumulative' AND unix_milli >= 1650931200000 AND unix_milli < 1651078380000) as filtered_time_series USING fingerprint WHERE metric_name = 'signoz_calls_total' AND unix_milli >= 1650991920000 AND unix_milli < 1651078380000 GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window as (PARTITION BY fingerprint ORDER BY fingerprint, ts)) WHERE isNaN(per_series_value) = 0 GROUP BY service_name, endpoint, ts ORDER BY service_name ASC, endpoint ASC, ts ASC",
},
}
@@ -292,7 +292,7 @@ func TestPrepareMetricQueryDeltaRate(t *testing.T) {
TimeAggregation: v3.TimeAggregationRate,
SpaceAggregation: v3.SpaceAggregationSum,
},
- expectedQueryContains: "SELECT service_name, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, sum(value)/60 as value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, fingerprint FROM signoz_metrics.time_series_v4_1day WHERE metric_name = 'signoz_calls_total' AND temporality = 'Delta' AND unix_milli >= 1650931200000 AND unix_milli < 1651078380000) as filtered_time_series USING fingerprint WHERE metric_name = 'signoz_calls_total' AND unix_milli >= 1650991920000 AND unix_milli < 1651078380000 GROUP BY GROUPING SETS ( (service_name, ts), (service_name) ) ORDER BY service_name ASC, ts ASC",
+ expectedQueryContains: "SELECT service_name, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, sum(value)/60 as value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, fingerprint FROM signoz_metrics.time_series_v4_1day WHERE metric_name = 'signoz_calls_total' AND temporality = 'Delta' AND unix_milli >= 1650931200000 AND unix_milli < 1651078380000) as filtered_time_series USING fingerprint WHERE metric_name = 'signoz_calls_total' AND unix_milli >= 1650991920000 AND unix_milli < 1651078380000 GROUP BY service_name, ts ORDER BY service_name ASC, ts ASC",
},
}
@@ -344,7 +344,7 @@ func TestPrepreMetricQueryCumulativeQuantile(t *testing.T) {
Disabled: false,
SpaceAggregation: v3.SpaceAggregationPercentile99,
},
- expectedQueryContains: "SELECT service_name, ts, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.990) as value FROM (SELECT service_name, le, ts, sum(per_series_value) as value FROM (SELECT service_name, le, ts, If((per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) < 0, nan, If((ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window) >= 86400, nan, (per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window))) as per_series_value FROM (SELECT fingerprint, any(service_name) as service_name, any(le) as le, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, max(value) as per_series_value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, JSONExtractString(labels, 'le') as le, fingerprint FROM signoz_metrics.time_series_v4_6hrs WHERE metric_name = 'signoz_latency_bucket' AND temporality = 'Cumulative' AND unix_milli >= 1650974400000 AND unix_milli < 1651078380000 AND like(JSONExtractString(labels, 'service_name'), '%frontend%')) as filtered_time_series USING fingerprint WHERE metric_name = 'signoz_latency_bucket' AND unix_milli >= 1650991980000 AND unix_milli < 1651078380000 GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window as (PARTITION BY fingerprint ORDER BY fingerprint, ts)) WHERE isNaN(per_series_value) = 0 GROUP BY GROUPING SETS ( (service_name, le, ts), (service_name, le) ) ORDER BY service_name ASC, le ASC, ts ASC) GROUP BY service_name, ts ORDER BY service_name ASC, ts ASC",
+ expectedQueryContains: "SELECT service_name, ts, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.990) as value FROM (SELECT service_name, le, ts, sum(per_series_value) as value FROM (SELECT service_name, le, ts, If((per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) < 0, nan, If((ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window) >= 86400, nan, (per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window))) as per_series_value FROM (SELECT fingerprint, any(service_name) as service_name, any(le) as le, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, max(value) as per_series_value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, JSONExtractString(labels, 'le') as le, fingerprint FROM signoz_metrics.time_series_v4_6hrs WHERE metric_name = 'signoz_latency_bucket' AND temporality = 'Cumulative' AND unix_milli >= 1650974400000 AND unix_milli < 1651078380000 AND like(JSONExtractString(labels, 'service_name'), '%frontend%')) as filtered_time_series USING fingerprint WHERE metric_name = 'signoz_latency_bucket' AND unix_milli >= 1650991980000 AND unix_milli < 1651078380000 GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window as (PARTITION BY fingerprint ORDER BY fingerprint, ts)) WHERE isNaN(per_series_value) = 0 GROUP BY service_name, le, ts ORDER BY service_name ASC, le ASC, ts ASC) GROUP BY service_name, ts ORDER BY service_name ASC, ts ASC",
},
{
name: "test temporality = cumulative, quantile = 0.99 without group by",
@@ -374,7 +374,7 @@ func TestPrepreMetricQueryCumulativeQuantile(t *testing.T) {
Disabled: false,
SpaceAggregation: v3.SpaceAggregationPercentile99,
},
- expectedQueryContains: "SELECT ts, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.990) as value FROM (SELECT le, ts, sum(per_series_value) as value FROM (SELECT le, ts, If((per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) < 0, nan, If((ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window) >= 86400, nan, (per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window))) as per_series_value FROM (SELECT fingerprint, any(le) as le, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, max(value) as per_series_value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'le') as le, fingerprint FROM signoz_metrics.time_series_v4_6hrs WHERE metric_name = 'signoz_latency_bucket' AND temporality = 'Cumulative' AND unix_milli >= 1650974400000 AND unix_milli < 1651078380000 AND like(JSONExtractString(labels, 'service_name'), '%frontend%')) as filtered_time_series USING fingerprint WHERE metric_name = 'signoz_latency_bucket' AND unix_milli >= 1650991980000 AND unix_milli < 1651078380000 GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window as (PARTITION BY fingerprint ORDER BY fingerprint, ts)) WHERE isNaN(per_series_value) = 0 GROUP BY GROUPING SETS ( (le, ts), (le) ) ORDER BY le ASC, ts ASC) GROUP BY ts ORDER BY ts ASC",
+ expectedQueryContains: "SELECT ts, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.990) as value FROM (SELECT le, ts, sum(per_series_value) as value FROM (SELECT le, ts, If((per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) < 0, nan, If((ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window) >= 86400, nan, (per_series_value - lagInFrame(per_series_value, 1, 0) OVER rate_window) / (ts - lagInFrame(ts, 1, toDate('1970-01-01')) OVER rate_window))) as per_series_value FROM (SELECT fingerprint, any(le) as le, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, max(value) as per_series_value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'le') as le, fingerprint FROM signoz_metrics.time_series_v4_6hrs WHERE metric_name = 'signoz_latency_bucket' AND temporality = 'Cumulative' AND unix_milli >= 1650974400000 AND unix_milli < 1651078380000 AND like(JSONExtractString(labels, 'service_name'), '%frontend%')) as filtered_time_series USING fingerprint WHERE metric_name = 'signoz_latency_bucket' AND unix_milli >= 1650991980000 AND unix_milli < 1651078380000 GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WINDOW rate_window as (PARTITION BY fingerprint ORDER BY fingerprint, ts)) WHERE isNaN(per_series_value) = 0 GROUP BY le, ts ORDER BY le ASC, ts ASC) GROUP BY ts ORDER BY ts ASC",
},
}
@@ -426,7 +426,7 @@ func TestPrepreMetricQueryDeltaQuantile(t *testing.T) {
Disabled: false,
SpaceAggregation: v3.SpaceAggregationPercentile99,
},
- expectedQueryContains: "SELECT service_name, ts, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.990) as value FROM (SELECT service_name, le, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, sum(value)/60 as value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, JSONExtractString(labels, 'le') as le, fingerprint FROM signoz_metrics.time_series_v4_6hrs WHERE metric_name = 'signoz_latency_bucket' AND temporality = 'Delta' AND unix_milli >= 1650974400000 AND unix_milli < 1651078380000 AND like(JSONExtractString(labels, 'service_name'), '%frontend%')) as filtered_time_series USING fingerprint WHERE metric_name = 'signoz_latency_bucket' AND unix_milli >= 1650991980000 AND unix_milli < 1651078380000 GROUP BY GROUPING SETS ( (service_name, le, ts), (service_name, le) ) ORDER BY service_name ASC, le ASC, ts ASC) GROUP BY service_name, ts ORDER BY service_name ASC, ts ASC",
+ expectedQueryContains: "SELECT service_name, ts, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.990) as value FROM (SELECT service_name, le, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, sum(value)/60 as value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'service_name') as service_name, JSONExtractString(labels, 'le') as le, fingerprint FROM signoz_metrics.time_series_v4_6hrs WHERE metric_name = 'signoz_latency_bucket' AND temporality = 'Delta' AND unix_milli >= 1650974400000 AND unix_milli < 1651078380000 AND like(JSONExtractString(labels, 'service_name'), '%frontend%')) as filtered_time_series USING fingerprint WHERE metric_name = 'signoz_latency_bucket' AND unix_milli >= 1650991980000 AND unix_milli < 1651078380000 GROUP BY service_name, le, ts ORDER BY service_name ASC, le ASC, ts ASC) GROUP BY service_name, ts ORDER BY service_name ASC, ts ASC",
},
{
name: "test temporality = delta, quantile = 0.99 no group by",
@@ -456,7 +456,7 @@ func TestPrepreMetricQueryDeltaQuantile(t *testing.T) {
Disabled: false,
SpaceAggregation: v3.SpaceAggregationPercentile99,
},
- expectedQueryContains: "SELECT ts, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.990) as value FROM (SELECT le, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, sum(value)/60 as value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'le') as le, fingerprint FROM signoz_metrics.time_series_v4_6hrs WHERE metric_name = 'signoz_latency_bucket' AND temporality = 'Delta' AND unix_milli >= 1650974400000 AND unix_milli < 1651078380000 AND like(JSONExtractString(labels, 'service_name'), '%frontend%')) as filtered_time_series USING fingerprint WHERE metric_name = 'signoz_latency_bucket' AND unix_milli >= 1650991980000 AND unix_milli < 1651078380000 GROUP BY GROUPING SETS ( (le, ts), (le) ) ORDER BY le ASC, ts ASC) GROUP BY ts ORDER BY ts ASC",
+ expectedQueryContains: "SELECT ts, histogramQuantile(arrayMap(x -> toFloat64(x), groupArray(le)), groupArray(value), 0.990) as value FROM (SELECT le, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, sum(value)/60 as value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'le') as le, fingerprint FROM signoz_metrics.time_series_v4_6hrs WHERE metric_name = 'signoz_latency_bucket' AND temporality = 'Delta' AND unix_milli >= 1650974400000 AND unix_milli < 1651078380000 AND like(JSONExtractString(labels, 'service_name'), '%frontend%')) as filtered_time_series USING fingerprint WHERE metric_name = 'signoz_latency_bucket' AND unix_milli >= 1650991980000 AND unix_milli < 1651078380000 GROUP BY le, ts ORDER BY le ASC, ts ASC) GROUP BY ts ORDER BY ts ASC",
},
}
@@ -520,7 +520,7 @@ func TestPrepareMetricQueryGauge(t *testing.T) {
Expression: "A",
Disabled: false,
},
- expectedQueryContains: "SELECT host_name, ts, sum(per_series_value) as value FROM (SELECT fingerprint, any(host_name) as host_name, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, avg(value) as per_series_value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'host_name') as host_name, fingerprint FROM signoz_metrics.time_series_v4_6hrs WHERE metric_name = 'system_cpu_usage' AND temporality = 'Unspecified' AND unix_milli >= 1650974400000 AND unix_milli < 1651078380000) as filtered_time_series USING fingerprint WHERE metric_name = 'system_cpu_usage' AND unix_milli >= 1650991980000 AND unix_milli < 1651078380000 GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WHERE isNaN(per_series_value) = 0 GROUP BY GROUPING SETS ( (host_name, ts), (host_name) ) ORDER BY host_name ASC, ts ASC",
+ expectedQueryContains: "SELECT host_name, ts, sum(per_series_value) as value FROM (SELECT fingerprint, any(host_name) as host_name, toStartOfInterval(toDateTime(intDiv(unix_milli, 1000)), INTERVAL 60 SECOND) as ts, avg(value) as per_series_value FROM signoz_metrics.distributed_samples_v4 INNER JOIN (SELECT DISTINCT JSONExtractString(labels, 'host_name') as host_name, fingerprint FROM signoz_metrics.time_series_v4_6hrs WHERE metric_name = 'system_cpu_usage' AND temporality = 'Unspecified' AND unix_milli >= 1650974400000 AND unix_milli < 1651078380000) as filtered_time_series USING fingerprint WHERE metric_name = 'system_cpu_usage' AND unix_milli >= 1650991980000 AND unix_milli < 1651078380000 GROUP BY fingerprint, ts ORDER BY fingerprint, ts) WHERE isNaN(per_series_value) = 0 GROUP BY host_name, ts ORDER BY host_name ASC, ts ASC",
},
}
diff --git a/pkg/query-service/app/parser.go b/pkg/query-service/app/parser.go
index 773156cc0d..679b7581aa 100644
--- a/pkg/query-service/app/parser.go
+++ b/pkg/query-service/app/parser.go
@@ -17,13 +17,15 @@ import (
promModel "github.com/prometheus/common/model"
"go.uber.org/multierr"
+ "go.signoz.io/signoz/ee/query-service/constants"
"go.signoz.io/signoz/pkg/query-service/app/metrics"
"go.signoz.io/signoz/pkg/query-service/app/queryBuilder"
"go.signoz.io/signoz/pkg/query-service/auth"
+ baseconstants "go.signoz.io/signoz/pkg/query-service/constants"
"go.signoz.io/signoz/pkg/query-service/common"
- "go.signoz.io/signoz/pkg/query-service/constants"
"go.signoz.io/signoz/pkg/query-service/model"
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
+ "go.signoz.io/signoz/pkg/query-service/postprocess"
"go.signoz.io/signoz/pkg/query-service/utils"
querytemplate "go.signoz.io/signoz/pkg/query-service/utils/queryTemplate"
)
@@ -249,28 +251,46 @@ func parseGetServicesRequest(r *http.Request) (*model.GetServicesParams, error)
return postData, nil
}
-func ParseSearchTracesParams(r *http.Request) (string, string, int, int, error) {
+func ParseSearchTracesParams(r *http.Request) (*model.SearchTracesParams, error) {
vars := mux.Vars(r)
- traceId := vars["traceId"]
- spanId := r.URL.Query().Get("spanId")
- levelUp := r.URL.Query().Get("levelUp")
- levelDown := r.URL.Query().Get("levelDown")
- if levelUp == "" || levelUp == "null" {
- levelUp = "0"
+ params := &model.SearchTracesParams{}
+ params.TraceID = vars["traceId"]
+ params.SpanID = r.URL.Query().Get("spanId")
+
+ levelUpStr := r.URL.Query().Get("levelUp")
+ levelDownStr := r.URL.Query().Get("levelDown")
+ SpanRenderLimitStr := r.URL.Query().Get("spanRenderLimit")
+ if levelUpStr == "" || levelUpStr == "null" {
+ levelUpStr = "0"
}
- if levelDown == "" || levelDown == "null" {
- levelDown = "0"
+ if levelDownStr == "" || levelDownStr == "null" {
+ levelDownStr = "0"
+ }
+ if SpanRenderLimitStr == "" || SpanRenderLimitStr == "null" {
+ SpanRenderLimitStr = constants.SpanRenderLimitStr
}
- levelUpInt, err := strconv.Atoi(levelUp)
+ levelUpInt, err := strconv.Atoi(levelUpStr)
if err != nil {
- return "", "", 0, 0, err
+ return nil, err
}
- levelDownInt, err := strconv.Atoi(levelDown)
+ levelDownInt, err := strconv.Atoi(levelDownStr)
if err != nil {
- return "", "", 0, 0, err
+ return nil, err
}
- return traceId, spanId, levelUpInt, levelDownInt, nil
+ SpanRenderLimitInt, err := strconv.Atoi(SpanRenderLimitStr)
+ if err != nil {
+ return nil, err
+ }
+ MaxSpansInTraceInt, err := strconv.Atoi(constants.MaxSpansInTraceStr)
+ if err != nil {
+ return nil, err
+ }
+ params.LevelUp = levelUpInt
+ params.LevelDown = levelDownInt
+ params.SpansRenderLimit = SpanRenderLimitInt
+ params.MaxSpansInTrace = MaxSpansInTraceInt
+ return params, nil
}
func DoesExistInSlice(item string, list []string) bool {
@@ -326,16 +346,16 @@ func parseFilteredSpansRequest(r *http.Request, aH *APIHandler) (*model.GetFilte
}
if len(postData.Order) != 0 {
- if postData.Order != constants.Ascending && postData.Order != constants.Descending {
+ if postData.Order != baseconstants.Ascending && postData.Order != baseconstants.Descending {
return nil, errors.New("order param is not in correct format")
}
- if postData.OrderParam != constants.Duration && postData.OrderParam != constants.Timestamp {
+ if postData.OrderParam != baseconstants.Duration && postData.OrderParam != baseconstants.Timestamp {
return nil, errors.New("order param is not in correct format")
}
- if postData.OrderParam == constants.Duration && !aH.CheckFeature(constants.DurationSort) {
- return nil, model.ErrFeatureUnavailable{Key: constants.DurationSort}
- } else if postData.OrderParam == constants.Timestamp && !aH.CheckFeature(constants.TimestampSort) {
- return nil, model.ErrFeatureUnavailable{Key: constants.TimestampSort}
+ if postData.OrderParam == baseconstants.Duration && !aH.CheckFeature(baseconstants.DurationSort) {
+ return nil, model.ErrFeatureUnavailable{Key: baseconstants.DurationSort}
+ } else if postData.OrderParam == baseconstants.Timestamp && !aH.CheckFeature(baseconstants.TimestampSort) {
+ return nil, model.ErrFeatureUnavailable{Key: baseconstants.TimestampSort}
}
}
tags, err := extractTagKeys(postData.Tags)
@@ -675,7 +695,7 @@ func parseTTLParams(r *http.Request) (*model.TTLParams, error) {
}
// Validate the type parameter
- if typeTTL != constants.TraceTTL && typeTTL != constants.MetricsTTL && typeTTL != constants.LogsTTL {
+ if typeTTL != baseconstants.TraceTTL && typeTTL != baseconstants.MetricsTTL && typeTTL != baseconstants.LogsTTL {
return nil, fmt.Errorf("type param should be metrics|traces|logs, got %v", typeTTL)
}
@@ -714,7 +734,7 @@ func parseGetTTL(r *http.Request) (*model.GetTTLParams, error) {
return nil, fmt.Errorf("type param cannot be empty from the query")
} else {
// Validate the type parameter
- if typeTTL != constants.TraceTTL && typeTTL != constants.MetricsTTL && typeTTL != constants.LogsTTL {
+ if typeTTL != baseconstants.TraceTTL && typeTTL != baseconstants.MetricsTTL && typeTTL != baseconstants.LogsTTL {
return nil, fmt.Errorf("type param should be metrics|traces|logs, got %v", typeTTL)
}
}
@@ -1007,7 +1027,7 @@ func ParseQueryRangeParams(r *http.Request) (*v3.QueryRangeParamsV3, *model.ApiE
// Formula query
// Check if the queries used in the expression can be joined
if query.QueryName != query.Expression {
- expression, err := govaluate.NewEvaluableExpressionWithFunctions(query.Expression, evalFuncs())
+ expression, err := govaluate.NewEvaluableExpressionWithFunctions(query.Expression, postprocess.EvalFuncs())
if err != nil {
return nil, &model.ApiError{Typ: model.ErrorBadData, Err: err}
}
@@ -1065,34 +1085,6 @@ func ParseQueryRangeParams(r *http.Request) (*v3.QueryRangeParamsV3, *model.ApiE
}
query.ShiftBy = timeShiftBy
- // for metrics v3
- // if the aggregate operator is a histogram quantile, and user has not forgotten
- // the le tag in the group by then add the le tag to the group by
- if query.AggregateOperator == v3.AggregateOperatorHistQuant50 ||
- query.AggregateOperator == v3.AggregateOperatorHistQuant75 ||
- query.AggregateOperator == v3.AggregateOperatorHistQuant90 ||
- query.AggregateOperator == v3.AggregateOperatorHistQuant95 ||
- query.AggregateOperator == v3.AggregateOperatorHistQuant99 {
- found := false
- for _, tag := range query.GroupBy {
- if tag.Key == "le" {
- found = true
- break
- }
- }
- if !found {
- query.GroupBy = append(
- query.GroupBy,
- v3.AttributeKey{
- Key: "le",
- DataType: v3.AttributeKeyDataTypeString,
- Type: v3.AttributeKeyTypeTag,
- IsColumn: false,
- },
- )
- }
- }
-
if query.Filters == nil || len(query.Filters.Items) == 0 {
continue
}
diff --git a/pkg/query-service/app/querier/querier.go b/pkg/query-service/app/querier/querier.go
index 1f68879d0c..d07ee4f60d 100644
--- a/pkg/query-service/app/querier/querier.go
+++ b/pkg/query-service/app/querier/querier.go
@@ -100,7 +100,7 @@ func (q *querier) execClickHouseQuery(ctx context.Context, query string) ([]*v3.
points := make([]v3.Point, 0)
for pointIdx := range series.Points {
point := series.Points[pointIdx]
- if point.Timestamp > 0 {
+ if point.Timestamp >= 0 {
points = append(points, point)
} else {
pointsWithNegativeTimestamps++
diff --git a/pkg/query-service/app/querier/v2/querier.go b/pkg/query-service/app/querier/v2/querier.go
index b3bf2c66f8..6754c03ddc 100644
--- a/pkg/query-service/app/querier/v2/querier.go
+++ b/pkg/query-service/app/querier/v2/querier.go
@@ -100,7 +100,7 @@ func (q *querier) execClickHouseQuery(ctx context.Context, query string) ([]*v3.
points := make([]v3.Point, 0)
for pointIdx := range series.Points {
point := series.Points[pointIdx]
- if point.Timestamp > 0 {
+ if point.Timestamp >= 0 {
points = append(points, point)
} else {
pointsWithNegativeTimestamps++
diff --git a/pkg/query-service/app/queryBuilder/query_builder.go b/pkg/query-service/app/queryBuilder/query_builder.go
index 693bc88f44..a3a957c985 100644
--- a/pkg/query-service/app/queryBuilder/query_builder.go
+++ b/pkg/query-service/app/queryBuilder/query_builder.go
@@ -384,6 +384,8 @@ func (c *cacheKeyGenerator) GenerateKeys(params *v3.QueryRangeParamsV3) map[stri
parts = append(parts, fmt.Sprintf("source=%s", query.DataSource))
parts = append(parts, fmt.Sprintf("step=%d", query.StepInterval))
parts = append(parts, fmt.Sprintf("aggregate=%s", query.AggregateOperator))
+ parts = append(parts, fmt.Sprintf("timeAggregation=%s", query.TimeAggregation))
+ parts = append(parts, fmt.Sprintf("spaceAggregation=%s", query.SpaceAggregation))
if query.AggregateAttribute.Key != "" {
parts = append(parts, fmt.Sprintf("aggregateAttribute=%s", query.AggregateAttribute.CacheKey()))
diff --git a/pkg/query-service/app/server.go b/pkg/query-service/app/server.go
index d28fd62666..773cd7218d 100644
--- a/pkg/query-service/app/server.go
+++ b/pkg/query-service/app/server.go
@@ -697,6 +697,7 @@ func makeRulesManager(
Logger: nil,
DisableRules: disableRules,
FeatureFlags: fm,
+ Reader: ch,
}
// create Manager
diff --git a/pkg/query-service/app/traces/v3/query_builder.go b/pkg/query-service/app/traces/v3/query_builder.go
index efbc4d8872..41f64548ad 100644
--- a/pkg/query-service/app/traces/v3/query_builder.go
+++ b/pkg/query-service/app/traces/v3/query_builder.go
@@ -174,7 +174,8 @@ func buildTracesFilterQuery(fs *v3.FilterSet, keys map[string]v3.AttributeKey) (
if operator, ok := tracesOperatorMappingV3[item.Operator]; ok {
switch item.Operator {
case v3.FilterOperatorContains, v3.FilterOperatorNotContains:
- conditions = append(conditions, fmt.Sprintf("%s %s '%%%s%%'", columnName, operator, item.Value))
+ val = utils.QuoteEscapedString(fmt.Sprintf("%v", item.Value))
+ conditions = append(conditions, fmt.Sprintf("%s %s '%%%s%%'", columnName, operator, val))
case v3.FilterOperatorRegex, v3.FilterOperatorNotRegex:
conditions = append(conditions, fmt.Sprintf(operator, columnName, fmtVal))
case v3.FilterOperatorExists, v3.FilterOperatorNotExists:
@@ -263,7 +264,7 @@ func buildTracesQuery(start, end, step int64, mq *v3.BuilderQuery, tableName str
queryTmpl =
"SELECT now() as ts,"
// step or aggregate interval is whole time period in case of table panel
- step = (end*getZerosForEpochNano(end) - start*getZerosForEpochNano(start))/1000000000
+ step = (end*getZerosForEpochNano(end) - start*getZerosForEpochNano(start)) / 1000000000
} else if panelType == v3.PanelTypeGraph || panelType == v3.PanelTypeValue {
// Select the aggregate value for interval
queryTmpl =
diff --git a/pkg/query-service/app/traces/v3/query_builder_test.go b/pkg/query-service/app/traces/v3/query_builder_test.go
index b4b1a2574c..cf4eb21cfe 100644
--- a/pkg/query-service/app/traces/v3/query_builder_test.go
+++ b/pkg/query-service/app/traces/v3/query_builder_test.go
@@ -100,6 +100,13 @@ var buildFilterQueryData = []struct {
}},
ExpectedFilter: " AND stringTagMap['host'] ILIKE '%102.%'",
},
+ {
+ Name: "Test contains with quotes",
+ FilterSet: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{
+ {Key: v3.AttributeKey{Key: "message", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Value: "Hello 'world'", Operator: "contains"},
+ }},
+ ExpectedFilter: " AND stringTagMap['message'] ILIKE '%Hello \\'world\\'%'",
+ },
{
Name: "Test not contains",
FilterSet: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{
diff --git a/pkg/query-service/constants/constants.go b/pkg/query-service/constants/constants.go
index 6e398a42e0..f44a8de353 100644
--- a/pkg/query-service/constants/constants.go
+++ b/pkg/query-service/constants/constants.go
@@ -154,11 +154,9 @@ const (
TraceID = "traceID"
ServiceName = "serviceName"
HttpRoute = "httpRoute"
- HttpCode = "httpCode"
HttpHost = "httpHost"
HttpUrl = "httpUrl"
HttpMethod = "httpMethod"
- Component = "component"
OperationDB = "name"
OperationRequest = "operation"
Status = "status"
@@ -193,7 +191,6 @@ var GroupByColMap = map[string]struct{}{
HttpRoute: {},
HttpUrl: {},
HttpMethod: {},
- Component: {},
OperationDB: {},
DBName: {},
DBOperation: {},
@@ -300,9 +297,11 @@ const (
// written clickhouse query. The column alias indcate which value is
// to be considered as final result (or target)
var ReservedColumnTargetAliases = map[string]struct{}{
- "result": {},
- "res": {},
- "value": {},
+ "__result": {},
+ "__value": {},
+ "result": {},
+ "res": {},
+ "value": {},
}
// logsPPLPfx is a short constant for logsPipelinePrefix
diff --git a/pkg/query-service/interfaces/interface.go b/pkg/query-service/interfaces/interface.go
index 4c89f6f793..a0631eb70a 100644
--- a/pkg/query-service/interfaces/interface.go
+++ b/pkg/query-service/interfaces/interface.go
@@ -52,7 +52,7 @@ type Reader interface {
GetNextPrevErrorIDs(ctx context.Context, params *model.GetErrorParams) (*model.NextPrevErrorIDs, *model.ApiError)
// Search Interfaces
- SearchTraces(ctx context.Context, traceID string, spanId string, levelUp int, levelDown int, spanLimit int, smartTraceAlgorithm func(payload []model.SearchSpanResponseItem, targetSpanId string, levelUp int, levelDown int, spanLimit int) ([]model.SearchSpansResult, error)) (*[]model.SearchSpansResult, error)
+ SearchTraces(ctx context.Context, params *model.SearchTracesParams, smartTraceAlgorithm func(payload []model.SearchSpanResponseItem, targetSpanId string, levelUp int, levelDown int, spanLimit int) ([]model.SearchSpansResult, error)) (*[]model.SearchSpansResult, error)
// Setter Interfaces
SetTTL(ctx context.Context, ttlParams *model.TTLParams) (*model.SetTTLResponseItem, *model.ApiError)
diff --git a/pkg/query-service/model/queryParams.go b/pkg/query-service/model/queryParams.go
index 4a24dba2b6..321f7417be 100644
--- a/pkg/query-service/model/queryParams.go
+++ b/pkg/query-service/model/queryParams.go
@@ -374,11 +374,9 @@ type GetFilteredSpansParams struct {
SpanKind string `json:"spanKind"`
Status []string `json:"status"`
HttpRoute []string `json:"httpRoute"`
- HttpCode []string `json:"httpCode"`
HttpUrl []string `json:"httpUrl"`
HttpHost []string `json:"httpHost"`
HttpMethod []string `json:"httpMethod"`
- Component []string `json:"component"`
RPCMethod []string `json:"rpcMethod"`
ResponseStatusCode []string `json:"responseStatusCode"`
StartStr string `json:"start"`
@@ -402,11 +400,9 @@ type GetFilteredSpanAggregatesParams struct {
SpanKind string `json:"spanKind"`
Status []string `json:"status"`
HttpRoute []string `json:"httpRoute"`
- HttpCode []string `json:"httpCode"`
HttpUrl []string `json:"httpUrl"`
HttpHost []string `json:"httpHost"`
HttpMethod []string `json:"httpMethod"`
- Component []string `json:"component"`
RPCMethod []string `json:"rpcMethod"`
ResponseStatusCode []string `json:"responseStatusCode"`
MinDuration string `json:"minDuration"`
@@ -424,17 +420,24 @@ type GetFilteredSpanAggregatesParams struct {
End *time.Time
}
+type SearchTracesParams struct {
+ TraceID string `json:"traceId"`
+ LevelUp int `json:"levelUp"`
+ LevelDown int `json:"levelDown"`
+ SpanID string `json:"spanId"`
+ SpansRenderLimit int `json:"spansRenderLimit"`
+ MaxSpansInTrace int `json:"maxSpansInTrace"`
+}
+
type SpanFilterParams struct {
TraceID []string `json:"traceID"`
Status []string `json:"status"`
ServiceName []string `json:"serviceName"`
SpanKind string `json:"spanKind"`
HttpRoute []string `json:"httpRoute"`
- HttpCode []string `json:"httpCode"`
HttpUrl []string `json:"httpUrl"`
HttpHost []string `json:"httpHost"`
HttpMethod []string `json:"httpMethod"`
- Component []string `json:"component"`
Operation []string `json:"operation"`
RPCMethod []string `json:"rpcMethod"`
ResponseStatusCode []string `json:"responseStatusCode"`
@@ -453,12 +456,10 @@ type TagFilterParams struct {
Status []string `json:"status"`
ServiceName []string `json:"serviceName"`
HttpRoute []string `json:"httpRoute"`
- HttpCode []string `json:"httpCode"`
SpanKind string `json:"spanKind"`
HttpUrl []string `json:"httpUrl"`
HttpHost []string `json:"httpHost"`
HttpMethod []string `json:"httpMethod"`
- Component []string `json:"component"`
Operation []string `json:"operation"`
RPCMethod []string `json:"rpcMethod"`
ResponseStatusCode []string `json:"responseStatusCode"`
diff --git a/pkg/query-service/model/response.go b/pkg/query-service/model/response.go
index 1f3970e0d4..7a3d948ebb 100644
--- a/pkg/query-service/model/response.go
+++ b/pkg/query-service/model/response.go
@@ -212,8 +212,9 @@ type ServiceOverviewItem struct {
}
type SearchSpansResult struct {
- Columns []string `json:"columns"`
- Events [][]interface{} `json:"events"`
+ Columns []string `json:"columns"`
+ Events [][]interface{} `json:"events"`
+ IsSubTree bool `json:"isSubTree"`
}
type GetFilterSpansResponseItem struct {
@@ -394,11 +395,6 @@ type DBResponseServiceName struct {
Count uint64 `ch:"count"`
}
-type DBResponseHttpCode struct {
- HttpCode string `ch:"httpCode"`
- Count uint64 `ch:"count"`
-}
-
type DBResponseHttpRoute struct {
HttpRoute string `ch:"httpRoute"`
Count uint64 `ch:"count"`
@@ -453,14 +449,12 @@ type SpanFiltersResponse struct {
Status map[string]uint64 `json:"status"`
Duration map[string]uint64 `json:"duration"`
Operation map[string]uint64 `json:"operation"`
- HttpCode map[string]uint64 `json:"httpCode"`
ResponseStatusCode map[string]uint64 `json:"responseStatusCode"`
RPCMethod map[string]uint64 `json:"rpcMethod"`
HttpUrl map[string]uint64 `json:"httpUrl"`
HttpMethod map[string]uint64 `json:"httpMethod"`
HttpRoute map[string]uint64 `json:"httpRoute"`
HttpHost map[string]uint64 `json:"httpHost"`
- Component map[string]uint64 `json:"component"`
}
type Error struct {
ExceptionType string `json:"exceptionType" ch:"exceptionType"`
diff --git a/pkg/query-service/model/v3/v3.go b/pkg/query-service/model/v3/v3.go
index d1f55d7bb0..731a1edcac 100644
--- a/pkg/query-service/model/v3/v3.go
+++ b/pkg/query-service/model/v3/v3.go
@@ -669,6 +669,34 @@ type BuilderQuery struct {
ShiftBy int64
}
+// CanDefaultZero returns true if the missing value can be substituted by zero
+// For example, for an aggregation window [Tx - Tx+1], with an aggregation operator `count`
+// The lack of data can always be interpreted as zero. No data for requests count = zero requests
+// This is true for all aggregations that have `count`ing involved.
+//
+// The same can't be true for others, `sum` of no values doesn't necessarily mean zero.
+// We can't decide whether or not should it be zero.
+func (b *BuilderQuery) CanDefaultZero() bool {
+ switch b.DataSource {
+ case DataSourceMetrics:
+ if b.AggregateOperator.IsRateOperator() ||
+ b.TimeAggregation.IsRateOperator() ||
+ b.AggregateOperator == AggregateOperatorCount ||
+ b.AggregateOperator == AggregateOperatorCountDistinct ||
+ b.TimeAggregation == TimeAggregationCount ||
+ b.TimeAggregation == TimeAggregationCountDistinct {
+ return true
+ }
+ case DataSourceTraces, DataSourceLogs:
+ if b.AggregateOperator.IsRateOperator() ||
+ b.AggregateOperator == AggregateOperatorCount ||
+ b.AggregateOperator == AggregateOperatorCountDistinct {
+ return true
+ }
+ }
+ return false
+}
+
func (b *BuilderQuery) Validate(panelType PanelType) error {
if b == nil {
return nil
@@ -961,10 +989,9 @@ type LogsLiveTailClient struct {
}
type Series struct {
- Labels map[string]string `json:"labels"`
- LabelsArray []map[string]string `json:"labelsArray"`
- Points []Point `json:"values"`
- GroupingSetsPoint *Point `json:"-"`
+ Labels map[string]string `json:"labels"`
+ LabelsArray []map[string]string `json:"labelsArray"`
+ Points []Point `json:"values"`
}
func (s *Series) SortPoints() {
diff --git a/pkg/query-service/app/formula.go b/pkg/query-service/postprocess/formula.go
similarity index 86%
rename from pkg/query-service/app/formula.go
rename to pkg/query-service/postprocess/formula.go
index f1f10e4499..6c800b47c4 100644
--- a/pkg/query-service/app/formula.go
+++ b/pkg/query-service/postprocess/formula.go
@@ -1,4 +1,4 @@
-package app
+package postprocess
import (
"fmt"
@@ -24,10 +24,13 @@ func isSubset(super, sub map[string]string) bool {
}
// Function to find unique label sets
-func findUniqueLabelSets(results []*v3.Result) []map[string]string {
+func findUniqueLabelSets(results []*v3.Result, queriesInExpression map[string]struct{}) []map[string]string {
allLabelSets := make([]map[string]string, 0)
// The size of the `results` small, It is the number of queries in the request
for _, result := range results {
+ if _, ok := queriesInExpression[result.QueryName]; !ok {
+ continue
+ }
// The size of the `result.Series` slice is usually small, It is the number of series in the query result.
// We will limit the number of series in the query result to order of 100-1000.
for _, series := range result.Series {
@@ -60,7 +63,12 @@ func findUniqueLabelSets(results []*v3.Result) []map[string]string {
}
// Function to join series on timestamp and calculate new values
-func joinAndCalculate(results []*v3.Result, uniqueLabelSet map[string]string, expression *govaluate.EvaluableExpression) (*v3.Series, error) {
+func joinAndCalculate(
+ results []*v3.Result,
+ uniqueLabelSet map[string]string,
+ expression *govaluate.EvaluableExpression,
+ canDefaultZero map[string]bool,
+) (*v3.Series, error) {
uniqueTimestamps := make(map[int64]struct{})
// map[queryName]map[timestamp]value
@@ -103,15 +111,31 @@ func joinAndCalculate(results []*v3.Result, uniqueLabelSet map[string]string, ex
for _, timestamp := range timestamps {
values := make(map[string]interface{})
for queryName, series := range seriesMap {
- values[queryName] = series[timestamp]
+ if _, ok := series[timestamp]; ok {
+ values[queryName] = series[timestamp]
+ }
}
// If the value is not present in the values map, set it to 0
for _, v := range expression.Vars() {
- if _, ok := values[v]; !ok {
+ if _, ok := values[v]; !ok && canDefaultZero[v] {
values[v] = 0
}
}
+
+ canEval := true
+
+ for _, v := range expression.Vars() {
+ if _, ok := values[v]; !ok {
+ canEval = false
+ }
+ }
+
+ if !canEval {
+ // not enough values for expression evaluation
+ continue
+ }
+
newValue, err := expression.Evaluate(values)
if err != nil {
return nil, err
@@ -136,16 +160,25 @@ func joinAndCalculate(results []*v3.Result, uniqueLabelSet map[string]string, ex
// 2. For each unique label set, find a series that matches the label set from each query result
// 3. Join the series on timestamp and calculate the new values
// 4. Return the new series
-func processResults(results []*v3.Result, expression *govaluate.EvaluableExpression) (*v3.Result, error) {
- uniqueLabelSets := findUniqueLabelSets(results)
+func processResults(
+ results []*v3.Result,
+ expression *govaluate.EvaluableExpression,
+ canDefaultZero map[string]bool,
+) (*v3.Result, error) {
+
+ queriesInExpression := make(map[string]struct{})
+ for _, v := range expression.Vars() {
+ queriesInExpression[v] = struct{}{}
+ }
+ uniqueLabelSets := findUniqueLabelSets(results, queriesInExpression)
newSeries := make([]*v3.Series, 0)
for _, labelSet := range uniqueLabelSets {
- series, err := joinAndCalculate(results, labelSet, expression)
+ series, err := joinAndCalculate(results, labelSet, expression, canDefaultZero)
if err != nil {
return nil, err
}
- if series != nil {
+ if series != nil && len(series.Points) != 0 {
labelsArray := make([]map[string]string, 0)
for k, v := range series.Labels {
labelsArray = append(labelsArray, map[string]string{k: v})
@@ -162,7 +195,7 @@ func processResults(results []*v3.Result, expression *govaluate.EvaluableExpress
var SupportedFunctions = []string{"exp", "log", "ln", "exp2", "log2", "exp10", "log10", "sqrt", "cbrt", "erf", "erfc", "lgamma", "tgamma", "sin", "cos", "tan", "asin", "acos", "atan", "degrees", "radians", "now", "toUnixTimestamp"}
-func evalFuncs() map[string]govaluate.ExpressionFunction {
+func EvalFuncs() map[string]govaluate.ExpressionFunction {
GoValuateFuncs := make(map[string]govaluate.ExpressionFunction)
// Returns e to the power of the given argument.
GoValuateFuncs["exp"] = func(args ...interface{}) (interface{}, error) {
@@ -249,20 +282,9 @@ func evalFuncs() map[string]govaluate.ExpressionFunction {
GoValuateFuncs["radians"] = func(args ...interface{}) (interface{}, error) {
return args[0].(float64) * math.Pi / 180, nil
}
-
+ // Returns the current Unix timestamp in seconds.
GoValuateFuncs["now"] = func(args ...interface{}) (interface{}, error) {
- return time.Now().Unix(), nil
- }
-
- GoValuateFuncs["toUnixTimestamp"] = func(args ...interface{}) (interface{}, error) {
- if len(args) != 1 {
- return nil, fmt.Errorf("toUnixTimestamp requires exactly one argument")
- }
- t, err := time.Parse(time.RFC3339, args[0].(string))
- if err != nil {
- return nil, err
- }
- return t.Unix(), nil
+ return float64(time.Now().Unix()), nil
}
return GoValuateFuncs
diff --git a/pkg/query-service/app/formula_test.go b/pkg/query-service/postprocess/formula_test.go
similarity index 83%
rename from pkg/query-service/app/formula_test.go
rename to pkg/query-service/postprocess/formula_test.go
index 365d794836..d80519b105 100644
--- a/pkg/query-service/app/formula_test.go
+++ b/pkg/query-service/postprocess/formula_test.go
@@ -1,4 +1,4 @@
-package app
+package postprocess
import (
"math"
@@ -11,9 +11,10 @@ import (
func TestFindUniqueLabelSets(t *testing.T) {
tests := []struct {
- name string
- result []*v3.Result
- want []map[string]string
+ name string
+ result []*v3.Result
+ want []map[string]string
+ queriesInExpression map[string]struct{}
}{
{
name: "test1",
@@ -40,6 +41,10 @@ func TestFindUniqueLabelSets(t *testing.T) {
},
},
},
+ queriesInExpression: map[string]struct{}{
+ "A": {},
+ "B": {},
+ },
want: []map[string]string{
{
"service_name": "frontend",
@@ -96,6 +101,12 @@ func TestFindUniqueLabelSets(t *testing.T) {
},
},
},
+ queriesInExpression: map[string]struct{}{
+ "A": {},
+ "B": {},
+ "C": {},
+ "D": {},
+ },
want: []map[string]string{
{
"service_name": "frontend",
@@ -122,6 +133,10 @@ func TestFindUniqueLabelSets(t *testing.T) {
Series: []*v3.Series{},
},
},
+ queriesInExpression: map[string]struct{}{
+ "A": {},
+ "B": {},
+ },
want: []map[string]string{},
},
{
@@ -160,6 +175,10 @@ func TestFindUniqueLabelSets(t *testing.T) {
},
},
},
+ queriesInExpression: map[string]struct{}{
+ "A": {},
+ "B": {},
+ },
want: []map[string]string{
{
"service_name": "frontend",
@@ -175,7 +194,7 @@ func TestFindUniqueLabelSets(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- got := findUniqueLabelSets(tt.result)
+ got := findUniqueLabelSets(tt.result, tt.queriesInExpression)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("findUniqueLabelSets() = %v, want %v\n", got, tt.want)
}
@@ -278,7 +297,11 @@ func TestProcessResults(t *testing.T) {
if err != nil {
t.Errorf("Error parsing expression: %v", err)
}
- got, err := processResults(tt.results, expression)
+ canDefaultZero := map[string]bool{
+ "A": true,
+ "B": true,
+ }
+ got, err := processResults(tt.results, expression, canDefaultZero)
if err != nil {
t.Errorf("Error processing results: %v", err)
}
@@ -438,7 +461,11 @@ func TestProcessResultsErrorRate(t *testing.T) {
if err != nil {
t.Errorf("Error parsing expression: %v", err)
}
- got, err := processResults(tt.results, expression)
+ canDefaultZero := map[string]bool{
+ "A": true,
+ "B": true,
+ }
+ got, err := processResults(tt.results, expression, canDefaultZero)
if err != nil {
t.Errorf("Error processing results: %v", err)
}
@@ -1557,7 +1584,12 @@ func TestFormula(t *testing.T) {
t.Errorf("Error parsing expression: %v", err)
return
}
- got, err := processResults(tt.results, expression)
+ canDefaultZero := map[string]bool{
+ "A": true,
+ "B": true,
+ "C": true,
+ }
+ got, err := processResults(tt.results, expression, canDefaultZero)
if err != nil {
t.Errorf("Error processing results: %v", err)
return
@@ -1581,3 +1613,224 @@ func TestFormula(t *testing.T) {
})
}
}
+
+func TestProcessResultsNoDefaultZero(t *testing.T) {
+ tests := []struct {
+ name string
+ results []*v3.Result
+ want *v3.Result
+ }{
+ {
+ name: "test1",
+ results: []*v3.Result{
+ {
+ QueryName: "A",
+ Series: []*v3.Series{
+ {
+ Labels: map[string]string{
+ "service_name": "frontend",
+ "operation": "GET /api",
+ },
+ Points: []v3.Point{
+ {
+ Timestamp: 1,
+ Value: 10,
+ },
+ {
+ Timestamp: 2,
+ Value: 20,
+ },
+ },
+ },
+ },
+ },
+ {
+ QueryName: "B",
+ Series: []*v3.Series{
+ {
+ Labels: map[string]string{
+ "service_name": "redis",
+ },
+ Points: []v3.Point{
+ {
+ Timestamp: 1,
+ Value: 30,
+ },
+ {
+ Timestamp: 3,
+ Value: 40,
+ },
+ },
+ },
+ },
+ },
+ },
+ want: &v3.Result{
+ Series: []*v3.Series{},
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ expression, err := govaluate.NewEvaluableExpression("A + B")
+ if err != nil {
+ t.Errorf("Error parsing expression: %v", err)
+ }
+ canDefaultZero := map[string]bool{
+ "A": false,
+ "B": false,
+ }
+ got, err := processResults(tt.results, expression, canDefaultZero)
+ if err != nil {
+ t.Errorf("Error processing results: %v", err)
+ }
+ if len(got.Series) != len(tt.want.Series) {
+ t.Errorf("processResults(): number of sereis - got = %v, want %v", len(got.Series), len(tt.want.Series))
+ }
+
+ for i := range got.Series {
+ if len(got.Series[i].Points) != len(tt.want.Series[i].Points) {
+ t.Errorf("processResults(): number of points - got = %v, want %v", got, tt.want)
+ }
+ for j := range got.Series[i].Points {
+ if got.Series[i].Points[j].Value != tt.want.Series[i].Points[j].Value {
+ t.Errorf("processResults(): got = %v, want %v", got.Series[i].Points[j].Value, tt.want.Series[i].Points[j].Value)
+ }
+ }
+ }
+ })
+ }
+}
+
+func TestProcessResultsMixedQueries(t *testing.T) {
+ tests := []struct {
+ name string
+ results []*v3.Result
+ want *v3.Result
+ }{
+ {
+ name: "test1",
+ results: []*v3.Result{
+ {
+ QueryName: "A",
+ Series: []*v3.Series{
+ {
+ Labels: map[string]string{
+ "service_name": "frontend",
+ "operation": "GET /api",
+ },
+ Points: []v3.Point{
+ {
+ Timestamp: 1,
+ Value: 10,
+ },
+ {
+ Timestamp: 2,
+ Value: 20,
+ },
+ },
+ },
+ },
+ },
+ {
+ QueryName: "B",
+ Series: []*v3.Series{
+ {
+ Labels: map[string]string{
+ "service_name": "frontend",
+ "operation": "GET /api",
+ },
+ Points: []v3.Point{
+ {
+ Timestamp: 1,
+ Value: 10,
+ },
+ {
+ Timestamp: 2,
+ Value: 20,
+ },
+ },
+ },
+ },
+ },
+ {
+ QueryName: "C",
+ Series: []*v3.Series{
+ {
+ Labels: map[string]string{
+ "service_name": "redis",
+ },
+ Points: []v3.Point{
+ {
+ Timestamp: 1,
+ Value: 30,
+ },
+ {
+ Timestamp: 2,
+ Value: 50,
+ },
+ {
+ Timestamp: 3,
+ Value: 45,
+ },
+ },
+ },
+ },
+ },
+ },
+ want: &v3.Result{
+ Series: []*v3.Series{
+ {
+ Labels: map[string]string{
+ "service_name": "frontend",
+ "operation": "GET /api",
+ },
+ Points: []v3.Point{
+ {
+ Timestamp: 1,
+ Value: 1,
+ },
+ {
+ Timestamp: 2,
+ Value: 1,
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ expression, err := govaluate.NewEvaluableExpression("A / B")
+ if err != nil {
+ t.Errorf("Error parsing expression: %v", err)
+ }
+ canDefaultZero := map[string]bool{
+ "A": true,
+ "B": true,
+ "C": true,
+ }
+ got, err := processResults(tt.results, expression, canDefaultZero)
+ if err != nil {
+ t.Errorf("Error processing results: %v", err)
+ }
+ if len(got.Series) != len(tt.want.Series) {
+ t.Errorf("processResults(): number of sereis - got = %v, want %v", len(got.Series), len(tt.want.Series))
+ }
+
+ for i := range got.Series {
+ if len(got.Series[i].Points) != len(tt.want.Series[i].Points) {
+ t.Errorf("processResults(): number of points - got = %v, want %v", got, tt.want)
+ }
+ for j := range got.Series[i].Points {
+ if got.Series[i].Points[j].Value != tt.want.Series[i].Points[j].Value {
+ t.Errorf("processResults(): got = %v, want %v", got.Series[i].Points[j].Value, tt.want.Series[i].Points[j].Value)
+ }
+ }
+ }
+ })
+ }
+}
diff --git a/pkg/query-service/app/having.go b/pkg/query-service/postprocess/having.go
similarity index 93%
rename from pkg/query-service/app/having.go
rename to pkg/query-service/postprocess/having.go
index b99471ef4e..a37ba70379 100644
--- a/pkg/query-service/app/having.go
+++ b/pkg/query-service/postprocess/having.go
@@ -1,4 +1,4 @@
-package app
+package postprocess
import (
"strings"
@@ -23,6 +23,10 @@ func applyHavingClause(result []*v3.Result, queryRangeParams *v3.QueryRangeParam
j--
}
}
+ if len(result.Series[i].Points) == 0 {
+ result.Series = append(result.Series[:i], result.Series[i+1:]...)
+ i--
+ }
}
}
}
diff --git a/pkg/query-service/app/having_test.go b/pkg/query-service/postprocess/having_test.go
similarity index 99%
rename from pkg/query-service/app/having_test.go
rename to pkg/query-service/postprocess/having_test.go
index 2eeafa1b65..e7e37095fb 100644
--- a/pkg/query-service/app/having_test.go
+++ b/pkg/query-service/postprocess/having_test.go
@@ -1,4 +1,4 @@
-package app
+package postprocess
import (
"testing"
diff --git a/pkg/query-service/app/limit.go b/pkg/query-service/postprocess/limit.go
similarity index 95%
rename from pkg/query-service/app/limit.go
rename to pkg/query-service/postprocess/limit.go
index 3ace3c687c..491c91da54 100644
--- a/pkg/query-service/app/limit.go
+++ b/pkg/query-service/postprocess/limit.go
@@ -1,4 +1,4 @@
-package app
+package postprocess
import (
"math"
@@ -9,8 +9,8 @@ import (
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
)
-// applyMetricLimit applies limit to the metrics query results
-func applyMetricLimit(results []*v3.Result, queryRangeParams *v3.QueryRangeParamsV3) {
+// ApplyMetricLimit applies limit to the metrics query results
+func ApplyMetricLimit(results []*v3.Result, queryRangeParams *v3.QueryRangeParamsV3) {
// apply limit if any for metrics
// use the grouping set points to apply the limit
diff --git a/pkg/query-service/app/limit_test.go b/pkg/query-service/postprocess/limit_test.go
similarity index 87%
rename from pkg/query-service/app/limit_test.go
rename to pkg/query-service/postprocess/limit_test.go
index d90d7b9417..3f5ffaf15e 100644
--- a/pkg/query-service/app/limit_test.go
+++ b/pkg/query-service/postprocess/limit_test.go
@@ -1,4 +1,4 @@
-package app
+package postprocess
import (
"testing"
@@ -34,10 +34,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 19.5,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 19.3,
- },
},
{
Labels: map[string]string{
@@ -53,10 +49,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 8.83,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 8.83,
- },
},
},
},
@@ -99,10 +91,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 19.5,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 19.3,
- },
},
},
},
@@ -128,10 +116,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 19.5,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 19.3,
- },
},
{
Labels: map[string]string{
@@ -147,10 +131,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 8.83,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 8.83,
- },
},
},
},
@@ -194,10 +174,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 8.83,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 8.83,
- },
},
},
},
@@ -223,10 +199,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 240,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 154.5,
- },
},
{
Labels: map[string]string{
@@ -242,10 +214,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 260,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 340,
- },
},
},
},
@@ -289,10 +257,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 240,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 154.5,
- },
},
{
Labels: map[string]string{
@@ -308,10 +272,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 260,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 340,
- },
},
},
},
@@ -339,10 +299,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 19.5,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 19.3,
- },
},
{
Labels: map[string]string{
@@ -359,10 +315,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 8.83,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 8.83,
- },
},
},
},
@@ -407,10 +359,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 8.83,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 8.83,
- },
},
},
},
@@ -439,10 +387,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 19.5,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 19.3,
- },
},
{
Labels: map[string]string{
@@ -461,10 +405,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 8.83,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 8.83,
- },
},
{
Labels: map[string]string{
@@ -483,10 +423,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 8.83,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 8.83,
- },
},
{
Labels: map[string]string{
@@ -505,10 +441,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 8.83,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 8.83,
- },
},
},
},
@@ -558,10 +490,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 19.5,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 19.3,
- },
},
{
Labels: map[string]string{
@@ -580,10 +508,6 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
Value: 8.83,
},
},
- GroupingSetsPoint: &v3.Point{
- Timestamp: 0,
- Value: 8.83,
- },
},
},
},
@@ -594,7 +518,7 @@ func TestApplyLimitOnMetricResult(t *testing.T) {
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
result := c.inputResult
- applyMetricLimit(result, c.params)
+ ApplyMetricLimit(result, c.params)
if len(result) != len(c.expectedResult) {
t.Errorf("expected result length: %d, but got: %d", len(c.expectedResult), len(result))
}
diff --git a/pkg/query-service/postprocess/query_range.go b/pkg/query-service/postprocess/query_range.go
new file mode 100644
index 0000000000..b6bd6461f3
--- /dev/null
+++ b/pkg/query-service/postprocess/query_range.go
@@ -0,0 +1,116 @@
+package postprocess
+
+import (
+ "github.com/SigNoz/govaluate"
+ "go.signoz.io/signoz/pkg/query-service/app/queryBuilder"
+ v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
+ "go.uber.org/zap"
+)
+
+// postProcessResult applies having clause, metric limit, reduce function to the result
+// This function is effective for metrics data source for now, but it can be extended to other data sources
+// if needed
+// Much of this work can be done in the ClickHouse query, but we decided to do it here because:
+// 1. Effective use of caching
+// 2. Easier to add new functions
+func PostProcessResult(result []*v3.Result, queryRangeParams *v3.QueryRangeParamsV3) ([]*v3.Result, error) {
+ // Having clause is not part of the clickhouse query, so we need to apply it here
+ // It's not included in the query because it doesn't work nicely with caching
+ // With this change, if you have a query with a having clause, and then you change the having clause
+ // to something else, the query will still be cached.
+ applyHavingClause(result, queryRangeParams)
+ // We apply the metric limit here because it's not part of the clickhouse query
+ // The limit in the context of the time series query is the number of time series
+ // So for the limit to work, we need to know what series to keep and what to discard
+ // For us to know that, we need to execute the query first, and then apply the limit
+ // which we found expensive, because we are executing the query twice on the same data
+ // So we decided to apply the limit here, after the query is executed
+ // The function is named applyMetricLimit because it only applies to metrics data source
+ // In traces and logs, the limit is achieved using subqueries
+ ApplyMetricLimit(result, queryRangeParams)
+ // Each series in the result produces N number of points, where N is (end - start) / step
+ // For the panel type table, we need to show one point for each series in the row
+ // We do that by applying a reduce function to each series
+ applyReduceTo(result, queryRangeParams)
+ // We apply the functions here it's easier to add new functions
+ ApplyFunctions(result, queryRangeParams)
+
+ // expressions are executed at query serivce so the value of time.now in the invdividual
+ // queries will be different so for table panel we are making it same.
+ if queryRangeParams.CompositeQuery.PanelType == v3.PanelTypeTable {
+ tablePanelResultProcessor(result)
+ }
+
+ canDefaultZero := make(map[string]bool)
+
+ for _, query := range queryRangeParams.CompositeQuery.BuilderQueries {
+ canDefaultZero[query.QueryName] = query.CanDefaultZero()
+ }
+
+ for _, query := range queryRangeParams.CompositeQuery.BuilderQueries {
+ // The way we distinguish between a formula and a query is by checking if the expression
+ // is the same as the query name
+ // TODO(srikanthccv): Update the UI to send a flag to distinguish between a formula and a query
+ if query.Expression != query.QueryName {
+ expression, err := govaluate.NewEvaluableExpressionWithFunctions(query.Expression, EvalFuncs())
+ // This shouldn't happen here, because it should have been caught earlier in validation
+ if err != nil {
+ zap.L().Error("error in expression", zap.Error(err))
+ return nil, err
+ }
+ formulaResult, err := processResults(result, expression, canDefaultZero)
+ if err != nil {
+ zap.L().Error("error in expression", zap.Error(err))
+ return nil, err
+ }
+ formulaResult.QueryName = query.QueryName
+ result = append(result, formulaResult)
+ }
+ }
+ // we are done with the formula calculations, only send the results for enabled queries
+ removeDisabledQueries := func(result []*v3.Result) []*v3.Result {
+ var newResult []*v3.Result
+ for _, res := range result {
+ if queryRangeParams.CompositeQuery.BuilderQueries[res.QueryName].Disabled {
+ continue
+ }
+ newResult = append(newResult, res)
+ }
+ return newResult
+ }
+ if queryRangeParams.CompositeQuery.QueryType == v3.QueryTypeBuilder {
+ result = removeDisabledQueries(result)
+ }
+ return result, nil
+}
+
+// ApplyFunctions applies functions for each query in the composite query
+// The functions can be more than one, and they are applied in the order they are defined
+func ApplyFunctions(results []*v3.Result, queryRangeParams *v3.QueryRangeParamsV3) {
+ for idx, result := range results {
+ builderQueries := queryRangeParams.CompositeQuery.BuilderQueries
+
+ if builderQueries != nil {
+ functions := builderQueries[result.QueryName].Functions
+
+ for _, function := range functions {
+ results[idx] = queryBuilder.ApplyFunction(function, result)
+ }
+ }
+ }
+}
+
+func tablePanelResultProcessor(results []*v3.Result) {
+ var ts int64
+ for ridx := range results {
+ for sidx := range results[ridx].Series {
+ for pidx := range results[ridx].Series[sidx].Points {
+ if ts == 0 {
+ ts = results[ridx].Series[sidx].Points[pidx].Timestamp
+ } else {
+ results[ridx].Series[sidx].Points[pidx].Timestamp = ts
+ }
+ }
+ }
+ }
+}
diff --git a/pkg/query-service/app/reduce_to.go b/pkg/query-service/postprocess/reduce_to.go
similarity index 99%
rename from pkg/query-service/app/reduce_to.go
rename to pkg/query-service/postprocess/reduce_to.go
index 26c60d07c6..2e9275eea8 100644
--- a/pkg/query-service/app/reduce_to.go
+++ b/pkg/query-service/postprocess/reduce_to.go
@@ -1,4 +1,4 @@
-package app
+package postprocess
import (
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
diff --git a/pkg/query-service/app/reduce_to_test.go b/pkg/query-service/postprocess/reduce_to_test.go
similarity index 98%
rename from pkg/query-service/app/reduce_to_test.go
rename to pkg/query-service/postprocess/reduce_to_test.go
index 1f5a16d65b..8709766850 100644
--- a/pkg/query-service/app/reduce_to_test.go
+++ b/pkg/query-service/postprocess/reduce_to_test.go
@@ -1,4 +1,4 @@
-package app
+package postprocess
import (
"testing"
diff --git a/pkg/query-service/rules/db.go b/pkg/query-service/rules/db.go
index 23372ce911..abf584a375 100644
--- a/pkg/query-service/rules/db.go
+++ b/pkg/query-service/rules/db.go
@@ -7,6 +7,7 @@ import (
"time"
"github.com/jmoiron/sqlx"
+ "go.signoz.io/signoz/pkg/query-service/auth"
"go.signoz.io/signoz/pkg/query-service/common"
"go.uber.org/zap"
)
@@ -27,6 +28,21 @@ type RuleDB interface {
// GetStoredRule for a given ID from DB
GetStoredRule(ctx context.Context, id string) (*StoredRule, error)
+
+ // CreatePlannedMaintenance stores a given maintenance in db
+ CreatePlannedMaintenance(ctx context.Context, maintenance PlannedMaintenance) (int64, error)
+
+ // DeletePlannedMaintenance deletes the given maintenance in the db
+ DeletePlannedMaintenance(ctx context.Context, id string) (string, error)
+
+ // GetPlannedMaintenanceByID fetches the maintenance definition from db by id
+ GetPlannedMaintenanceByID(ctx context.Context, id string) (*PlannedMaintenance, error)
+
+ // EditPlannedMaintenance updates the given maintenance in the db
+ EditPlannedMaintenance(ctx context.Context, maintenance PlannedMaintenance, id string) (string, error)
+
+ // GetAllPlannedMaintenance fetches the maintenance definitions from db
+ GetAllPlannedMaintenance(ctx context.Context) ([]PlannedMaintenance, error)
}
type StoredRule struct {
@@ -202,3 +218,80 @@ func (r *ruleDB) GetStoredRule(ctx context.Context, id string) (*StoredRule, err
return rule, nil
}
+
+func (r *ruleDB) GetAllPlannedMaintenance(ctx context.Context) ([]PlannedMaintenance, error) {
+ maintenances := []PlannedMaintenance{}
+
+ query := "SELECT id, name, description, schedule, alert_ids, created_at, created_by, updated_at, updated_by FROM planned_maintenance"
+
+ err := r.Select(&maintenances, query)
+
+ if err != nil {
+ zap.L().Error("Error in processing sql query", zap.Error(err))
+ return nil, err
+ }
+
+ return maintenances, nil
+}
+
+func (r *ruleDB) GetPlannedMaintenanceByID(ctx context.Context, id string) (*PlannedMaintenance, error) {
+ maintenance := &PlannedMaintenance{}
+
+ query := "SELECT id, name, description, schedule, alert_ids, created_at, created_by, updated_at, updated_by FROM planned_maintenance WHERE id=$1"
+ err := r.Get(maintenance, query, id)
+
+ if err != nil {
+ zap.L().Error("Error in processing sql query", zap.Error(err))
+ return nil, err
+ }
+
+ return maintenance, nil
+}
+
+func (r *ruleDB) CreatePlannedMaintenance(ctx context.Context, maintenance PlannedMaintenance) (int64, error) {
+
+ email, _ := auth.GetEmailFromJwt(ctx)
+ maintenance.CreatedBy = email
+ maintenance.CreatedAt = time.Now()
+ maintenance.UpdatedBy = email
+ maintenance.UpdatedAt = time.Now()
+
+ query := "INSERT INTO planned_maintenance (name, description, schedule, alert_ids, created_at, created_by, updated_at, updated_by) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)"
+
+ result, err := r.Exec(query, maintenance.Name, maintenance.Description, maintenance.Schedule, maintenance.AlertIds, maintenance.CreatedAt, maintenance.CreatedBy, maintenance.UpdatedAt, maintenance.UpdatedBy)
+
+ if err != nil {
+ zap.L().Error("Error in processing sql query", zap.Error(err))
+ return 0, err
+ }
+
+ return result.LastInsertId()
+}
+
+func (r *ruleDB) DeletePlannedMaintenance(ctx context.Context, id string) (string, error) {
+ query := "DELETE FROM planned_maintenance WHERE id=$1"
+ _, err := r.Exec(query, id)
+
+ if err != nil {
+ zap.L().Error("Error in processing sql query", zap.Error(err))
+ return "", err
+ }
+
+ return "", nil
+}
+
+func (r *ruleDB) EditPlannedMaintenance(ctx context.Context, maintenance PlannedMaintenance, id string) (string, error) {
+ email, _ := auth.GetEmailFromJwt(ctx)
+ maintenance.UpdatedBy = email
+ maintenance.UpdatedAt = time.Now()
+
+ query := "UPDATE planned_maintenance SET name=$1, description=$2, schedule=$3, alert_ids=$4, updated_at=$5, updated_by=$6 WHERE id=$7"
+ _, err := r.Exec(query, maintenance.Name, maintenance.Description, maintenance.Schedule, maintenance.AlertIds, maintenance.UpdatedAt, maintenance.UpdatedBy, id)
+
+ if err != nil {
+ zap.L().Error("Error in processing sql query", zap.Error(err))
+ return "", err
+ }
+
+ return "", nil
+}
diff --git a/pkg/query-service/rules/maintenance.go b/pkg/query-service/rules/maintenance.go
new file mode 100644
index 0000000000..014e8ac669
--- /dev/null
+++ b/pkg/query-service/rules/maintenance.go
@@ -0,0 +1,423 @@
+package rules
+
+import (
+ "database/sql/driver"
+ "encoding/json"
+ "slices"
+ "strings"
+ "time"
+
+ "github.com/pkg/errors"
+ "go.uber.org/zap"
+)
+
+var (
+ ErrMissingName = errors.New("missing name")
+ ErrMissingSchedule = errors.New("missing schedule")
+ ErrMissingTimezone = errors.New("missing timezone")
+ ErrMissingRepeatType = errors.New("missing repeat type")
+ ErrMissingDuration = errors.New("missing duration")
+)
+
+type PlannedMaintenance struct {
+ Id int64 `json:"id" db:"id"`
+ Name string `json:"name" db:"name"`
+ Description string `json:"description" db:"description"`
+ Schedule *Schedule `json:"schedule" db:"schedule"`
+ AlertIds *AlertIds `json:"alertIds" db:"alert_ids"`
+ CreatedAt time.Time `json:"createdAt" db:"created_at"`
+ CreatedBy string `json:"createdBy" db:"created_by"`
+ UpdatedAt time.Time `json:"updatedAt" db:"updated_at"`
+ UpdatedBy string `json:"updatedBy" db:"updated_by"`
+ Status string `json:"status"`
+ Kind string `json:"kind"`
+}
+
+type AlertIds []string
+
+func (a *AlertIds) Scan(src interface{}) error {
+ if data, ok := src.([]byte); ok {
+ return json.Unmarshal(data, a)
+ }
+ return nil
+}
+
+func (a *AlertIds) Value() (driver.Value, error) {
+ return json.Marshal(a)
+}
+
+type Schedule struct {
+ Timezone string `json:"timezone"`
+ StartTime time.Time `json:"startTime,omitempty"`
+ EndTime time.Time `json:"endTime,omitempty"`
+ Recurrence *Recurrence `json:"recurrence"`
+}
+
+func (s *Schedule) Scan(src interface{}) error {
+ if data, ok := src.([]byte); ok {
+ return json.Unmarshal(data, s)
+ }
+ return nil
+}
+
+func (s *Schedule) Value() (driver.Value, error) {
+ return json.Marshal(s)
+}
+
+type RepeatType string
+
+const (
+ RepeatTypeDaily RepeatType = "daily"
+ RepeatTypeWeekly RepeatType = "weekly"
+ RepeatTypeMonthly RepeatType = "monthly"
+)
+
+type RepeatOn string
+
+const (
+ RepeatOnSunday RepeatOn = "sunday"
+ RepeatOnMonday RepeatOn = "monday"
+ RepeatOnTuesday RepeatOn = "tuesday"
+ RepeatOnWednesday RepeatOn = "wednesday"
+ RepeatOnThursday RepeatOn = "thursday"
+ RepeatOnFriday RepeatOn = "friday"
+ RepeatOnSaturday RepeatOn = "saturday"
+)
+
+type Recurrence struct {
+ StartTime time.Time `json:"startTime"`
+ EndTime *time.Time `json:"endTime,omitempty"`
+ Duration Duration `json:"duration"`
+ RepeatType RepeatType `json:"repeatType"`
+ RepeatOn []RepeatOn `json:"repeatOn"`
+}
+
+func (r *Recurrence) Scan(src interface{}) error {
+ if data, ok := src.([]byte); ok {
+ return json.Unmarshal(data, r)
+ }
+ return nil
+}
+
+func (r *Recurrence) Value() (driver.Value, error) {
+ return json.Marshal(r)
+}
+
+func (s Schedule) MarshalJSON() ([]byte, error) {
+ loc, err := time.LoadLocation(s.Timezone)
+ if err != nil {
+ return nil, err
+ }
+
+ var startTime, endTime time.Time
+ if !s.StartTime.IsZero() {
+ startTime = time.Date(s.StartTime.Year(), s.StartTime.Month(), s.StartTime.Day(), s.StartTime.Hour(), s.StartTime.Minute(), s.StartTime.Second(), s.StartTime.Nanosecond(), loc)
+ }
+ if !s.EndTime.IsZero() {
+ endTime = time.Date(s.EndTime.Year(), s.EndTime.Month(), s.EndTime.Day(), s.EndTime.Hour(), s.EndTime.Minute(), s.EndTime.Second(), s.EndTime.Nanosecond(), loc)
+ }
+
+ var recurrence *Recurrence
+ if s.Recurrence != nil {
+ recStartTime := time.Date(s.Recurrence.StartTime.Year(), s.Recurrence.StartTime.Month(), s.Recurrence.StartTime.Day(), s.Recurrence.StartTime.Hour(), s.Recurrence.StartTime.Minute(), s.Recurrence.StartTime.Second(), s.Recurrence.StartTime.Nanosecond(), loc)
+ var recEndTime *time.Time
+ if s.Recurrence.EndTime != nil {
+ end := time.Date(s.Recurrence.EndTime.Year(), s.Recurrence.EndTime.Month(), s.Recurrence.EndTime.Day(), s.Recurrence.EndTime.Hour(), s.Recurrence.EndTime.Minute(), s.Recurrence.EndTime.Second(), s.Recurrence.EndTime.Nanosecond(), loc)
+ recEndTime = &end
+ }
+ recurrence = &Recurrence{
+ StartTime: recStartTime,
+ EndTime: recEndTime,
+ Duration: s.Recurrence.Duration,
+ RepeatType: s.Recurrence.RepeatType,
+ RepeatOn: s.Recurrence.RepeatOn,
+ }
+ }
+
+ return json.Marshal(&struct {
+ Timezone string `json:"timezone"`
+ StartTime string `json:"startTime"`
+ EndTime string `json:"endTime"`
+ Recurrence *Recurrence `json:"recurrence,omitempty"`
+ }{
+ Timezone: s.Timezone,
+ StartTime: startTime.Format(time.RFC3339),
+ EndTime: endTime.Format(time.RFC3339),
+ Recurrence: recurrence,
+ })
+}
+
+func (s *Schedule) UnmarshalJSON(data []byte) error {
+ aux := &struct {
+ Timezone string `json:"timezone"`
+ StartTime string `json:"startTime"`
+ EndTime string `json:"endTime"`
+ Recurrence *Recurrence `json:"recurrence,omitempty"`
+ }{}
+ if err := json.Unmarshal(data, aux); err != nil {
+ return err
+ }
+
+ loc, err := time.LoadLocation(aux.Timezone)
+ if err != nil {
+ return err
+ }
+
+ var startTime time.Time
+ if aux.StartTime != "" {
+ startTime, err = time.Parse(time.RFC3339, aux.StartTime)
+ if err != nil {
+ return err
+ }
+ s.StartTime = time.Date(startTime.Year(), startTime.Month(), startTime.Day(), startTime.Hour(), startTime.Minute(), startTime.Second(), startTime.Nanosecond(), loc)
+ }
+
+ var endTime time.Time
+ if aux.EndTime != "" {
+ endTime, err = time.Parse(time.RFC3339, aux.EndTime)
+ if err != nil {
+ return err
+ }
+ s.EndTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), endTime.Hour(), endTime.Minute(), endTime.Second(), endTime.Nanosecond(), loc)
+ }
+
+ s.Timezone = aux.Timezone
+
+ if aux.Recurrence != nil {
+ recStartTime, err := time.Parse(time.RFC3339, aux.Recurrence.StartTime.Format(time.RFC3339))
+ if err != nil {
+ return err
+ }
+
+ var recEndTime *time.Time
+ if aux.Recurrence.EndTime != nil {
+ end, err := time.Parse(time.RFC3339, aux.Recurrence.EndTime.Format(time.RFC3339))
+ if err != nil {
+ return err
+ }
+ endConverted := time.Date(end.Year(), end.Month(), end.Day(), end.Hour(), end.Minute(), end.Second(), end.Nanosecond(), loc)
+ recEndTime = &endConverted
+ }
+
+ s.Recurrence = &Recurrence{
+ StartTime: time.Date(recStartTime.Year(), recStartTime.Month(), recStartTime.Day(), recStartTime.Hour(), recStartTime.Minute(), recStartTime.Second(), recStartTime.Nanosecond(), loc),
+ EndTime: recEndTime,
+ Duration: aux.Recurrence.Duration,
+ RepeatType: aux.Recurrence.RepeatType,
+ RepeatOn: aux.Recurrence.RepeatOn,
+ }
+ }
+ return nil
+}
+
+func (m *PlannedMaintenance) shouldSkip(ruleID string, now time.Time) bool {
+
+ found := false
+ if m.AlertIds != nil {
+ for _, alertID := range *m.AlertIds {
+ if alertID == ruleID {
+ found = true
+ break
+ }
+ }
+ }
+
+ // If no alert ids, then skip all alerts
+ if m.AlertIds == nil || len(*m.AlertIds) == 0 {
+ found = true
+ }
+
+ if found {
+
+ zap.L().Info("alert found in maintenance", zap.String("alert", ruleID), zap.Any("maintenance", m.Name))
+
+ // If alert is found, we check if it should be skipped based on the schedule
+ // If it should be skipped, we return true
+ // If it should not be skipped, we return false
+
+ // fixed schedule
+ if !m.Schedule.StartTime.IsZero() && !m.Schedule.EndTime.IsZero() {
+ // if the current time in the timezone is between the start and end time
+ loc, err := time.LoadLocation(m.Schedule.Timezone)
+ if err != nil {
+ zap.L().Error("Error loading location", zap.String("timezone", m.Schedule.Timezone), zap.Error(err))
+ return false
+ }
+
+ currentTime := now.In(loc)
+ zap.L().Info("checking fixed schedule", zap.Any("rule", ruleID), zap.String("maintenance", m.Name), zap.Time("currentTime", currentTime), zap.Time("startTime", m.Schedule.StartTime), zap.Time("endTime", m.Schedule.EndTime))
+ if currentTime.After(m.Schedule.StartTime) && currentTime.Before(m.Schedule.EndTime) {
+ return true
+ }
+ }
+
+ // recurring schedule
+ if m.Schedule.Recurrence != nil {
+ zap.L().Info("evaluating recurrence schedule")
+ start := m.Schedule.Recurrence.StartTime
+ end := m.Schedule.Recurrence.StartTime.Add(time.Duration(m.Schedule.Recurrence.Duration))
+ // if the current time in the timezone is between the start and end time
+ loc, err := time.LoadLocation(m.Schedule.Timezone)
+ if err != nil {
+ zap.L().Error("Error loading location", zap.String("timezone", m.Schedule.Timezone), zap.Error(err))
+ return false
+ }
+ currentTime := now.In(loc)
+
+ zap.L().Info("checking recurring schedule", zap.Any("rule", ruleID), zap.String("maintenance", m.Name), zap.Time("currentTime", currentTime), zap.Time("startTime", start), zap.Time("endTime", end))
+
+ // make sure the start time is not after the current time
+ if currentTime.Before(start.In(loc)) {
+ zap.L().Info("current time is before start time", zap.Any("rule", ruleID), zap.String("maintenance", m.Name), zap.Time("currentTime", currentTime), zap.Time("startTime", start.In(loc)))
+ return false
+ }
+
+ var endTime time.Time
+ if m.Schedule.Recurrence.EndTime != nil {
+ endTime = *m.Schedule.Recurrence.EndTime
+ }
+ if !endTime.IsZero() && currentTime.After(endTime.In(loc)) {
+ zap.L().Info("current time is after end time", zap.Any("rule", ruleID), zap.String("maintenance", m.Name), zap.Time("currentTime", currentTime), zap.Time("endTime", end.In(loc)))
+ return false
+ }
+
+ switch m.Schedule.Recurrence.RepeatType {
+ case RepeatTypeDaily:
+ // take the hours and minutes from the start time and add them to the current time
+ startTime := time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), start.Hour(), start.Minute(), 0, 0, loc)
+ endTime := time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), end.Hour(), end.Minute(), 0, 0, loc)
+ zap.L().Info("checking daily schedule", zap.Any("rule", ruleID), zap.String("maintenance", m.Name), zap.Time("currentTime", currentTime), zap.Time("startTime", startTime), zap.Time("endTime", endTime))
+
+ if currentTime.After(startTime) && currentTime.Before(endTime) {
+ return true
+ }
+ case RepeatTypeWeekly:
+ // if the current time in the timezone is between the start and end time on the RepeatOn day
+ startTime := time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), start.Hour(), start.Minute(), 0, 0, loc)
+ endTime := time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), end.Hour(), end.Minute(), 0, 0, loc)
+ zap.L().Info("checking weekly schedule", zap.Any("rule", ruleID), zap.String("maintenance", m.Name), zap.Time("currentTime", currentTime), zap.Time("startTime", startTime), zap.Time("endTime", endTime))
+ if currentTime.After(startTime) && currentTime.Before(endTime) {
+ if len(m.Schedule.Recurrence.RepeatOn) == 0 {
+ return true
+ } else if slices.Contains(m.Schedule.Recurrence.RepeatOn, RepeatOn(strings.ToLower(currentTime.Weekday().String()))) {
+ return true
+ }
+ }
+ case RepeatTypeMonthly:
+ // if the current time in the timezone is between the start and end time on the day of the current month
+ startTime := time.Date(currentTime.Year(), currentTime.Month(), start.Day(), start.Hour(), start.Minute(), 0, 0, loc)
+ endTime := time.Date(currentTime.Year(), currentTime.Month(), end.Day(), end.Hour(), end.Minute(), 0, 0, loc)
+ zap.L().Info("checking monthly schedule", zap.Any("rule", ruleID), zap.String("maintenance", m.Name), zap.Time("currentTime", currentTime), zap.Time("startTime", startTime), zap.Time("endTime", endTime))
+ if currentTime.After(startTime) && currentTime.Before(endTime) && currentTime.Day() == start.Day() {
+ return true
+ }
+ }
+ }
+ }
+ // If alert is not found, we return false
+ return false
+}
+
+func (m *PlannedMaintenance) IsActive(now time.Time) bool {
+ ruleID := "maintenance"
+ if m.AlertIds != nil && len(*m.AlertIds) > 0 {
+ ruleID = (*m.AlertIds)[0]
+ }
+ return m.shouldSkip(ruleID, now)
+}
+
+func (m *PlannedMaintenance) IsUpcoming() bool {
+ now := time.Now().In(time.FixedZone(m.Schedule.Timezone, 0))
+ if !m.Schedule.StartTime.IsZero() && !m.Schedule.EndTime.IsZero() {
+ return now.Before(m.Schedule.StartTime)
+ }
+ if m.Schedule.Recurrence != nil {
+ return now.Before(m.Schedule.Recurrence.StartTime)
+ }
+ return false
+}
+
+func (m *PlannedMaintenance) IsRecurring() bool {
+ return m.Schedule.Recurrence != nil
+}
+
+func (m *PlannedMaintenance) Validate() error {
+ if m.Name == "" {
+ return ErrMissingName
+ }
+ if m.Schedule == nil {
+ return ErrMissingSchedule
+ }
+ if m.Schedule.Timezone == "" {
+ return ErrMissingTimezone
+ }
+
+ _, err := time.LoadLocation(m.Schedule.Timezone)
+ if err != nil {
+ return errors.New("invalid timezone")
+ }
+
+ if !m.Schedule.StartTime.IsZero() && !m.Schedule.EndTime.IsZero() {
+ if m.Schedule.StartTime.After(m.Schedule.EndTime) {
+ return errors.New("start time cannot be after end time")
+ }
+ }
+
+ if m.Schedule.Recurrence != nil {
+ if m.Schedule.Recurrence.RepeatType == "" {
+ return ErrMissingRepeatType
+ }
+ if m.Schedule.Recurrence.Duration == 0 {
+ return ErrMissingDuration
+ }
+ if m.Schedule.Recurrence.EndTime != nil && m.Schedule.Recurrence.EndTime.Before(m.Schedule.Recurrence.StartTime) {
+ return errors.New("end time cannot be before start time")
+ }
+ }
+ return nil
+}
+
+func (m PlannedMaintenance) MarshalJSON() ([]byte, error) {
+ now := time.Now().In(time.FixedZone(m.Schedule.Timezone, 0))
+ var status string
+ if m.IsActive(now) {
+ status = "active"
+ } else if m.IsUpcoming() {
+ status = "upcoming"
+ } else {
+ status = "expired"
+ }
+ var kind string
+
+ if !m.Schedule.StartTime.IsZero() && !m.Schedule.EndTime.IsZero() && m.Schedule.EndTime.After(m.Schedule.StartTime) {
+ kind = "fixed"
+ } else {
+ kind = "recurring"
+ }
+
+ return json.Marshal(struct {
+ Id int64 `json:"id" db:"id"`
+ Name string `json:"name" db:"name"`
+ Description string `json:"description" db:"description"`
+ Schedule *Schedule `json:"schedule" db:"schedule"`
+ AlertIds *AlertIds `json:"alertIds" db:"alert_ids"`
+ CreatedAt time.Time `json:"createdAt" db:"created_at"`
+ CreatedBy string `json:"createdBy" db:"created_by"`
+ UpdatedAt time.Time `json:"updatedAt" db:"updated_at"`
+ UpdatedBy string `json:"updatedBy" db:"updated_by"`
+ Status string `json:"status"`
+ Kind string `json:"kind"`
+ }{
+ Id: m.Id,
+ Name: m.Name,
+ Description: m.Description,
+ Schedule: m.Schedule,
+ AlertIds: m.AlertIds,
+ CreatedAt: m.CreatedAt,
+ CreatedBy: m.CreatedBy,
+ UpdatedAt: m.UpdatedAt,
+ UpdatedBy: m.UpdatedBy,
+ Status: status,
+ Kind: kind,
+ })
+}
diff --git a/pkg/query-service/rules/maintenance_test.go b/pkg/query-service/rules/maintenance_test.go
new file mode 100644
index 0000000000..aaf5edbb91
--- /dev/null
+++ b/pkg/query-service/rules/maintenance_test.go
@@ -0,0 +1,230 @@
+package rules
+
+import (
+ "testing"
+ "time"
+)
+
+func TestShouldSkipMaintenance(t *testing.T) {
+
+ cases := []struct {
+ name string
+ maintenance *PlannedMaintenance
+ ts time.Time
+ expected bool
+ }{
+ {
+ name: "fixed planned maintenance start <= ts <= end",
+ maintenance: &PlannedMaintenance{
+ Schedule: &Schedule{
+ Timezone: "UTC",
+ StartTime: time.Now().UTC().Add(-time.Hour),
+ EndTime: time.Now().UTC().Add(time.Hour * 2),
+ },
+ },
+ ts: time.Now().UTC(),
+ expected: true,
+ },
+ {
+ name: "fixed planned maintenance start >= ts",
+ maintenance: &PlannedMaintenance{
+ Schedule: &Schedule{
+ Timezone: "UTC",
+ StartTime: time.Now().UTC().Add(time.Hour),
+ EndTime: time.Now().UTC().Add(time.Hour * 2),
+ },
+ },
+ ts: time.Now().UTC(),
+ expected: false,
+ },
+ {
+ name: "fixed planned maintenance ts < start",
+ maintenance: &PlannedMaintenance{
+ Schedule: &Schedule{
+ Timezone: "UTC",
+ StartTime: time.Now().UTC().Add(time.Hour),
+ EndTime: time.Now().UTC().Add(time.Hour * 2),
+ },
+ },
+ ts: time.Now().UTC().Add(-time.Hour),
+ expected: false,
+ },
+ {
+ name: "recurring maintenance, repeat daily from 12:00 to 14:00",
+ maintenance: &PlannedMaintenance{
+ Schedule: &Schedule{
+ Timezone: "UTC",
+ Recurrence: &Recurrence{
+ StartTime: time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC),
+ Duration: Duration(time.Hour * 2),
+ RepeatType: RepeatTypeDaily,
+ },
+ },
+ },
+ ts: time.Date(2024, 1, 1, 12, 10, 0, 0, time.UTC),
+ expected: true,
+ },
+ {
+ name: "recurring maintenance, repeat daily from 12:00 to 14:00",
+ maintenance: &PlannedMaintenance{
+ Schedule: &Schedule{
+ Timezone: "UTC",
+ Recurrence: &Recurrence{
+ StartTime: time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC),
+ Duration: Duration(time.Hour * 2),
+ RepeatType: RepeatTypeDaily,
+ },
+ },
+ },
+ ts: time.Date(2024, 1, 1, 14, 0, 0, 0, time.UTC),
+ expected: false,
+ },
+ {
+ name: "recurring maintenance, repeat daily from 12:00 to 14:00",
+ maintenance: &PlannedMaintenance{
+ Schedule: &Schedule{
+ Timezone: "UTC",
+ Recurrence: &Recurrence{
+ StartTime: time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC),
+ Duration: Duration(time.Hour * 2),
+ RepeatType: RepeatTypeDaily,
+ },
+ },
+ },
+ ts: time.Date(2024, 04, 1, 12, 10, 0, 0, time.UTC),
+ expected: true,
+ },
+ {
+ name: "recurring maintenance, repeat weekly on monday from 12:00 to 14:00",
+ maintenance: &PlannedMaintenance{
+ Schedule: &Schedule{
+ Timezone: "UTC",
+ Recurrence: &Recurrence{
+ StartTime: time.Date(2024, 04, 01, 12, 0, 0, 0, time.UTC),
+ Duration: Duration(time.Hour * 2),
+ RepeatType: RepeatTypeWeekly,
+ RepeatOn: []RepeatOn{RepeatOnMonday},
+ },
+ },
+ },
+ ts: time.Date(2024, 04, 15, 12, 10, 0, 0, time.UTC),
+ expected: true,
+ },
+ {
+ name: "recurring maintenance, repeat weekly on monday from 12:00 to 14:00",
+ maintenance: &PlannedMaintenance{
+ Schedule: &Schedule{
+ Timezone: "UTC",
+ Recurrence: &Recurrence{
+ StartTime: time.Date(2024, 04, 01, 12, 0, 0, 0, time.UTC),
+ Duration: Duration(time.Hour * 2),
+ RepeatType: RepeatTypeWeekly,
+ RepeatOn: []RepeatOn{RepeatOnMonday},
+ },
+ },
+ },
+ ts: time.Date(2024, 04, 14, 12, 10, 0, 0, time.UTC), // 14th 04 is sunday
+ expected: false,
+ },
+ {
+ name: "recurring maintenance, repeat weekly on monday from 12:00 to 14:00",
+ maintenance: &PlannedMaintenance{
+ Schedule: &Schedule{
+ Timezone: "UTC",
+ Recurrence: &Recurrence{
+ StartTime: time.Date(2024, 04, 01, 12, 0, 0, 0, time.UTC),
+ Duration: Duration(time.Hour * 2),
+ RepeatType: RepeatTypeWeekly,
+ RepeatOn: []RepeatOn{RepeatOnMonday},
+ },
+ },
+ },
+ ts: time.Date(2024, 04, 16, 12, 10, 0, 0, time.UTC), // 16th 04 is tuesday
+ expected: false,
+ },
+ {
+ name: "recurring maintenance, repeat weekly on monday from 12:00 to 14:00",
+ maintenance: &PlannedMaintenance{
+ Schedule: &Schedule{
+ Timezone: "UTC",
+ Recurrence: &Recurrence{
+ StartTime: time.Date(2024, 04, 01, 12, 0, 0, 0, time.UTC),
+ Duration: Duration(time.Hour * 2),
+ RepeatType: RepeatTypeWeekly,
+ RepeatOn: []RepeatOn{RepeatOnMonday},
+ },
+ },
+ },
+ ts: time.Date(2024, 05, 06, 12, 10, 0, 0, time.UTC),
+ expected: true,
+ },
+ {
+ name: "recurring maintenance, repeat weekly on monday from 12:00 to 14:00",
+ maintenance: &PlannedMaintenance{
+ Schedule: &Schedule{
+ Timezone: "UTC",
+ Recurrence: &Recurrence{
+ StartTime: time.Date(2024, 04, 01, 12, 0, 0, 0, time.UTC),
+ Duration: Duration(time.Hour * 2),
+ RepeatType: RepeatTypeWeekly,
+ RepeatOn: []RepeatOn{RepeatOnMonday},
+ },
+ },
+ },
+ ts: time.Date(2024, 05, 06, 14, 00, 0, 0, time.UTC),
+ expected: false,
+ },
+ {
+ name: "recurring maintenance, repeat monthly on 4th from 12:00 to 14:00",
+ maintenance: &PlannedMaintenance{
+ Schedule: &Schedule{
+ Timezone: "UTC",
+ Recurrence: &Recurrence{
+ StartTime: time.Date(2024, 04, 04, 12, 0, 0, 0, time.UTC),
+ Duration: Duration(time.Hour * 2),
+ RepeatType: RepeatTypeMonthly,
+ },
+ },
+ },
+ ts: time.Date(2024, 04, 04, 12, 10, 0, 0, time.UTC),
+ expected: true,
+ },
+ {
+ name: "recurring maintenance, repeat monthly on 4th from 12:00 to 14:00",
+ maintenance: &PlannedMaintenance{
+ Schedule: &Schedule{
+ Timezone: "UTC",
+ Recurrence: &Recurrence{
+ StartTime: time.Date(2024, 04, 04, 12, 0, 0, 0, time.UTC),
+ Duration: Duration(time.Hour * 2),
+ RepeatType: RepeatTypeMonthly,
+ },
+ },
+ },
+ ts: time.Date(2024, 04, 04, 14, 10, 0, 0, time.UTC),
+ expected: false,
+ },
+ {
+ name: "recurring maintenance, repeat monthly on 4th from 12:00 to 14:00",
+ maintenance: &PlannedMaintenance{
+ Schedule: &Schedule{
+ Timezone: "UTC",
+ Recurrence: &Recurrence{
+ StartTime: time.Date(2024, 04, 04, 12, 0, 0, 0, time.UTC),
+ Duration: Duration(time.Hour * 2),
+ RepeatType: RepeatTypeMonthly,
+ },
+ },
+ },
+ ts: time.Date(2024, 05, 04, 12, 10, 0, 0, time.UTC),
+ expected: true,
+ },
+ }
+
+ for _, c := range cases {
+ result := c.maintenance.shouldSkip(c.name, c.ts)
+ if result != c.expected {
+ t.Errorf("expected %v, got %v", c.expected, result)
+ }
+ }
+}
diff --git a/pkg/query-service/rules/manager.go b/pkg/query-service/rules/manager.go
index d649b565fd..20951f56a0 100644
--- a/pkg/query-service/rules/manager.go
+++ b/pkg/query-service/rules/manager.go
@@ -61,6 +61,7 @@ type ManagerOptions struct {
ResendDelay time.Duration
DisableRules bool
FeatureFlags interfaces.FeatureLookup
+ Reader interfaces.Reader
}
// The Manager manages recording and alerting rules.
@@ -79,6 +80,7 @@ type Manager struct {
logger log.Logger
featureFlags interfaces.FeatureLookup
+ reader interfaces.Reader
}
func defaultOptions(o *ManagerOptions) *ManagerOptions {
@@ -119,6 +121,7 @@ func NewManager(o *ManagerOptions) (*Manager, error) {
block: make(chan struct{}),
logger: o.Logger,
featureFlags: o.FeatureFlags,
+ reader: o.Reader,
}
return m, nil
}
@@ -130,6 +133,10 @@ func (m *Manager) Start() {
m.run()
}
+func (m *Manager) RuleDB() RuleDB {
+ return m.ruleDB
+}
+
func (m *Manager) Pause(b bool) {
m.mtx.Lock()
defer m.mtx.Unlock()
@@ -516,6 +523,7 @@ func (m *Manager) prepareTask(acquireLock bool, r *PostableRule, taskName string
r,
ThresholdRuleOpts{},
m.featureFlags,
+ m.reader,
)
if err != nil {
@@ -525,7 +533,7 @@ func (m *Manager) prepareTask(acquireLock bool, r *PostableRule, taskName string
rules = append(rules, tr)
// create ch rule task for evalution
- task = newTask(TaskTypeCh, taskName, taskNamesuffix, time.Duration(r.Frequency), rules, m.opts, m.prepareNotifyFunc())
+ task = newTask(TaskTypeCh, taskName, taskNamesuffix, time.Duration(r.Frequency), rules, m.opts, m.prepareNotifyFunc(), m.ruleDB)
// add rule to memory
m.rules[ruleId] = tr
@@ -547,7 +555,7 @@ func (m *Manager) prepareTask(acquireLock bool, r *PostableRule, taskName string
rules = append(rules, pr)
// create promql rule task for evalution
- task = newTask(TaskTypeProm, taskName, taskNamesuffix, time.Duration(r.Frequency), rules, m.opts, m.prepareNotifyFunc())
+ task = newTask(TaskTypeProm, taskName, taskNamesuffix, time.Duration(r.Frequency), rules, m.opts, m.prepareNotifyFunc(), m.ruleDB)
// add rule to memory
m.rules[ruleId] = pr
@@ -879,6 +887,7 @@ func (m *Manager) TestNotification(ctx context.Context, ruleStr string) (int, *m
SendAlways: true,
},
m.featureFlags,
+ m.reader,
)
if err != nil {
diff --git a/pkg/query-service/rules/promRuleTask.go b/pkg/query-service/rules/promRuleTask.go
index e74106266d..57b7a58dc7 100644
--- a/pkg/query-service/rules/promRuleTask.go
+++ b/pkg/query-service/rules/promRuleTask.go
@@ -27,19 +27,20 @@ type PromRuleTask struct {
evaluationTime time.Duration
lastEvaluation time.Time
- markStale bool
- done chan struct{}
- terminated chan struct{}
- managerDone chan struct{}
+ markStale bool
+ done chan struct{}
+ terminated chan struct{}
pause bool
logger log.Logger
notify NotifyFunc
+
+ ruleDB RuleDB
}
// newPromRuleTask holds rules that have promql condition
// and evalutes the rule at a given frequency
-func newPromRuleTask(name, file string, frequency time.Duration, rules []Rule, opts *ManagerOptions, notify NotifyFunc) *PromRuleTask {
+func newPromRuleTask(name, file string, frequency time.Duration, rules []Rule, opts *ManagerOptions, notify NotifyFunc, ruleDB RuleDB) *PromRuleTask {
zap.L().Info("Initiating a new rule group", zap.String("name", name), zap.Duration("frequency", frequency))
if time.Now() == time.Now().Add(frequency) {
@@ -57,6 +58,7 @@ func newPromRuleTask(name, file string, frequency time.Duration, rules []Rule, o
done: make(chan struct{}),
terminated: make(chan struct{}),
notify: notify,
+ ruleDB: ruleDB,
logger: log.With(opts.Logger, "group", name),
}
}
@@ -313,10 +315,32 @@ func (g *PromRuleTask) CopyState(fromTask Task) error {
// Eval runs a single evaluation cycle in which all rules are evaluated sequentially.
func (g *PromRuleTask) Eval(ctx context.Context, ts time.Time) {
zap.L().Info("promql rule task", zap.String("name", g.name), zap.Time("eval started at", ts))
+
+ maintenance, err := g.ruleDB.GetAllPlannedMaintenance(ctx)
+
+ if err != nil {
+ zap.L().Error("Error in processing sql query", zap.Error(err))
+ }
+
for i, rule := range g.rules {
if rule == nil {
continue
}
+
+ shouldSkip := false
+ for _, m := range maintenance {
+ zap.L().Info("checking if rule should be skipped", zap.String("rule", rule.ID()), zap.Any("maintenance", m))
+ if m.shouldSkip(rule.ID(), ts) {
+ shouldSkip = true
+ break
+ }
+ }
+
+ if shouldSkip {
+ zap.L().Info("rule should be skipped", zap.String("rule", rule.ID()))
+ continue
+ }
+
select {
case <-g.done:
return
diff --git a/pkg/query-service/rules/ruleTask.go b/pkg/query-service/rules/ruleTask.go
index edf3957a6f..577bd453a5 100644
--- a/pkg/query-service/rules/ruleTask.go
+++ b/pkg/query-service/rules/ruleTask.go
@@ -30,12 +30,14 @@ type RuleTask struct {
pause bool
notify NotifyFunc
+
+ ruleDB RuleDB
}
const DefaultFrequency = 1 * time.Minute
// newRuleTask makes a new RuleTask with the given name, options, and rules.
-func newRuleTask(name, file string, frequency time.Duration, rules []Rule, opts *ManagerOptions, notify NotifyFunc) *RuleTask {
+func newRuleTask(name, file string, frequency time.Duration, rules []Rule, opts *ManagerOptions, notify NotifyFunc, ruleDB RuleDB) *RuleTask {
if time.Now() == time.Now().Add(frequency) {
frequency = DefaultFrequency
@@ -52,6 +54,7 @@ func newRuleTask(name, file string, frequency time.Duration, rules []Rule, opts
done: make(chan struct{}),
terminated: make(chan struct{}),
notify: notify,
+ ruleDB: ruleDB,
}
}
@@ -294,10 +297,31 @@ func (g *RuleTask) Eval(ctx context.Context, ts time.Time) {
zap.L().Debug("rule task eval started", zap.String("name", g.name), zap.Time("start time", ts))
+ maintenance, err := g.ruleDB.GetAllPlannedMaintenance(ctx)
+
+ if err != nil {
+ zap.L().Error("Error in processing sql query", zap.Error(err))
+ }
+
for i, rule := range g.rules {
if rule == nil {
continue
}
+
+ shouldSkip := false
+ for _, m := range maintenance {
+ zap.L().Info("checking if rule should be skipped", zap.String("rule", rule.ID()), zap.Any("maintenance", m))
+ if m.shouldSkip(rule.ID(), ts) {
+ shouldSkip = true
+ break
+ }
+ }
+
+ if shouldSkip {
+ zap.L().Info("rule should be skipped", zap.String("rule", rule.ID()))
+ continue
+ }
+
select {
case <-g.done:
return
diff --git a/pkg/query-service/rules/task.go b/pkg/query-service/rules/task.go
index bec4ff1c13..64acf6c76e 100644
--- a/pkg/query-service/rules/task.go
+++ b/pkg/query-service/rules/task.go
@@ -29,9 +29,9 @@ type Task interface {
// newTask returns an appropriate group for
// rule type
-func newTask(taskType TaskType, name, file string, frequency time.Duration, rules []Rule, opts *ManagerOptions, notify NotifyFunc) Task {
+func newTask(taskType TaskType, name, file string, frequency time.Duration, rules []Rule, opts *ManagerOptions, notify NotifyFunc, ruleDB RuleDB) Task {
if taskType == TaskTypeCh {
- return newRuleTask(name, file, frequency, rules, opts, notify)
+ return newRuleTask(name, file, frequency, rules, opts, notify, ruleDB)
}
- return newPromRuleTask(name, file, frequency, rules, opts, notify)
+ return newPromRuleTask(name, file, frequency, rules, opts, notify, ruleDB)
}
diff --git a/pkg/query-service/rules/thresholdRule.go b/pkg/query-service/rules/thresholdRule.go
index feb16bda49..0b8d080bd9 100644
--- a/pkg/query-service/rules/thresholdRule.go
+++ b/pkg/query-service/rules/thresholdRule.go
@@ -7,7 +7,6 @@ import (
"fmt"
"math"
"net/url"
- "reflect"
"regexp"
"sort"
"sync"
@@ -21,7 +20,10 @@ import (
"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
"go.signoz.io/signoz/pkg/query-service/common"
"go.signoz.io/signoz/pkg/query-service/converter"
+ "go.signoz.io/signoz/pkg/query-service/postprocess"
+ "go.signoz.io/signoz/pkg/query-service/app/querier"
+ querierV2 "go.signoz.io/signoz/pkg/query-service/app/querier/v2"
"go.signoz.io/signoz/pkg/query-service/app/queryBuilder"
"go.signoz.io/signoz/pkg/query-service/constants"
"go.signoz.io/signoz/pkg/query-service/interfaces"
@@ -32,9 +34,6 @@ import (
"go.signoz.io/signoz/pkg/query-service/utils/timestamp"
logsv3 "go.signoz.io/signoz/pkg/query-service/app/logs/v3"
- metricsv3 "go.signoz.io/signoz/pkg/query-service/app/metrics/v3"
- metricsV4 "go.signoz.io/signoz/pkg/query-service/app/metrics/v4"
- tracesV3 "go.signoz.io/signoz/pkg/query-service/app/traces/v3"
"go.signoz.io/signoz/pkg/query-service/formatter"
yaml "gopkg.in/yaml.v2"
@@ -62,9 +61,7 @@ type ThresholdRule struct {
// map of active alerts
active map[uint64]*Alert
- queryBuilder *queryBuilder.QueryBuilder
- version string
- queryBuilderV4 *queryBuilder.QueryBuilder
+ version string
// temporalityMap is a map of metric name to temporality
// to avoid fetching temporality for the same metric multiple times
// querying the v4 table on low cardinal temporality column
@@ -75,6 +72,9 @@ type ThresholdRule struct {
lastTimestampWithDatapoints time.Time
typ string
+
+ querier interfaces.Querier
+ querierV2 interfaces.Querier
}
type ThresholdRuleOpts struct {
@@ -93,6 +93,7 @@ func NewThresholdRule(
p *PostableRule,
opts ThresholdRuleOpts,
featureFlags interfaces.FeatureLookup,
+ reader interfaces.Reader,
) (*ThresholdRule, error) {
if p.RuleCondition == nil {
@@ -122,19 +123,22 @@ func NewThresholdRule(
t.evalWindow = 5 * time.Minute
}
- builderOpts := queryBuilder.QueryBuilderOptions{
- BuildMetricQuery: metricsv3.PrepareMetricQuery,
- BuildTraceQuery: tracesV3.PrepareTracesQuery,
- BuildLogQuery: logsv3.PrepareLogsQuery,
+ querierOption := querier.QuerierOptions{
+ Reader: reader,
+ Cache: nil,
+ KeyGenerator: queryBuilder.NewKeyGenerator(),
+ FeatureLookup: featureFlags,
}
- t.queryBuilder = queryBuilder.NewQueryBuilder(builderOpts, featureFlags)
- builderOptsV4 := queryBuilder.QueryBuilderOptions{
- BuildMetricQuery: metricsV4.PrepareMetricQuery,
- BuildTraceQuery: tracesV3.PrepareTracesQuery,
- BuildLogQuery: logsv3.PrepareLogsQuery,
+ querierOptsV2 := querierV2.QuerierOptions{
+ Reader: reader,
+ Cache: nil,
+ KeyGenerator: queryBuilder.NewKeyGenerator(),
+ FeatureLookup: featureFlags,
}
- t.queryBuilderV4 = queryBuilder.NewQueryBuilder(builderOptsV4, featureFlags)
+
+ t.querier = querier.NewQuerier(querierOption)
+ t.querierV2 = querierV2.NewQuerier(querierOptsV2)
zap.L().Info("creating new ThresholdRule", zap.String("name", t.name), zap.String("id", t.id))
@@ -166,7 +170,9 @@ func (r *ThresholdRule) targetVal() float64 {
return 0
}
- return *r.ruleCondition.Target
+ unitConverter := converter.FromUnit(converter.Unit(r.ruleCondition.TargetUnit))
+ value := unitConverter.Convert(converter.Value{F: *r.ruleCondition.Target, U: converter.Unit(r.ruleCondition.TargetUnit)}, converter.Unit(r.Unit()))
+ return value.F
}
func (r *ThresholdRule) matchType() MatchType {
@@ -414,39 +420,7 @@ func (r *ThresholdRule) Unit() string {
return ""
}
-func (r *ThresholdRule) CheckCondition(v float64) bool {
-
- if math.IsNaN(v) {
- zap.L().Debug("found NaN in rule condition", zap.String("rule", r.Name()))
- return false
- }
-
- if r.ruleCondition.Target == nil {
- zap.L().Debug("found null target in rule condition", zap.String("rule", r.Name()))
- return false
- }
-
- unitConverter := converter.FromUnit(converter.Unit(r.ruleCondition.TargetUnit))
-
- value := unitConverter.Convert(converter.Value{F: *r.ruleCondition.Target, U: converter.Unit(r.ruleCondition.TargetUnit)}, converter.Unit(r.Unit()))
-
- zap.L().Info("Checking condition for rule", zap.String("rule", r.Name()), zap.String("converter", unitConverter.Name()), zap.Float64("value", v), zap.Float64("target", value.F), zap.String("compareOp", string(r.ruleCondition.CompareOp)))
- switch r.ruleCondition.CompareOp {
- case ValueIsEq:
- return v == value.F
- case ValueIsNotEq:
- return v != value.F
- case ValueIsBelow:
- return v < value.F
- case ValueIsAbove:
- return v > value.F
- default:
- return false
- }
-}
-
func (r *ThresholdRule) prepareQueryRange(ts time.Time) *v3.QueryRangeParamsV3 {
- // todo(amol): add 30 seconds to evalWindow for rate calc
// todo(srikanthccv): make this configurable
// 2 minutes is reasonable time to wait for data to be available
@@ -459,13 +433,47 @@ func (r *ThresholdRule) prepareQueryRange(ts time.Time) *v3.QueryRangeParamsV3 {
end = end - (end % (60 * 1000))
if r.ruleCondition.QueryType() == v3.QueryTypeClickHouseSQL {
- return &v3.QueryRangeParamsV3{
- Start: start,
- End: end,
- Step: 60,
- CompositeQuery: r.ruleCondition.CompositeQuery,
- Variables: make(map[string]interface{}, 0),
+ params := &v3.QueryRangeParamsV3{
+ Start: start,
+ End: end,
+ Step: int64(math.Max(float64(common.MinAllowedStepInterval(start, end)), 60)),
+ CompositeQuery: &v3.CompositeQuery{
+ QueryType: r.ruleCondition.CompositeQuery.QueryType,
+ PanelType: r.ruleCondition.CompositeQuery.PanelType,
+ BuilderQueries: make(map[string]*v3.BuilderQuery),
+ ClickHouseQueries: make(map[string]*v3.ClickHouseQuery),
+ PromQueries: make(map[string]*v3.PromQuery),
+ Unit: r.ruleCondition.CompositeQuery.Unit,
+ },
+ Variables: make(map[string]interface{}, 0),
+ NoCache: true,
}
+ querytemplate.AssignReservedVarsV3(params)
+ for name, chQuery := range r.ruleCondition.CompositeQuery.ClickHouseQueries {
+ if chQuery.Disabled {
+ continue
+ }
+ tmpl := template.New("clickhouse-query")
+ tmpl, err := tmpl.Parse(chQuery.Query)
+ if err != nil {
+ zap.L().Error("failed to parse clickhouse query to populate vars", zap.String("ruleid", r.ID()), zap.Error(err))
+ r.SetHealth(HealthBad)
+ return params
+ }
+ var query bytes.Buffer
+ err = tmpl.Execute(&query, params.Variables)
+ if err != nil {
+ zap.L().Error("failed to populate clickhouse query", zap.String("ruleid", r.ID()), zap.Error(err))
+ r.SetHealth(HealthBad)
+ return params
+ }
+ params.CompositeQuery.ClickHouseQueries[name] = &v3.ClickHouseQuery{
+ Query: query.String(),
+ Disabled: chQuery.Disabled,
+ Legend: chQuery.Legend,
+ }
+ }
+ return params
}
if r.ruleCondition.CompositeQuery != nil && r.ruleCondition.CompositeQuery.BuilderQueries != nil {
@@ -478,297 +486,13 @@ func (r *ThresholdRule) prepareQueryRange(ts time.Time) *v3.QueryRangeParamsV3 {
return &v3.QueryRangeParamsV3{
Start: start,
End: end,
- Step: 60,
+ Step: int64(math.Max(float64(common.MinAllowedStepInterval(start, end)), 60)),
CompositeQuery: r.ruleCondition.CompositeQuery,
+ Variables: make(map[string]interface{}, 0),
+ NoCache: true,
}
}
-func (r *ThresholdRule) shouldSkipFirstRecord() bool {
- shouldSkip := false
- for _, q := range r.ruleCondition.CompositeQuery.BuilderQueries {
- if q.DataSource == v3.DataSourceMetrics && q.AggregateOperator.IsRateOperator() {
- shouldSkip = true
- }
- }
- return shouldSkip
-}
-
-// queryClickhouse runs actual query against clickhouse
-func (r *ThresholdRule) runChQuery(ctx context.Context, db clickhouse.Conn, query string) (Vector, error) {
- rows, err := db.Query(ctx, query)
- if err != nil {
- zap.L().Error("failed to get alert query result", zap.String("rule", r.Name()), zap.Error(err))
- return nil, err
- }
-
- columnTypes := rows.ColumnTypes()
- columnNames := rows.Columns()
- vars := make([]interface{}, len(columnTypes))
-
- for i := range columnTypes {
- vars[i] = reflect.New(columnTypes[i].ScanType()).Interface()
- }
-
- // []sample list
- var result Vector
-
- // map[fingerprint]sample
- resultMap := make(map[uint64]Sample, 0)
-
- // for rates we want to skip the first record
- // but we dont know when the rates are being used
- // so we always pick timeframe - 30 seconds interval
- // and skip the first record for a given label combo
- // NOTE: this is not applicable for raw queries
- skipFirstRecord := make(map[uint64]bool, 0)
-
- defer rows.Close()
- for rows.Next() {
-
- if err := rows.Scan(vars...); err != nil {
- return nil, err
- }
- r.lastTimestampWithDatapoints = time.Now()
-
- sample := Sample{}
- // Why do we maintain two labels sets? Alertmanager requires
- // label keys to follow the model https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
- // However, our traces and logs explorers support label keys with dot and other namespace characters
- // Using normalized label keys results in invalid filter criteria.
- // The original labels are used to prepare the related{logs, traces} link in alert notification
- lbls := labels.NewBuilder(labels.Labels{})
- lblsOrig := labels.NewBuilder(labels.Labels{})
-
- for i, v := range vars {
-
- colName := normalizeLabelName(columnNames[i])
-
- switch v := v.(type) {
- case *string:
- lbls.Set(colName, *v)
- lblsOrig.Set(columnNames[i], *v)
- case *time.Time:
- timval := *v
-
- if colName == "ts" || colName == "interval" {
- sample.Point.T = timval.Unix()
- } else {
- lbls.Set(colName, timval.Format(constants.AlertTimeFormat))
- lblsOrig.Set(columnNames[i], timval.Format(constants.AlertTimeFormat))
- }
-
- case *float64:
- if _, ok := constants.ReservedColumnTargetAliases[colName]; ok {
- sample.Point.V = *v
- } else {
- lbls.Set(colName, fmt.Sprintf("%f", *v))
- lblsOrig.Set(columnNames[i], fmt.Sprintf("%f", *v))
- }
- case **float64:
- // ch seems to return this type when column is derived from
- // SELECT count(*)/ SELECT count(*)
- floatVal := *v
- if floatVal != nil {
- if _, ok := constants.ReservedColumnTargetAliases[colName]; ok {
- sample.Point.V = *floatVal
- } else {
- lbls.Set(colName, fmt.Sprintf("%f", *floatVal))
- lblsOrig.Set(columnNames[i], fmt.Sprintf("%f", *floatVal))
- }
- }
- case *float32:
- float32Val := float32(*v)
- if _, ok := constants.ReservedColumnTargetAliases[colName]; ok {
- sample.Point.V = float64(float32Val)
- } else {
- lbls.Set(colName, fmt.Sprintf("%f", float32Val))
- lblsOrig.Set(columnNames[i], fmt.Sprintf("%f", float32Val))
- }
- case *uint8, *uint64, *uint16, *uint32:
- if _, ok := constants.ReservedColumnTargetAliases[colName]; ok {
- sample.Point.V = float64(reflect.ValueOf(v).Elem().Uint())
- } else {
- lbls.Set(colName, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Uint()))
- lblsOrig.Set(columnNames[i], fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Uint()))
- }
- case *int8, *int16, *int32, *int64:
- if _, ok := constants.ReservedColumnTargetAliases[colName]; ok {
- sample.Point.V = float64(reflect.ValueOf(v).Elem().Int())
- } else {
- lbls.Set(colName, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Int()))
- lblsOrig.Set(columnNames[i], fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Int()))
- }
- default:
- zap.L().Error("invalid var found in query result", zap.String("ruleId", r.ID()), zap.Any("value", v), zap.Any("column", columnNames[i]))
- }
- }
-
- if math.IsNaN(sample.Point.V) {
- continue
- }
- sample.Point.Vs = append(sample.Point.Vs, sample.Point.V)
-
- // capture lables in result
- sample.Metric = lbls.Labels()
- sample.MetricOrig = lblsOrig.Labels()
-
- labelHash := lbls.Labels().Hash()
-
- // here we walk through values of time series
- // and calculate the final value used to compare
- // with rule target
- if existing, ok := resultMap[labelHash]; ok {
-
- switch r.matchType() {
- case AllTheTimes:
- if r.compareOp() == ValueIsAbove {
- sample.Point.V = math.Min(existing.Point.V, sample.Point.V)
- resultMap[labelHash] = sample
- } else if r.compareOp() == ValueIsBelow {
- sample.Point.V = math.Max(existing.Point.V, sample.Point.V)
- resultMap[labelHash] = sample
- } else {
- sample.Point.Vs = append(existing.Point.Vs, sample.Point.V)
- resultMap[labelHash] = sample
- }
- case AtleastOnce:
- if r.compareOp() == ValueIsAbove {
- sample.Point.V = math.Max(existing.Point.V, sample.Point.V)
- resultMap[labelHash] = sample
- } else if r.compareOp() == ValueIsBelow {
- sample.Point.V = math.Min(existing.Point.V, sample.Point.V)
- resultMap[labelHash] = sample
- } else {
- sample.Point.Vs = append(existing.Point.Vs, sample.Point.V)
- resultMap[labelHash] = sample
- }
- case OnAverage:
- sample.Point.Vs = append(existing.Point.Vs, sample.Point.V)
- sample.Point.V = (existing.Point.V + sample.Point.V)
- resultMap[labelHash] = sample
- case InTotal:
- sample.Point.V = (existing.Point.V + sample.Point.V)
- resultMap[labelHash] = sample
- }
-
- } else {
- if r.Condition().QueryType() == v3.QueryTypeBuilder {
- // for query builder, time series data
- // we skip the first record to support rate cases correctly
- // improvement(amol): explore approaches to limit this only for
- // rate uses cases
- if exists := skipFirstRecord[labelHash]; exists || !r.shouldSkipFirstRecord() {
- resultMap[labelHash] = sample
- } else {
- // looks like the first record for this label combo, skip it
- skipFirstRecord[labelHash] = true
- }
- } else {
- // for clickhouse raw queries, all records are considered
- // improvement(amol): think about supporting rate queries
- // written by user. may have to skip a record, similar to qb case(above)
- resultMap[labelHash] = sample
- }
-
- }
-
- }
-
- if r.matchType() == OnAverage {
- for hash, s := range resultMap {
- s.Point.V = s.Point.V / float64(len(s.Point.Vs))
- resultMap[hash] = s
- }
- }
-
- for hash, s := range resultMap {
- if r.matchType() == AllTheTimes && r.compareOp() == ValueIsEq {
- for _, v := range s.Point.Vs {
- if v != r.targetVal() { // if any of the values is not equal to target, alert shouldn't be sent
- s.Point.V = v
- }
- }
- resultMap[hash] = s
- } else if r.matchType() == AllTheTimes && r.compareOp() == ValueIsNotEq {
- for _, v := range s.Point.Vs {
- if v == r.targetVal() { // if any of the values is equal to target, alert shouldn't be sent
- s.Point.V = v
- }
- }
- resultMap[hash] = s
- } else if r.matchType() == AtleastOnce && r.compareOp() == ValueIsEq {
- for _, v := range s.Point.Vs {
- if v == r.targetVal() { // if any of the values is equal to target, alert should be sent
- s.Point.V = v
- }
- }
- resultMap[hash] = s
- } else if r.matchType() == AtleastOnce && r.compareOp() == ValueIsNotEq {
- for _, v := range s.Point.Vs {
- if v != r.targetVal() { // if any of the values is not equal to target, alert should be sent
- s.Point.V = v
- }
- }
- resultMap[hash] = s
- }
- }
-
- zap.L().Debug("resultmap(potential alerts)", zap.String("ruleid", r.ID()), zap.Int("count", len(resultMap)))
-
- // if the data is missing for `For` duration then we should send alert
- if r.ruleCondition.AlertOnAbsent && r.lastTimestampWithDatapoints.Add(time.Duration(r.Condition().AbsentFor)*time.Minute).Before(time.Now()) {
- zap.L().Info("no data found for rule condition", zap.String("ruleid", r.ID()))
- lbls := labels.NewBuilder(labels.Labels{})
- if !r.lastTimestampWithDatapoints.IsZero() {
- lbls.Set("lastSeen", r.lastTimestampWithDatapoints.Format(constants.AlertTimeFormat))
- }
- result = append(result, Sample{
- Metric: lbls.Labels(),
- IsMissing: true,
- })
- return result, nil
- }
-
- for _, sample := range resultMap {
- // check alert rule condition before dumping results, if sendUnmatchedResults
- // is set then add results irrespective of condition
- if r.opts.SendUnmatched || r.CheckCondition(sample.Point.V) {
- result = append(result, sample)
- }
- }
- if len(result) != 0 {
- zap.L().Info("found alerts", zap.String("ruleid", r.ID()), zap.String("query", query), zap.Int("count", len(result)))
- }
- return result, nil
-}
-
-func (r *ThresholdRule) prepareBuilderQueries(ts time.Time, ch driver.Conn) (map[string]string, error) {
- params := r.prepareQueryRange(ts)
- if params.CompositeQuery.QueryType == v3.QueryTypeBuilder {
- // check if any enrichment is required for logs if yes then enrich them
- if logsv3.EnrichmentRequired(params) {
- // Note: Sending empty fields key because enrichment is only needed for json
- // TODO: Add support for attribute enrichment later
- logsv3.Enrich(params, map[string]v3.AttributeKey{})
- }
-
- }
-
- var runQueries map[string]string
- var err error
-
- if r.version == "v4" {
- if ch != nil {
- r.populateTemporality(context.Background(), params, ch)
- }
- runQueries, err = r.queryBuilderV4.PrepareQueries(params)
- } else {
- runQueries, err = r.queryBuilder.PrepareQueries(params)
- }
-
- return runQueries, err
-}
-
// The following function is used to prepare the where clause for the query
// `lbls` contains the key value pairs of the labels from the result of the query
// We iterate over the where clause and replace the labels with the actual values
@@ -974,73 +698,26 @@ func (r *ThresholdRule) hostFromSource() string {
return fmt.Sprintf("%s://%s", parsedUrl.Scheme, parsedUrl.Hostname())
}
-func (r *ThresholdRule) prepareClickhouseQueries(ts time.Time) (map[string]string, error) {
- queries := make(map[string]string)
-
- if r.ruleCondition == nil {
- return nil, fmt.Errorf("rule condition is empty")
- }
-
- if r.ruleCondition.QueryType() != v3.QueryTypeClickHouseSQL {
- zap.L().Error("unsupported query type in prepareClickhouseQueries", zap.String("ruleid", r.ID()))
- return nil, fmt.Errorf("failed to prepare clickhouse queries")
- }
-
- params := r.prepareQueryRange(ts)
-
- // replace reserved go template variables
- querytemplate.AssignReservedVarsV3(params)
-
- for name, chQuery := range r.ruleCondition.CompositeQuery.ClickHouseQueries {
- if chQuery.Disabled {
- continue
- }
- tmpl := template.New("clickhouse-query")
- tmpl, err := tmpl.Parse(chQuery.Query)
- if err != nil {
- zap.L().Error("failed to parse clickhouse query to populate vars", zap.String("ruleid", r.ID()), zap.Error(err))
- r.SetHealth(HealthBad)
- return nil, err
- }
- var query bytes.Buffer
- err = tmpl.Execute(&query, params.Variables)
- if err != nil {
- zap.L().Error("failed to populate clickhouse query", zap.String("ruleid", r.ID()), zap.Error(err))
- r.SetHealth(HealthBad)
- return nil, err
- }
- queries[name] = query.String()
- }
- return queries, nil
-}
-
func (r *ThresholdRule) GetSelectedQuery() string {
-
- // The actual query string is not relevant here
- // we just need to know the selected query
-
- var queries map[string]string
- var err error
-
- if r.ruleCondition.QueryType() == v3.QueryTypeBuilder {
- queries, err = r.prepareBuilderQueries(time.Now(), nil)
- if err != nil {
- zap.L().Error("failed to prepare metric queries", zap.String("ruleid", r.ID()), zap.Error(err))
- return ""
- }
- } else if r.ruleCondition.QueryType() == v3.QueryTypeClickHouseSQL {
- queries, err = r.prepareClickhouseQueries(time.Now())
- if err != nil {
- zap.L().Error("failed to prepare clickhouse queries", zap.String("ruleid", r.ID()), zap.Error(err))
- return ""
- }
- }
-
if r.ruleCondition != nil {
if r.ruleCondition.SelectedQuery != "" {
return r.ruleCondition.SelectedQuery
}
+ queryNames := map[string]struct{}{}
+
+ if r.ruleCondition.CompositeQuery != nil {
+ if r.ruleCondition.QueryType() == v3.QueryTypeBuilder {
+ for name := range r.ruleCondition.CompositeQuery.BuilderQueries {
+ queryNames[name] = struct{}{}
+ }
+ } else if r.ruleCondition.QueryType() == v3.QueryTypeClickHouseSQL {
+ for name := range r.ruleCondition.CompositeQuery.ClickHouseQueries {
+ queryNames[name] = struct{}{}
+ }
+ }
+ }
+
// The following logic exists for backward compatibility
// If there is no selected query, then
// - check if F1 is present, if yes, return F1
@@ -1048,11 +725,11 @@ func (r *ThresholdRule) GetSelectedQuery() string {
// this logic is not really correct. we should be considering
// whether the query is enabled or not. but this is a temporary
// fix to support backward compatibility
- if _, ok := queries["F1"]; ok {
+ if _, ok := queryNames["F1"]; ok {
return "F1"
}
- keys := make([]string, 0, len(queries))
- for k := range queries {
+ keys := make([]string, 0, len(queryNames))
+ for k := range queryNames {
keys = append(keys, k)
}
sort.Strings(keys)
@@ -1062,56 +739,91 @@ func (r *ThresholdRule) GetSelectedQuery() string {
return ""
}
-// query looks if alert condition is being
-// satisfied and returns the signals
func (r *ThresholdRule) buildAndRunQuery(ctx context.Context, ts time.Time, ch clickhouse.Conn) (Vector, error) {
if r.ruleCondition == nil || r.ruleCondition.CompositeQuery == nil {
r.SetHealth(HealthBad)
+ r.SetLastError(fmt.Errorf("no rule condition"))
return nil, fmt.Errorf("invalid rule condition")
}
- // var to hold target query to be executed
- var queries map[string]string
- var err error
+ params := r.prepareQueryRange(ts)
+ err := r.populateTemporality(ctx, params, ch)
+ if err != nil {
+ r.SetHealth(HealthBad)
+ zap.L().Error("failed to set temporality", zap.String("rule", r.Name()), zap.Error(err))
+ return nil, fmt.Errorf("internal error while setting temporality")
+ }
- // fetch the target query based on query type
- if r.ruleCondition.QueryType() == v3.QueryTypeBuilder {
-
- queries, err = r.prepareBuilderQueries(ts, ch)
-
- if err != nil {
- zap.L().Error("failed to prepare metric queries", zap.String("ruleid", r.ID()), zap.Error(err))
- return nil, fmt.Errorf("failed to prepare metric queries")
+ if params.CompositeQuery.QueryType == v3.QueryTypeBuilder {
+ // check if any enrichment is required for logs if yes then enrich them
+ if logsv3.EnrichmentRequired(params) {
+ // Note: Sending empty fields key because enrichment is only needed for json
+ // TODO: Add support for attribute enrichment later
+ logsv3.Enrich(params, map[string]v3.AttributeKey{})
}
+ }
- } else if r.ruleCondition.QueryType() == v3.QueryTypeClickHouseSQL {
-
- queries, err = r.prepareClickhouseQueries(ts)
-
- if err != nil {
- zap.L().Error("failed to prepare clickhouse queries", zap.String("ruleid", r.ID()), zap.Error(err))
- return nil, fmt.Errorf("failed to prepare clickhouse queries")
- }
+ var results []*v3.Result
+ var errQuriesByName map[string]error
+ if r.version == "v4" {
+ results, err, errQuriesByName = r.querierV2.QueryRange(ctx, params, map[string]v3.AttributeKey{})
} else {
- return nil, fmt.Errorf("unexpected rule condition - query type is empty")
+ results, err, errQuriesByName = r.querier.QueryRange(ctx, params, map[string]v3.AttributeKey{})
}
- if len(queries) == 0 {
- return nil, fmt.Errorf("no queries could be built with the rule config")
+ if err != nil {
+ zap.L().Error("failed to get alert query result", zap.String("rule", r.Name()), zap.Error(err), zap.Any("queries", errQuriesByName))
+ r.SetHealth(HealthBad)
+ return nil, fmt.Errorf("internal error while querying")
}
- zap.L().Info("prepared queries", zap.String("ruleid", r.ID()), zap.Any("queries", queries))
-
- queryLabel := r.GetSelectedQuery()
- zap.L().Debug("Selected query lable for rule", zap.String("ruleid", r.ID()), zap.String("label", queryLabel))
-
- if queryString, ok := queries[queryLabel]; ok {
- return r.runChQuery(ctx, ch, queryString)
+ if params.CompositeQuery.QueryType == v3.QueryTypeBuilder {
+ results, err = postprocess.PostProcessResult(results, params)
+ if err != nil {
+ r.SetHealth(HealthBad)
+ zap.L().Error("failed to post process result", zap.String("rule", r.Name()), zap.Error(err))
+ return nil, fmt.Errorf("internal error while post processing")
+ }
}
- zap.L().Error("invalid query label", zap.String("ruleid", r.ID()), zap.String("label", queryLabel), zap.Any("queries", queries))
- return nil, fmt.Errorf("this is unexpected, invalid query label")
+ selectedQuery := r.GetSelectedQuery()
+
+ var queryResult *v3.Result
+ for _, res := range results {
+ if res.QueryName == selectedQuery {
+ queryResult = res
+ break
+ }
+ }
+
+ if queryResult != nil && len(queryResult.Series) > 0 {
+ r.lastTimestampWithDatapoints = time.Now()
+ }
+
+ var resultVector Vector
+
+ // if the data is missing for `For` duration then we should send alert
+ if r.ruleCondition.AlertOnAbsent && r.lastTimestampWithDatapoints.Add(time.Duration(r.Condition().AbsentFor)*time.Minute).Before(time.Now()) {
+ zap.L().Info("no data found for rule condition", zap.String("ruleid", r.ID()))
+ lbls := labels.NewBuilder(labels.Labels{})
+ if !r.lastTimestampWithDatapoints.IsZero() {
+ lbls.Set("lastSeen", r.lastTimestampWithDatapoints.Format(constants.AlertTimeFormat))
+ }
+ resultVector = append(resultVector, Sample{
+ Metric: lbls.Labels(),
+ IsMissing: true,
+ })
+ return resultVector, nil
+ }
+
+ for _, series := range queryResult.Series {
+ smpl, shouldAlert := r.shouldAlert(*series)
+ if shouldAlert {
+ resultVector = append(resultVector, smpl)
+ }
+ }
+ return resultVector, nil
}
func normalizeLabelName(name string) string {
@@ -1184,7 +896,7 @@ func (r *ThresholdRule) Eval(ctx context.Context, ts time.Time, queriers *Querie
return result
}
- lb := labels.NewBuilder(smpl.Metric).Del(labels.MetricNameLabel)
+ lb := labels.NewBuilder(smpl.Metric).Del(labels.MetricNameLabel).Del(labels.TemporalityLabel)
for _, l := range r.labels {
lb.Set(l.Name, expand(l.Value))
@@ -1307,3 +1019,161 @@ func (r *ThresholdRule) String() string {
return string(byt)
}
+
+func removeGroupinSetPoints(series v3.Series) []v3.Point {
+ var result []v3.Point
+ for _, s := range series.Points {
+ if s.Timestamp >= 0 && !math.IsNaN(s.Value) && !math.IsInf(s.Value, 0) {
+ result = append(result, s)
+ }
+ }
+ return result
+}
+
+func (r *ThresholdRule) shouldAlert(series v3.Series) (Sample, bool) {
+ var alertSmpl Sample
+ var shouldAlert bool
+ var lbls labels.Labels
+ var lblsNormalized labels.Labels
+
+ for name, value := range series.Labels {
+ lbls = append(lbls, labels.Label{Name: name, Value: value})
+ lblsNormalized = append(lblsNormalized, labels.Label{Name: normalizeLabelName(name), Value: value})
+ }
+
+ series.Points = removeGroupinSetPoints(series)
+
+ // nothing to evaluate
+ if len(series.Points) == 0 {
+ return alertSmpl, false
+ }
+
+ switch r.matchType() {
+ case AtleastOnce:
+ // If any sample matches the condition, the rule is firing.
+ if r.compareOp() == ValueIsAbove {
+ for _, smpl := range series.Points {
+ if smpl.Value > r.targetVal() {
+ alertSmpl = Sample{Point: Point{V: smpl.Value}, Metric: lblsNormalized, MetricOrig: lbls}
+ shouldAlert = true
+ break
+ }
+ }
+ } else if r.compareOp() == ValueIsBelow {
+ for _, smpl := range series.Points {
+ if smpl.Value < r.targetVal() {
+ alertSmpl = Sample{Point: Point{V: smpl.Value}, Metric: lblsNormalized, MetricOrig: lbls}
+ shouldAlert = true
+ break
+ }
+ }
+ } else if r.compareOp() == ValueIsEq {
+ for _, smpl := range series.Points {
+ if smpl.Value == r.targetVal() {
+ alertSmpl = Sample{Point: Point{V: smpl.Value}, Metric: lblsNormalized, MetricOrig: lbls}
+ shouldAlert = true
+ break
+ }
+ }
+ } else if r.compareOp() == ValueIsNotEq {
+ for _, smpl := range series.Points {
+ if smpl.Value != r.targetVal() {
+ alertSmpl = Sample{Point: Point{V: smpl.Value}, Metric: lblsNormalized, MetricOrig: lbls}
+ shouldAlert = true
+ break
+ }
+ }
+ }
+ case AllTheTimes:
+ // If all samples match the condition, the rule is firing.
+ shouldAlert = true
+ alertSmpl = Sample{Point: Point{V: r.targetVal()}, Metric: lblsNormalized, MetricOrig: lbls}
+ if r.compareOp() == ValueIsAbove {
+ for _, smpl := range series.Points {
+ if smpl.Value <= r.targetVal() {
+ shouldAlert = false
+ break
+ }
+ }
+ } else if r.compareOp() == ValueIsBelow {
+ for _, smpl := range series.Points {
+ if smpl.Value >= r.targetVal() {
+ shouldAlert = false
+ break
+ }
+ }
+ } else if r.compareOp() == ValueIsEq {
+ for _, smpl := range series.Points {
+ if smpl.Value != r.targetVal() {
+ shouldAlert = false
+ break
+ }
+ }
+ } else if r.compareOp() == ValueIsNotEq {
+ for _, smpl := range series.Points {
+ if smpl.Value == r.targetVal() {
+ shouldAlert = false
+ break
+ }
+ }
+ }
+ case OnAverage:
+ // If the average of all samples matches the condition, the rule is firing.
+ var sum, count float64
+ for _, smpl := range series.Points {
+ if math.IsNaN(smpl.Value) || math.IsInf(smpl.Value, 0) {
+ continue
+ }
+ sum += smpl.Value
+ count++
+ }
+ avg := sum / count
+ alertSmpl = Sample{Point: Point{V: avg}, Metric: lblsNormalized, MetricOrig: lbls}
+ if r.compareOp() == ValueIsAbove {
+ if avg > r.targetVal() {
+ shouldAlert = true
+ }
+ } else if r.compareOp() == ValueIsBelow {
+ if avg < r.targetVal() {
+ shouldAlert = true
+ }
+ } else if r.compareOp() == ValueIsEq {
+ if avg == r.targetVal() {
+ shouldAlert = true
+ }
+ } else if r.compareOp() == ValueIsNotEq {
+ if avg != r.targetVal() {
+ shouldAlert = true
+ }
+ }
+ case InTotal:
+ // If the sum of all samples matches the condition, the rule is firing.
+ var sum float64
+
+ for _, smpl := range series.Points {
+ if math.IsNaN(smpl.Value) || math.IsInf(smpl.Value, 0) {
+ continue
+ }
+ sum += smpl.Value
+ }
+ alertSmpl = Sample{Point: Point{V: sum}, Metric: lblsNormalized, MetricOrig: lbls}
+ if r.compareOp() == ValueIsAbove {
+ if sum > r.targetVal() {
+ shouldAlert = true
+ }
+ } else if r.compareOp() == ValueIsBelow {
+ if sum < r.targetVal() {
+ shouldAlert = true
+ }
+ } else if r.compareOp() == ValueIsEq {
+ if sum == r.targetVal() {
+ shouldAlert = true
+ }
+ } else if r.compareOp() == ValueIsNotEq {
+ if sum != r.targetVal() {
+ shouldAlert = true
+ }
+ }
+ }
+ return alertSmpl, shouldAlert
+}
diff --git a/pkg/query-service/rules/thresholdRule_test.go b/pkg/query-service/rules/thresholdRule_test.go
index 3e51e652b9..762666cbf3 100644
--- a/pkg/query-service/rules/thresholdRule_test.go
+++ b/pkg/query-service/rules/thresholdRule_test.go
@@ -1,18 +1,16 @@
package rules
import (
- "context"
"testing"
"time"
- cmock "github.com/srikanthccv/ClickHouse-go-mock"
"github.com/stretchr/testify/assert"
"go.signoz.io/signoz/pkg/query-service/featureManager"
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
"go.signoz.io/signoz/pkg/query-service/utils/labels"
)
-func TestThresholdRuleCombinations(t *testing.T) {
+func TestThresholdRuleShouldAlert(t *testing.T) {
postableRule := PostableRule{
AlertName: "Tricky Condition Tests",
AlertType: "METRIC_BASED_ALERT",
@@ -37,18 +35,9 @@ func TestThresholdRuleCombinations(t *testing.T) {
},
},
}
- fm := featureManager.StartManager()
- mock, err := cmock.NewClickHouseNative(nil)
- if err != nil {
- t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
- }
-
- cols := make([]cmock.ColumnType, 0)
- cols = append(cols, cmock.ColumnType{Name: "value", Type: "Int32"})
- cols = append(cols, cmock.ColumnType{Name: "endpoint", Type: "String"})
cases := []struct {
- values [][]interface{}
+ values v3.Series
expectAlert bool
compareOp string
matchType string
@@ -56,12 +45,14 @@ func TestThresholdRuleCombinations(t *testing.T) {
}{
// Test cases for Equals Always
{
- values: [][]interface{}{
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 0.0},
+ },
},
expectAlert: true,
compareOp: "3", // Equals
@@ -69,12 +60,14 @@ func TestThresholdRuleCombinations(t *testing.T) {
target: 0.0,
},
{
- values: [][]interface{}{
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
- {int32(1), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 1.0},
+ },
},
expectAlert: false,
compareOp: "3", // Equals
@@ -82,12 +75,14 @@ func TestThresholdRuleCombinations(t *testing.T) {
target: 0.0,
},
{
- values: [][]interface{}{
- {int32(0), "endpoint"},
- {int32(1), "endpoint"},
- {int32(0), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 0.0},
+ {Value: 1.0},
+ {Value: 0.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ },
},
expectAlert: false,
compareOp: "3", // Equals
@@ -95,12 +90,14 @@ func TestThresholdRuleCombinations(t *testing.T) {
target: 0.0,
},
{
- values: [][]interface{}{
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 1.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ },
},
expectAlert: false,
compareOp: "3", // Equals
@@ -109,12 +106,14 @@ func TestThresholdRuleCombinations(t *testing.T) {
},
// Test cases for Equals Once
{
- values: [][]interface{}{
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 0.0},
+ },
},
expectAlert: true,
compareOp: "3", // Equals
@@ -122,12 +121,14 @@ func TestThresholdRuleCombinations(t *testing.T) {
target: 0.0,
},
{
- values: [][]interface{}{
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
- {int32(1), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 1.0},
+ },
},
expectAlert: true,
compareOp: "3", // Equals
@@ -135,12 +136,14 @@ func TestThresholdRuleCombinations(t *testing.T) {
target: 0.0,
},
{
- values: [][]interface{}{
- {int32(0), "endpoint"},
- {int32(1), "endpoint"},
- {int32(0), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 0.0},
+ {Value: 1.0},
+ {Value: 0.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ },
},
expectAlert: true,
compareOp: "3", // Equals
@@ -148,26 +151,92 @@ func TestThresholdRuleCombinations(t *testing.T) {
target: 0.0,
},
{
- values: [][]interface{}{
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 1.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ },
},
expectAlert: false,
compareOp: "3", // Equals
matchType: "1", // Once
target: 0.0,
},
+ // Test cases for Greater Than Always
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ {Value: 4.0},
+ {Value: 6.0},
+ {Value: 8.0},
+ {Value: 2.0},
+ },
+ },
+ expectAlert: true,
+ compareOp: "1", // Greater Than
+ matchType: "2", // Always
+ target: 1.5,
+ },
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ {Value: 4.0},
+ {Value: 6.0},
+ {Value: 8.0},
+ {Value: 2.0},
+ },
+ },
+ expectAlert: false,
+ compareOp: "1", // Greater Than
+ matchType: "2", // Always
+ target: 4.5,
+ },
+ // Test cases for Greater Than Once
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ {Value: 4.0},
+ {Value: 6.0},
+ {Value: 8.0},
+ {Value: 2.0},
+ },
+ },
+ expectAlert: true,
+ compareOp: "1", // Greater Than
+ matchType: "1", // Once
+ target: 4.5,
+ },
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 4.0},
+ {Value: 4.0},
+ {Value: 4.0},
+ {Value: 4.0},
+ {Value: 4.0},
+ },
+ },
+ expectAlert: false,
+ compareOp: "1", // Greater Than
+ matchType: "1", // Once
+ target: 4.5,
+ },
// Test cases for Not Equals Always
{
- values: [][]interface{}{
- {int32(0), "endpoint"},
- {int32(1), "endpoint"},
- {int32(0), "endpoint"},
- {int32(1), "endpoint"},
- {int32(0), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 0.0},
+ {Value: 1.0},
+ {Value: 0.0},
+ {Value: 1.0},
+ {Value: 0.0},
+ },
},
expectAlert: false,
compareOp: "4", // Not Equals
@@ -175,12 +244,14 @@ func TestThresholdRuleCombinations(t *testing.T) {
target: 0.0,
},
{
- values: [][]interface{}{
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
- {int32(0), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 1.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ {Value: 0.0},
+ },
},
expectAlert: false,
compareOp: "4", // Not Equals
@@ -188,12 +259,14 @@ func TestThresholdRuleCombinations(t *testing.T) {
target: 0.0,
},
{
- values: [][]interface{}{
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 1.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ },
},
expectAlert: true,
compareOp: "4", // Not Equals
@@ -201,12 +274,14 @@ func TestThresholdRuleCombinations(t *testing.T) {
target: 0.0,
},
{
- values: [][]interface{}{
- {int32(1), "endpoint"},
- {int32(0), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 1.0},
+ {Value: 0.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ },
},
expectAlert: false,
compareOp: "4", // Not Equals
@@ -215,12 +290,14 @@ func TestThresholdRuleCombinations(t *testing.T) {
},
// Test cases for Not Equals Once
{
- values: [][]interface{}{
- {int32(0), "endpoint"},
- {int32(1), "endpoint"},
- {int32(0), "endpoint"},
- {int32(1), "endpoint"},
- {int32(0), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 0.0},
+ {Value: 1.0},
+ {Value: 0.0},
+ {Value: 1.0},
+ {Value: 0.0},
+ },
},
expectAlert: true,
compareOp: "4", // Not Equals
@@ -228,12 +305,14 @@ func TestThresholdRuleCombinations(t *testing.T) {
target: 0.0,
},
{
- values: [][]interface{}{
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 0.0},
+ },
},
expectAlert: false,
compareOp: "4", // Not Equals
@@ -241,12 +320,14 @@ func TestThresholdRuleCombinations(t *testing.T) {
target: 0.0,
},
{
- values: [][]interface{}{
- {int32(0), "endpoint"},
- {int32(0), "endpoint"},
- {int32(1), "endpoint"},
- {int32(0), "endpoint"},
- {int32(1), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 1.0},
+ {Value: 0.0},
+ {Value: 1.0},
+ },
},
expectAlert: true,
compareOp: "4", // Not Equals
@@ -254,85 +335,294 @@ func TestThresholdRuleCombinations(t *testing.T) {
target: 0.0,
},
{
- values: [][]interface{}{
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
- {int32(1), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 1.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ {Value: 1.0},
+ },
},
expectAlert: true,
compareOp: "4", // Not Equals
matchType: "1", // Once
target: 0.0,
},
+ // Test cases for Less Than Always
{
- values: [][]interface{}{
- {int32(2), "endpoint"},
- {int32(3), "endpoint"},
- {int32(2), "endpoint"},
- {int32(4), "endpoint"},
- {int32(2), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 1.5},
+ {Value: 1.5},
+ {Value: 1.5},
+ {Value: 1.5},
+ {Value: 1.5},
+ },
},
expectAlert: true,
- compareOp: "2", // Below
- matchType: "3", // On Average
- target: 3.0,
+ compareOp: "2", // Less Than
+ matchType: "2", // Always
+ target: 4,
},
{
- values: [][]interface{}{
- {int32(4), "endpoint"},
- {int32(7), "endpoint"},
- {int32(5), "endpoint"},
- {int32(2), "endpoint"},
- {int32(9), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 4.5},
+ {Value: 4.5},
+ {Value: 4.5},
+ {Value: 4.5},
+ {Value: 4.5},
+ },
},
expectAlert: false,
- compareOp: "2", // Below
- matchType: "3", // On Average
- target: 3.0,
+ compareOp: "2", // Less Than
+ matchType: "2", // Always
+ target: 4,
},
+ // Test cases for Less Than Once
{
- values: [][]interface{}{
- {int32(4), "endpoint"},
- {int32(7), "endpoint"},
- {int32(5), "endpoint"},
- {int32(2), "endpoint"},
- {int32(9), "endpoint"},
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 4.5},
+ {Value: 4.5},
+ {Value: 4.5},
+ {Value: 4.5},
+ {Value: 2.5},
+ },
},
expectAlert: true,
- compareOp: "2", // Below
- matchType: "3", // On Average
+ compareOp: "2", // Less Than
+ matchType: "1", // Once
+ target: 4,
+ },
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 4.5},
+ {Value: 4.5},
+ {Value: 4.5},
+ {Value: 4.5},
+ {Value: 4.5},
+ },
+ },
+ expectAlert: false,
+ compareOp: "2", // Less Than
+ matchType: "1", // Once
+ target: 4,
+ },
+ // Test cases for OnAverage
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ {Value: 4.0},
+ {Value: 6.0},
+ {Value: 8.0},
+ {Value: 2.0},
+ },
+ },
+ expectAlert: true,
+ compareOp: "3", // Equals
+ matchType: "3", // OnAverage
target: 6.0,
},
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ {Value: 4.0},
+ {Value: 6.0},
+ {Value: 8.0},
+ {Value: 2.0},
+ },
+ },
+ expectAlert: false,
+ compareOp: "3", // Equals
+ matchType: "3", // OnAverage
+ target: 4.5,
+ },
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ {Value: 4.0},
+ {Value: 6.0},
+ {Value: 8.0},
+ {Value: 2.0},
+ },
+ },
+ expectAlert: true,
+ compareOp: "4", // Not Equals
+ matchType: "3", // OnAverage
+ target: 4.5,
+ },
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ {Value: 4.0},
+ {Value: 6.0},
+ {Value: 8.0},
+ {Value: 2.0},
+ },
+ },
+ expectAlert: false,
+ compareOp: "4", // Not Equals
+ matchType: "3", // OnAverage
+ target: 6.0,
+ },
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ {Value: 4.0},
+ {Value: 6.0},
+ {Value: 8.0},
+ {Value: 2.0},
+ },
+ },
+ expectAlert: true,
+ compareOp: "1", // Greater Than
+ matchType: "3", // OnAverage
+ target: 4.5,
+ },
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ {Value: 4.0},
+ {Value: 6.0},
+ {Value: 8.0},
+ {Value: 2.0},
+ },
+ },
+ expectAlert: true,
+ compareOp: "2", // Less Than
+ matchType: "3", // OnAverage
+ target: 12.0,
+ },
+ // Test cases for InTotal
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ {Value: 4.0},
+ {Value: 6.0},
+ {Value: 8.0},
+ {Value: 2.0},
+ },
+ },
+ expectAlert: true,
+ compareOp: "3", // Equals
+ matchType: "4", // InTotal
+ target: 30.0,
+ },
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ {Value: 4.0},
+ {Value: 6.0},
+ {Value: 8.0},
+ {Value: 2.0},
+ },
+ },
+ expectAlert: false,
+ compareOp: "3", // Equals
+ matchType: "4", // InTotal
+ target: 20.0,
+ },
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ },
+ },
+ expectAlert: true,
+ compareOp: "4", // Not Equals
+ matchType: "4", // InTotal
+ target: 9.0,
+ },
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ },
+ },
+ expectAlert: false,
+ compareOp: "4", // Not Equals
+ matchType: "4", // InTotal
+ target: 10.0,
+ },
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ {Value: 10.0},
+ },
+ },
+ expectAlert: true,
+ compareOp: "1", // Greater Than
+ matchType: "4", // InTotal
+ target: 10.0,
+ },
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ {Value: 10.0},
+ },
+ },
+ expectAlert: false,
+ compareOp: "1", // Greater Than
+ matchType: "4", // InTotal
+ target: 20.0,
+ },
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ {Value: 10.0},
+ },
+ },
+ expectAlert: true,
+ compareOp: "2", // Less Than
+ matchType: "4", // InTotal
+ target: 30.0,
+ },
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 10.0},
+ {Value: 10.0},
+ },
+ },
+ expectAlert: false,
+ compareOp: "2", // Less Than
+ matchType: "4", // InTotal
+ target: 20.0,
+ },
}
+ fm := featureManager.StartManager()
for idx, c := range cases {
- rows := cmock.NewRows(cols, c.values)
- // We are testing the eval logic after the query is run
- // so we don't care about the query string here
- queryString := "SELECT value, endpoint FROM table"
- mock.
- ExpectQuery(queryString).
- WillReturnRows(rows)
postableRule.RuleCondition.CompareOp = CompareOp(c.compareOp)
postableRule.RuleCondition.MatchType = MatchType(c.matchType)
postableRule.RuleCondition.Target = &c.target
- rule, err := NewThresholdRule("69", &postableRule, ThresholdRuleOpts{}, fm)
+ rule, err := NewThresholdRule("69", &postableRule, ThresholdRuleOpts{}, fm, nil)
if err != nil {
assert.NoError(t, err)
}
- result, err := rule.runChQuery(context.Background(), mock, queryString)
- if err != nil {
- assert.NoError(t, err)
- }
- if c.expectAlert {
- assert.Equal(t, 1, len(result), "case %d", idx)
- } else {
- assert.Equal(t, 0, len(result), "case %d", idx)
+ values := c.values
+ for i := range values.Points {
+ values.Points[i].Timestamp = time.Now().UnixMilli()
}
+
+ _, shoulAlert := rule.shouldAlert(c.values)
+ assert.Equal(t, c.expectAlert, shoulAlert, "Test case %d", idx)
}
}
@@ -407,7 +697,7 @@ func TestPrepareLinksToLogs(t *testing.T) {
}
fm := featureManager.StartManager()
- rule, err := NewThresholdRule("69", &postableRule, ThresholdRuleOpts{}, fm)
+ rule, err := NewThresholdRule("69", &postableRule, ThresholdRuleOpts{}, fm, nil)
if err != nil {
assert.NoError(t, err)
}
@@ -449,7 +739,7 @@ func TestPrepareLinksToTraces(t *testing.T) {
}
fm := featureManager.StartManager()
- rule, err := NewThresholdRule("69", &postableRule, ThresholdRuleOpts{}, fm)
+ rule, err := NewThresholdRule("69", &postableRule, ThresholdRuleOpts{}, fm, nil)
if err != nil {
assert.NoError(t, err)
}
@@ -459,3 +749,136 @@ func TestPrepareLinksToTraces(t *testing.T) {
link := rule.prepareLinksToTraces(ts, labels.Labels{})
assert.Contains(t, link, "&timeRange=%7B%22start%22%3A1705468620000000000%2C%22end%22%3A1705468920000000000%2C%22pageSize%22%3A100%7D&startTime=1705468620000000000&endTime=1705468920000000000")
}
+
+func TestThresholdRuleLabelNormalization(t *testing.T) {
+ postableRule := PostableRule{
+ AlertName: "Tricky Condition Tests",
+ AlertType: "METRIC_BASED_ALERT",
+ RuleType: RuleTypeThreshold,
+ EvalWindow: Duration(5 * time.Minute),
+ Frequency: Duration(1 * time.Minute),
+ RuleCondition: &RuleCondition{
+ CompositeQuery: &v3.CompositeQuery{
+ QueryType: v3.QueryTypeBuilder,
+ BuilderQueries: map[string]*v3.BuilderQuery{
+ "A": {
+ QueryName: "A",
+ StepInterval: 60,
+ AggregateAttribute: v3.AttributeKey{
+ Key: "probe_success",
+ },
+ AggregateOperator: v3.AggregateOperatorNoOp,
+ DataSource: v3.DataSourceMetrics,
+ Expression: "A",
+ },
+ },
+ },
+ },
+ }
+
+ cases := []struct {
+ values v3.Series
+ expectAlert bool
+ compareOp string
+ matchType string
+ target float64
+ }{
+ // Test cases for Equals Always
+ {
+ values: v3.Series{
+ Points: []v3.Point{
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 0.0},
+ {Value: 0.0},
+ },
+ Labels: map[string]string{
+ "service.name": "frontend",
+ },
+ LabelsArray: []map[string]string{
+ map[string]string{
+ "service.name": "frontend",
+ },
+ },
+ },
+ expectAlert: true,
+ compareOp: "3", // Equals
+ matchType: "2", // Always
+ target: 0.0,
+ },
+ }
+
+ fm := featureManager.StartManager()
+ for idx, c := range cases {
+ postableRule.RuleCondition.CompareOp = CompareOp(c.compareOp)
+ postableRule.RuleCondition.MatchType = MatchType(c.matchType)
+ postableRule.RuleCondition.Target = &c.target
+
+ rule, err := NewThresholdRule("69", &postableRule, ThresholdRuleOpts{}, fm, nil)
+ if err != nil {
+ assert.NoError(t, err)
+ }
+
+ values := c.values
+ for i := range values.Points {
+ values.Points[i].Timestamp = time.Now().UnixMilli()
+ }
+
+ sample, shoulAlert := rule.shouldAlert(c.values)
+ for name, value := range c.values.Labels {
+ assert.Equal(t, value, sample.Metric.Get(normalizeLabelName(name)))
+ }
+
+ assert.Equal(t, c.expectAlert, shoulAlert, "Test case %d", idx)
+ }
+}
+
+func TestThresholdRuleClickHouseTmpl(t *testing.T) {
+ postableRule := PostableRule{
+ AlertName: "Tricky Condition Tests",
+ AlertType: "METRIC_BASED_ALERT",
+ RuleType: RuleTypeThreshold,
+ EvalWindow: Duration(5 * time.Minute),
+ Frequency: Duration(1 * time.Minute),
+ RuleCondition: &RuleCondition{
+ CompositeQuery: &v3.CompositeQuery{
+ QueryType: v3.QueryTypeClickHouseSQL,
+ ClickHouseQueries: map[string]*v3.ClickHouseQuery{
+ "A": {
+ Query: "SELECT 1 >= {{.start_timestamp_ms}} AND 1 <= {{.end_timestamp_ms}}",
+ },
+ },
+ },
+ },
+ }
+
+ // 01:39:47
+ ts := time.Unix(1717205987, 0)
+
+ cases := []struct {
+ expectedQuery string
+ }{
+ // Test cases for Equals Always
+ {
+ // 01:32:00 - 01:37:00
+ expectedQuery: "SELECT 1 >= 1717205520000 AND 1 <= 1717205820000",
+ },
+ }
+
+ fm := featureManager.StartManager()
+ for idx, c := range cases {
+ rule, err := NewThresholdRule("69", &postableRule, ThresholdRuleOpts{}, fm, nil)
+ if err != nil {
+ assert.NoError(t, err)
+ }
+
+ params := rule.prepareQueryRange(ts)
+
+ assert.Equal(t, c.expectedQuery, params.CompositeQuery.ClickHouseQueries["A"].Query, "Test case %d", idx)
+
+ secondTimeParams := rule.prepareQueryRange(ts)
+
+ assert.Equal(t, c.expectedQuery, secondTimeParams.CompositeQuery.ClickHouseQueries["A"].Query, "Test case %d", idx)
+ }
+}
diff --git a/pkg/query-service/telemetry/telemetry.go b/pkg/query-service/telemetry/telemetry.go
index e4eabe6f51..3625a3c9e2 100644
--- a/pkg/query-service/telemetry/telemetry.go
+++ b/pkg/query-service/telemetry/telemetry.go
@@ -37,6 +37,9 @@ const (
TELEMETRY_EVENT_LANGUAGE = "Language"
TELEMETRY_EVENT_SERVICE = "ServiceName"
TELEMETRY_EVENT_LOGS_FILTERS = "Logs Filters"
+ TELEMETRY_EVENT_LARGE_TRACE_OPENED = "Large Trace Opened"
+ TELEMETRY_EVENT_TRACE_DETAIL_API = "Trace Detail API"
+ TELEMETRY_EVENT_MAX_SPANS_ALLOWED_LIMIT_REACHED = "Max spans in a trace limit reached"
TELEMETRY_EVENT_DISTRIBUTED = "Distributed"
TELEMETRY_EVENT_QUERY_RANGE_API = "Query Range API"
TELEMETRY_EVENT_DASHBOARDS_ALERTS = "Dashboards/Alerts Info"
@@ -61,6 +64,9 @@ var SAAS_EVENTS_LIST = map[string]struct{}{
TELEMETRY_EVENT_SUCCESSFUL_DASHBOARD_PANEL_QUERY: {},
TELEMETRY_EVENT_SUCCESSFUL_ALERT_QUERY: {},
TELEMETRY_EVENT_QUERY_RANGE_API: {},
+ TELEMETRY_EVENT_MAX_SPANS_ALLOWED_LIMIT_REACHED: {},
+ TELEMETRY_EVENT_LARGE_TRACE_OPENED: {},
+ TELEMETRY_EVENT_TRACE_DETAIL_API: {},
}
const api_key = "4Gmoa4ixJAUHx2BpJxsjwA1bEfnwEeRz"
diff --git a/pkg/query-service/tests/test-deploy/docker-compose.yaml b/pkg/query-service/tests/test-deploy/docker-compose.yaml
index 396b059157..67d6f6d508 100644
--- a/pkg/query-service/tests/test-deploy/docker-compose.yaml
+++ b/pkg/query-service/tests/test-deploy/docker-compose.yaml
@@ -192,7 +192,7 @@ services:
<<: *db-depend
otel-collector-migrator:
- image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.88.24}
+ image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.88.26}
container_name: otel-migrator
command:
- "--dsn=tcp://clickhouse:9000"
@@ -205,7 +205,7 @@ services:
# condition: service_healthy
otel-collector:
- image: signoz/signoz-otel-collector:0.88.24
+ image: signoz/signoz-otel-collector:0.88.26
container_name: signoz-otel-collector
command:
[
diff --git a/pkg/query-service/utils/format.go b/pkg/query-service/utils/format.go
index 0adaebff4a..481590e761 100644
--- a/pkg/query-service/utils/format.go
+++ b/pkg/query-service/utils/format.go
@@ -143,7 +143,7 @@ func ValidateAndCastValue(v interface{}, dataType v3.AttributeKeyDataType) (inte
}
}
-func quoteEscapedString(str string) string {
+func QuoteEscapedString(str string) string {
// https://clickhouse.com/docs/en/sql-reference/syntax#string
str = strings.ReplaceAll(str, `\`, `\\`)
str = strings.ReplaceAll(str, `'`, `\'`)
@@ -161,7 +161,7 @@ func ClickHouseFormattedValue(v interface{}) string {
case float32, float64:
return fmt.Sprintf("%f", x)
case string:
- return fmt.Sprintf("'%s'", quoteEscapedString(x))
+ return fmt.Sprintf("'%s'", QuoteEscapedString(x))
case bool:
return fmt.Sprintf("%v", x)
@@ -173,7 +173,7 @@ func ClickHouseFormattedValue(v interface{}) string {
case string:
str := "["
for idx, sVal := range x {
- str += fmt.Sprintf("'%s'", quoteEscapedString(sVal.(string)))
+ str += fmt.Sprintf("'%s'", QuoteEscapedString(sVal.(string)))
if idx != len(x)-1 {
str += ","
}
diff --git a/pkg/query-service/utils/labels/labels.go b/pkg/query-service/utils/labels/labels.go
index 2e0041aafc..991490806c 100644
--- a/pkg/query-service/utils/labels/labels.go
+++ b/pkg/query-service/utils/labels/labels.go
@@ -14,8 +14,9 @@ const sep = '\xff'
// Well-known label names used by Prometheus components.
const (
- MetricNameLabel = "__name__"
- AlertNameLabel = "alertname"
+ MetricNameLabel = "__name__"
+ TemporalityLabel = "__temporality__"
+ AlertNameLabel = "alertname"
// AlertStateLabel is the label name indicating the state of an alert.
AlertStateLabel = "alertstate"
diff --git a/pkg/query-service/utils/queryTemplate/vars.go b/pkg/query-service/utils/queryTemplate/vars.go
index 677d3aa773..c9d814e004 100644
--- a/pkg/query-service/utils/queryTemplate/vars.go
+++ b/pkg/query-service/utils/queryTemplate/vars.go
@@ -15,6 +15,9 @@ func AssignReservedVarsV3(queryRangeParams *v3.QueryRangeParamsV3) {
queryRangeParams.Variables["start_timestamp_ms"] = queryRangeParams.Start
queryRangeParams.Variables["end_timestamp_ms"] = queryRangeParams.End
+ queryRangeParams.Variables["SIGNOZ_START_TIME"] = queryRangeParams.Start
+ queryRangeParams.Variables["SIGNOZ_END_TIME"] = queryRangeParams.End
+
queryRangeParams.Variables["start_timestamp_nano"] = queryRangeParams.Start * 1e6
queryRangeParams.Variables["end_timestamp_nano"] = queryRangeParams.End * 1e6