diff --git a/ee/anomaly/seasonal.go b/ee/anomaly/seasonal.go
index abd455e0e005..6636188b6d04 100644
--- a/ee/anomaly/seasonal.go
+++ b/ee/anomaly/seasonal.go
@@ -50,19 +50,14 @@ func (p *BaseSeasonalProvider) getQueryParams(req *AnomaliesRequest) *anomalyQue
func (p *BaseSeasonalProvider) toTSResults(ctx context.Context, resp *qbtypes.QueryRangeResponse) []*qbtypes.TimeSeriesData {
- if resp == nil || resp.Data == nil {
+ tsData := []*qbtypes.TimeSeriesData{}
+
+ if resp == nil {
p.logger.InfoContext(ctx, "nil response from query range")
+ return tsData
}
- data, ok := resp.Data.(struct {
- Results []any `json:"results"`
- Warnings []string `json:"warnings"`
- })
- if !ok {
- return nil
- }
- tsData := []*qbtypes.TimeSeriesData{}
- for _, item := range data.Results {
+ for _, item := range resp.Data.Results {
if resultData, ok := item.(*qbtypes.TimeSeriesData); ok {
tsData = append(tsData, resultData)
}
@@ -395,6 +390,11 @@ func (p *BaseSeasonalProvider) getAnomalies(ctx context.Context, orgID valuer.UU
continue
}
+ // no data;
+ if len(result.Aggregations) == 0 {
+ continue
+ }
+
aggOfInterest := result.Aggregations[0]
for _, series := range aggOfInterest.Series {
diff --git a/ee/query-service/app/api/api.go b/ee/query-service/app/api/api.go
index 26f69087b164..c5fcbf64f473 100644
--- a/ee/query-service/app/api/api.go
+++ b/ee/query-service/app/api/api.go
@@ -113,6 +113,8 @@ func (ah *APIHandler) RegisterRoutes(router *mux.Router, am *middleware.AuthZ) {
// v5
router.HandleFunc("/api/v5/query_range", am.ViewAccess(ah.queryRangeV5)).Methods(http.MethodPost)
+ router.HandleFunc("/api/v5/substitute_vars", am.ViewAccess(ah.QuerierAPI.ReplaceVariables)).Methods(http.MethodPost)
+
// Gateway
router.PathPrefix(gateway.RoutePrefix).HandlerFunc(am.EditAccess(ah.ServeGatewayHTTP))
diff --git a/ee/query-service/app/api/queryrange.go b/ee/query-service/app/api/queryrange.go
index 85d60d4b6b43..698ac2d91c72 100644
--- a/ee/query-service/app/api/queryrange.go
+++ b/ee/query-service/app/api/queryrange.go
@@ -260,11 +260,9 @@ func (aH *APIHandler) queryRangeV5(rw http.ResponseWriter, req *http.Request) {
finalResp := &qbtypes.QueryRangeResponse{
Type: queryRangeRequest.RequestType,
Data: struct {
- Results []any `json:"results"`
- Warnings []string `json:"warnings"`
+ Results []any `json:"results"`
}{
- Results: results,
- Warnings: make([]string, 0), // TODO(srikanthccv): will there be any warnings here?
+ Results: results,
},
Meta: struct {
RowsScanned uint64 `json:"rowsScanned"`
diff --git a/ee/query-service/rules/anomaly.go b/ee/query-service/rules/anomaly.go
index 52226bd08b7f..3fbf1e32b1f2 100644
--- a/ee/query-service/rules/anomaly.go
+++ b/ee/query-service/rules/anomaly.go
@@ -211,7 +211,8 @@ func (r *AnomalyRule) prepareQueryRangeV5(ctx context.Context, ts time.Time) (*q
},
NoCache: true,
}
- copy(r.Condition().CompositeQuery.Queries, req.CompositeQuery.Queries)
+ req.CompositeQuery.Queries = make([]qbtypes.QueryEnvelope, len(r.Condition().CompositeQuery.Queries))
+ copy(req.CompositeQuery.Queries, r.Condition().CompositeQuery.Queries)
return req, nil
}
diff --git a/frontend/src/constants/orgPreferences.ts b/frontend/src/constants/orgPreferences.ts
index 83a4a1e3f341..f96aa4a014ed 100644
--- a/frontend/src/constants/orgPreferences.ts
+++ b/frontend/src/constants/orgPreferences.ts
@@ -7,8 +7,8 @@ export const ORG_PREFERENCES = {
'welcome_checklist_setup_alerts_skipped',
WELCOME_CHECKLIST_SETUP_SAVED_VIEW_SKIPPED:
'welcome_checklist_setup_saved_view_skipped',
- WELCOME_CHECKLIST_SEND_INFRA_METRICS_SKIPPED:
- 'welcome_checklist_send_infra_metrics_skipped',
+ WELCOME_CHECKLIST_SEND_METRICS_SKIPPED:
+ 'welcome_checklist_send_metrics_skipped',
WELCOME_CHECKLIST_SETUP_DASHBOARDS_SKIPPED:
'welcome_checklist_setup_dashboards_skipped',
WELCOME_CHECKLIST_SETUP_WORKSPACE_SKIPPED:
diff --git a/frontend/src/container/Home/Home.tsx b/frontend/src/container/Home/Home.tsx
index 33e96374224d..d9133095b95d 100644
--- a/frontend/src/container/Home/Home.tsx
+++ b/frontend/src/container/Home/Home.tsx
@@ -4,21 +4,17 @@ import './Home.styles.scss';
import { Color } from '@signozhq/design-tokens';
import { Button, Popover } from 'antd';
import logEvent from 'api/common/logEvent';
-import { HostListPayload } from 'api/infraMonitoring/getHostLists';
-import { K8sPodsListPayload } from 'api/infraMonitoring/getK8sPodsList';
import listUserPreferences from 'api/v1/user/preferences/list';
import updateUserPreferenceAPI from 'api/v1/user/preferences/name/update';
import Header from 'components/Header/Header';
import { ENTITY_VERSION_V5 } from 'constants/app';
-import { FeatureKeys } from 'constants/features';
import { LOCALSTORAGE } from 'constants/localStorage';
import { ORG_PREFERENCES } from 'constants/orgPreferences';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import ROUTES from 'constants/routes';
-import { getHostListsQuery } from 'container/InfraMonitoringHosts/utils';
-import { useGetHostList } from 'hooks/infraMonitoring/useGetHostList';
-import { useGetK8sPodsList } from 'hooks/infraMonitoring/useGetK8sPodsList';
+import { getMetricsListQuery } from 'container/MetricsExplorer/Summary/utils';
+import { useGetMetricsList } from 'hooks/metricsExplorer/useGetMetricsList';
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
import { useGetTenantLicense } from 'hooks/useGetTenantLicense';
import history from 'lib/history';
@@ -132,9 +128,9 @@ export default function Home(): JSX.Element {
},
);
- // Detect Infra Metrics - Hosts
+ // Detect Metrics
const query = useMemo(() => {
- const baseQuery = getHostListsQuery();
+ const baseQuery = getMetricsListQuery();
let queryStartTime = startTime;
let queryEndTime = endTime;
@@ -161,26 +157,11 @@ export default function Home(): JSX.Element {
};
}, [startTime, endTime]);
- const { data: hostData } = useGetHostList(query as HostListPayload, {
- queryKey: ['hostList', query],
+ const { data: metricsData } = useGetMetricsList(query, {
enabled: !!query,
+ queryKey: ['metricsList', query],
});
- const { featureFlags } = useAppContext();
- const dotMetricsEnabled =
- featureFlags?.find((flag) => flag.name === FeatureKeys.DOT_METRICS_ENABLED)
- ?.active || false;
-
- const { data: k8sPodsData } = useGetK8sPodsList(
- query as K8sPodsListPayload,
- {
- queryKey: ['K8sPodsList', query],
- enabled: !!query,
- },
- undefined,
- dotMetricsEnabled,
- );
-
const [isLogsIngestionActive, setIsLogsIngestionActive] = useState(false);
const [isTracesIngestionActive, setIsTracesIngestionActive] = useState(false);
const [isMetricsIngestionActive, setIsMetricsIngestionActive] = useState(
@@ -305,15 +286,14 @@ export default function Home(): JSX.Element {
}, [tracesData, handleUpdateChecklistDoneItem]);
useEffect(() => {
- const hostDataTotal = hostData?.payload?.data?.total ?? 0;
- const k8sPodsDataTotal = k8sPodsData?.payload?.data?.total ?? 0;
+ const metricsDataTotal = metricsData?.payload?.data?.total ?? 0;
- if (hostDataTotal > 0 || k8sPodsDataTotal > 0) {
+ if (metricsDataTotal > 0) {
setIsMetricsIngestionActive(true);
handleUpdateChecklistDoneItem('ADD_DATA_SOURCE');
- handleUpdateChecklistDoneItem('SEND_INFRA_METRICS');
+ handleUpdateChecklistDoneItem('SEND_METRICS');
}
- }, [hostData, k8sPodsData, handleUpdateChecklistDoneItem]);
+ }, [metricsData, handleUpdateChecklistDoneItem]);
useEffect(() => {
logEvent('Homepage: Visited', {});
@@ -520,19 +500,19 @@ export default function Home(): JSX.Element {
logEvent('Homepage: Ingestion Active Explore clicked', {
source: 'Metrics',
});
- history.push(ROUTES.INFRASTRUCTURE_MONITORING_HOSTS);
+ history.push(ROUTES.METRICS_EXPLORER);
}}
onKeyDown={(e): void => {
if (e.key === 'Enter') {
logEvent('Homepage: Ingestion Active Explore clicked', {
source: 'Metrics',
});
- history.push(ROUTES.INFRASTRUCTURE_MONITORING_HOSTS);
+ history.push(ROUTES.METRICS_EXPLORER);
}
}}
>
- Explore Infra Metrics
+ Explore Metrics
@@ -593,6 +573,20 @@ export default function Home(): JSX.Element {
>
Open Traces Explorer
+
+ }
+ onClick={(): void => {
+ logEvent('Homepage: Explore clicked', {
+ source: 'Metrics',
+ });
+ history.push(ROUTES.METRICS_EXPLORER_EXPLORER);
+ }}
+ >
+ Open Metrics Explorer
+
diff --git a/frontend/src/container/Home/SavedViews/SavedViews.tsx b/frontend/src/container/Home/SavedViews/SavedViews.tsx
index a89f898de55c..0e3272fc36e4 100644
--- a/frontend/src/container/Home/SavedViews/SavedViews.tsx
+++ b/frontend/src/container/Home/SavedViews/SavedViews.tsx
@@ -7,6 +7,7 @@ import { useHandleExplorerTabChange } from 'hooks/useHandleExplorerTabChange';
import {
ArrowRight,
ArrowUpRight,
+ BarChart,
CompassIcon,
DraftingCompass,
} from 'lucide-react';
@@ -42,6 +43,12 @@ export default function SavedViews({
isError: tracesViewsError,
} = useGetAllViews(DataSource.TRACES);
+ const {
+ data: metricsViewsData,
+ isLoading: metricsViewsLoading,
+ isError: metricsViewsError,
+ } = useGetAllViews(DataSource.METRICS);
+
const logsViews = useMemo(() => [...(logsViewsData?.data.data || [])], [
logsViewsData,
]);
@@ -50,14 +57,25 @@ export default function SavedViews({
tracesViewsData,
]);
+ const metricsViews = useMemo(() => [...(metricsViewsData?.data.data || [])], [
+ metricsViewsData,
+ ]);
+
useEffect(() => {
- setSelectedEntityViews(selectedEntity === 'logs' ? logsViews : tracesViews);
- }, [selectedEntity, logsViews, tracesViews]);
+ if (selectedEntity === 'logs') {
+ setSelectedEntityViews(logsViews);
+ } else if (selectedEntity === 'traces') {
+ setSelectedEntityViews(tracesViews);
+ } else if (selectedEntity === 'metrics') {
+ setSelectedEntityViews(metricsViews);
+ }
+ }, [selectedEntity, logsViews, tracesViews, metricsViews]);
const hasTracesViews = tracesViews.length > 0;
const hasLogsViews = logsViews.length > 0;
+ const hasMetricsViews = metricsViews.length > 0;
- const hasSavedViews = hasTracesViews || hasLogsViews;
+ const hasSavedViews = hasTracesViews || hasLogsViews || hasMetricsViews;
const { handleExplorerTabChange } = useHandleExplorerTabChange();
@@ -68,10 +86,16 @@ export default function SavedViews({
entity: selectedEntity,
});
- const currentViewDetails = getViewDetailsUsingViewKey(
- view.id,
- selectedEntity === 'logs' ? logsViews : tracesViews,
- );
+ let currentViews: ViewProps[] = [];
+ if (selectedEntity === 'logs') {
+ currentViews = logsViews;
+ } else if (selectedEntity === 'traces') {
+ currentViews = tracesViews;
+ } else if (selectedEntity === 'metrics') {
+ currentViews = metricsViews;
+ }
+
+ const currentViewDetails = getViewDetailsUsingViewKey(view.id, currentViews);
if (!currentViewDetails) return;
const { query, name, id, panelType: currentPanelType } = currentViewDetails;
@@ -94,6 +118,32 @@ export default function SavedViews({
}
}, [hasSavedViews, onUpdateChecklistDoneItem, loadingUserPreferences]);
+ const footerLink = useMemo(() => {
+ if (selectedEntity === 'logs') {
+ return ROUTES.LOGS_SAVE_VIEWS;
+ }
+ if (selectedEntity === 'traces') {
+ return ROUTES.TRACES_SAVE_VIEWS;
+ }
+ if (selectedEntity === 'metrics') {
+ return ROUTES.METRICS_EXPLORER_VIEWS;
+ }
+ return '';
+ }, [selectedEntity]);
+
+ const getStartedLink = useMemo(() => {
+ if (selectedEntity === 'logs') {
+ return ROUTES.LOGS_EXPLORER;
+ }
+ if (selectedEntity === 'traces') {
+ return ROUTES.TRACES_EXPLORER;
+ }
+ if (selectedEntity === 'metrics') {
+ return ROUTES.METRICS_EXPLORER_EXPLORER;
+ }
+ return '';
+ }, [selectedEntity]);
+
const emptyStateCard = (): JSX.Element => (
@@ -115,13 +165,7 @@ export default function SavedViews({
{user?.role !== USER_ROLES.VIEWER && (
-
+
)}
+
+ {selectedEntity === 'metrics' && metricsViewsError && (
+
+
+ Oops, something went wrong while loading your saved views.
+
+
+ )}
);
@@ -246,11 +298,19 @@ export default function SavedViews({
logEvent('Homepage: Saved views switched', {
tab,
});
- setSelectedEntityViews(tab === 'logs' ? logsViews : tracesViews);
+ let currentViews: ViewProps[] = [];
+ if (tab === 'logs') {
+ currentViews = logsViews;
+ } else if (tab === 'traces') {
+ currentViews = tracesViews;
+ } else if (tab === 'metrics') {
+ currentViews = metricsViews;
+ }
+ setSelectedEntityViews(currentViews);
setSelectedEntity(tab);
};
- if (logsViewsLoading || tracesViewsLoading) {
+ if (logsViewsLoading || tracesViewsLoading || metricsViewsLoading) {
return (
@@ -260,7 +320,7 @@ export default function SavedViews({
);
}
- if (logsViewsError || tracesViewsError) {
+ if (logsViewsError || tracesViewsError || metricsViewsError) {
return (
@@ -299,6 +359,16 @@ export default function SavedViews({
>
Traces
+
@@ -312,13 +382,7 @@ export default function SavedViews({
{selectedEntityViews.length > 0 && (
-
+