mirror of
https://github.com/SigNoz/signoz.git
synced 2026-08-05 12:40:46 +01:00
Compare commits
1 Commits
v0.101.0
...
fix/pass_t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5165d1665 |
@@ -176,7 +176,7 @@ services:
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
signoz:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz:v0.101.0
|
||||
image: signoz/signoz:v0.100.1
|
||||
command:
|
||||
- --config=/root/config/prometheus.yml
|
||||
ports:
|
||||
|
||||
@@ -117,7 +117,7 @@ services:
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
signoz:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz:v0.101.0
|
||||
image: signoz/signoz:v0.100.1
|
||||
command:
|
||||
- --config=/root/config/prometheus.yml
|
||||
ports:
|
||||
|
||||
@@ -179,7 +179,7 @@ services:
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
signoz:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz:${VERSION:-v0.101.0}
|
||||
image: signoz/signoz:${VERSION:-v0.100.1}
|
||||
container_name: signoz
|
||||
command:
|
||||
- --config=/root/config/prometheus.yml
|
||||
|
||||
@@ -111,7 +111,7 @@ services:
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
signoz:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz:${VERSION:-v0.101.0}
|
||||
image: signoz/signoz:${VERSION:-v0.100.1}
|
||||
container_name: signoz
|
||||
command:
|
||||
- --config=/root/config/prometheus.yml
|
||||
|
||||
@@ -274,7 +274,7 @@ function App(): JSX.Element {
|
||||
chat_settings: {
|
||||
app_id: process.env.PYLON_APP_ID,
|
||||
email: user.email,
|
||||
name: user.displayName || user.email,
|
||||
name: user.displayName,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { LogEventAxiosInstance as axios } from 'api';
|
||||
import { ApiBaseInstance as axios } from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
/* eslint-disable sonarjs/no-duplicate-string */
|
||||
import axios from 'api';
|
||||
import { ApiBaseInstance } from 'api';
|
||||
|
||||
import { getFieldKeys } from '../getFieldKeys';
|
||||
|
||||
// Mock the API instance
|
||||
jest.mock('api', () => ({
|
||||
get: jest.fn(),
|
||||
ApiBaseInstance: {
|
||||
get: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('getFieldKeys API', () => {
|
||||
@@ -29,33 +31,33 @@ describe('getFieldKeys API', () => {
|
||||
|
||||
it('should call API with correct parameters when no args provided', async () => {
|
||||
// Mock successful API response
|
||||
(axios.get as jest.Mock).mockResolvedValueOnce(mockSuccessResponse);
|
||||
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce(mockSuccessResponse);
|
||||
|
||||
// Call function with no parameters
|
||||
await getFieldKeys();
|
||||
|
||||
// Verify API was called correctly with empty params object
|
||||
expect(axios.get).toHaveBeenCalledWith('/fields/keys', {
|
||||
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/keys', {
|
||||
params: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should call API with signal parameter when provided', async () => {
|
||||
// Mock successful API response
|
||||
(axios.get as jest.Mock).mockResolvedValueOnce(mockSuccessResponse);
|
||||
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce(mockSuccessResponse);
|
||||
|
||||
// Call function with signal parameter
|
||||
await getFieldKeys('traces');
|
||||
|
||||
// Verify API was called with signal parameter
|
||||
expect(axios.get).toHaveBeenCalledWith('/fields/keys', {
|
||||
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/keys', {
|
||||
params: { signal: 'traces' },
|
||||
});
|
||||
});
|
||||
|
||||
it('should call API with name parameter when provided', async () => {
|
||||
// Mock successful API response
|
||||
(axios.get as jest.Mock).mockResolvedValueOnce({
|
||||
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
|
||||
status: 200,
|
||||
data: {
|
||||
status: 'success',
|
||||
@@ -70,14 +72,14 @@ describe('getFieldKeys API', () => {
|
||||
await getFieldKeys(undefined, 'service');
|
||||
|
||||
// Verify API was called with name parameter
|
||||
expect(axios.get).toHaveBeenCalledWith('/fields/keys', {
|
||||
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/keys', {
|
||||
params: { name: 'service' },
|
||||
});
|
||||
});
|
||||
|
||||
it('should call API with both signal and name when provided', async () => {
|
||||
// Mock successful API response
|
||||
(axios.get as jest.Mock).mockResolvedValueOnce({
|
||||
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
|
||||
status: 200,
|
||||
data: {
|
||||
status: 'success',
|
||||
@@ -92,14 +94,14 @@ describe('getFieldKeys API', () => {
|
||||
await getFieldKeys('logs', 'service');
|
||||
|
||||
// Verify API was called with both parameters
|
||||
expect(axios.get).toHaveBeenCalledWith('/fields/keys', {
|
||||
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/keys', {
|
||||
params: { signal: 'logs', name: 'service' },
|
||||
});
|
||||
});
|
||||
|
||||
it('should return properly formatted response', async () => {
|
||||
// Mock API to return our response
|
||||
(axios.get as jest.Mock).mockResolvedValueOnce(mockSuccessResponse);
|
||||
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce(mockSuccessResponse);
|
||||
|
||||
// Call the function
|
||||
const result = await getFieldKeys('traces');
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
/* eslint-disable sonarjs/no-duplicate-string */
|
||||
import axios from 'api';
|
||||
import { ApiBaseInstance } from 'api';
|
||||
|
||||
import { getFieldValues } from '../getFieldValues';
|
||||
|
||||
// Mock the API instance
|
||||
jest.mock('api', () => ({
|
||||
get: jest.fn(),
|
||||
ApiBaseInstance: {
|
||||
get: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('getFieldValues API', () => {
|
||||
@@ -15,7 +17,7 @@ describe('getFieldValues API', () => {
|
||||
|
||||
it('should call the API with correct parameters (no options)', async () => {
|
||||
// Mock API response
|
||||
(axios.get as jest.Mock).mockResolvedValueOnce({
|
||||
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
|
||||
status: 200,
|
||||
data: {
|
||||
status: 'success',
|
||||
@@ -32,14 +34,14 @@ describe('getFieldValues API', () => {
|
||||
await getFieldValues();
|
||||
|
||||
// Verify API was called correctly with empty params
|
||||
expect(axios.get).toHaveBeenCalledWith('/fields/values', {
|
||||
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/values', {
|
||||
params: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should call the API with signal parameter', async () => {
|
||||
// Mock API response
|
||||
(axios.get as jest.Mock).mockResolvedValueOnce({
|
||||
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
|
||||
status: 200,
|
||||
data: {
|
||||
status: 'success',
|
||||
@@ -56,14 +58,14 @@ describe('getFieldValues API', () => {
|
||||
await getFieldValues('traces');
|
||||
|
||||
// Verify API was called with signal parameter
|
||||
expect(axios.get).toHaveBeenCalledWith('/fields/values', {
|
||||
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/values', {
|
||||
params: { signal: 'traces' },
|
||||
});
|
||||
});
|
||||
|
||||
it('should call the API with name parameter', async () => {
|
||||
// Mock API response
|
||||
(axios.get as jest.Mock).mockResolvedValueOnce({
|
||||
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
|
||||
status: 200,
|
||||
data: {
|
||||
status: 'success',
|
||||
@@ -80,14 +82,14 @@ describe('getFieldValues API', () => {
|
||||
await getFieldValues(undefined, 'service.name');
|
||||
|
||||
// Verify API was called with name parameter
|
||||
expect(axios.get).toHaveBeenCalledWith('/fields/values', {
|
||||
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/values', {
|
||||
params: { name: 'service.name' },
|
||||
});
|
||||
});
|
||||
|
||||
it('should call the API with value parameter', async () => {
|
||||
// Mock API response
|
||||
(axios.get as jest.Mock).mockResolvedValueOnce({
|
||||
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
|
||||
status: 200,
|
||||
data: {
|
||||
status: 'success',
|
||||
@@ -104,14 +106,14 @@ describe('getFieldValues API', () => {
|
||||
await getFieldValues(undefined, 'service.name', 'front');
|
||||
|
||||
// Verify API was called with value parameter
|
||||
expect(axios.get).toHaveBeenCalledWith('/fields/values', {
|
||||
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/values', {
|
||||
params: { name: 'service.name', searchText: 'front' },
|
||||
});
|
||||
});
|
||||
|
||||
it('should call the API with time range parameters', async () => {
|
||||
// Mock API response
|
||||
(axios.get as jest.Mock).mockResolvedValueOnce({
|
||||
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce({
|
||||
status: 200,
|
||||
data: {
|
||||
status: 'success',
|
||||
@@ -136,7 +138,7 @@ describe('getFieldValues API', () => {
|
||||
);
|
||||
|
||||
// Verify API was called with time range parameters (converted to milliseconds)
|
||||
expect(axios.get).toHaveBeenCalledWith('/fields/values', {
|
||||
expect(ApiBaseInstance.get).toHaveBeenCalledWith('/fields/values', {
|
||||
params: {
|
||||
signal: 'logs',
|
||||
name: 'service.name',
|
||||
@@ -163,7 +165,7 @@ describe('getFieldValues API', () => {
|
||||
},
|
||||
};
|
||||
|
||||
(axios.get as jest.Mock).mockResolvedValueOnce(mockResponse);
|
||||
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce(mockResponse);
|
||||
|
||||
// Call the function
|
||||
const result = await getFieldValues('traces', 'mixed.values');
|
||||
@@ -194,7 +196,7 @@ describe('getFieldValues API', () => {
|
||||
};
|
||||
|
||||
// Mock API to return our response
|
||||
(axios.get as jest.Mock).mockResolvedValueOnce(mockApiResponse);
|
||||
(ApiBaseInstance.get as jest.Mock).mockResolvedValueOnce(mockApiResponse);
|
||||
|
||||
// Call the function
|
||||
const result = await getFieldValues('traces', 'service.name');
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import axios from 'api';
|
||||
import { ApiBaseInstance } from 'api';
|
||||
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
|
||||
@@ -24,7 +24,7 @@ export const getFieldKeys = async (
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.get('/fields/keys', { params });
|
||||
const response = await ApiBaseInstance.get('/fields/keys', { params });
|
||||
|
||||
return {
|
||||
httpStatusCode: response.status,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable sonarjs/cognitive-complexity */
|
||||
import axios from 'api';
|
||||
import { ApiBaseInstance } from 'api';
|
||||
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
|
||||
@@ -47,7 +47,7 @@ export const getFieldValues = async (
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.get('/fields/values', { params });
|
||||
const response = await ApiBaseInstance.get('/fields/values', { params });
|
||||
|
||||
// Normalize values from different types (stringValues, boolValues, etc.)
|
||||
if (response.data?.data?.values) {
|
||||
|
||||
@@ -86,9 +86,8 @@ const interceptorRejected = async (
|
||||
|
||||
if (
|
||||
response.status === 401 &&
|
||||
// if the session rotate call or the create session errors out with 401 or the delete sessions call returns 401 then we do not retry!
|
||||
// if the session rotate call errors out with 401 or the delete sessions call returns 401 then we do not retry!
|
||||
response.config.url !== '/sessions/rotate' &&
|
||||
response.config.url !== '/sessions/email_password' &&
|
||||
!(
|
||||
response.config.url === '/sessions' && response.config.method === 'delete'
|
||||
)
|
||||
@@ -200,15 +199,15 @@ ApiV5Instance.interceptors.request.use(interceptorsRequestResponse);
|
||||
//
|
||||
|
||||
// axios Base
|
||||
export const LogEventAxiosInstance = axios.create({
|
||||
export const ApiBaseInstance = axios.create({
|
||||
baseURL: `${ENVIRONMENT.baseURL}${apiV1}`,
|
||||
});
|
||||
|
||||
LogEventAxiosInstance.interceptors.response.use(
|
||||
ApiBaseInstance.interceptors.response.use(
|
||||
interceptorsResponse,
|
||||
interceptorRejectedBase,
|
||||
);
|
||||
LogEventAxiosInstance.interceptors.request.use(interceptorsRequestResponse);
|
||||
ApiBaseInstance.interceptors.request.use(interceptorsRequestResponse);
|
||||
//
|
||||
|
||||
// gateway Api V1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import axios from 'api';
|
||||
import { ApiBaseInstance } from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError, AxiosResponse } from 'axios';
|
||||
import { baseAutoCompleteIdKeysOrder } from 'constants/queryBuilder';
|
||||
@@ -17,7 +17,7 @@ export const getHostAttributeKeys = async (
|
||||
try {
|
||||
const response: AxiosResponse<{
|
||||
data: IQueryAutocompleteResponse;
|
||||
}> = await axios.get(
|
||||
}> = await ApiBaseInstance.get(
|
||||
`/${entity}/attribute_keys?dataSource=metrics&searchText=${searchText}`,
|
||||
{
|
||||
params: {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import axios from 'api';
|
||||
import { ApiBaseInstance } from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||
@@ -20,7 +20,7 @@ const getOnboardingStatus = async (props: {
|
||||
}): Promise<SuccessResponse<OnboardingStatusResponse> | ErrorResponse> => {
|
||||
const { endpointService, ...rest } = props;
|
||||
try {
|
||||
const response = await axios.post(
|
||||
const response = await ApiBaseInstance.post(
|
||||
`/messaging-queues/kafka/onboarding/${endpointService || 'consumers'}`,
|
||||
rest,
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import axios from 'api';
|
||||
import { ApiBaseInstance } from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
@@ -9,7 +9,7 @@ const getCustomFilters = async (
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
const { signal } = props;
|
||||
try {
|
||||
const response = await axios.get(`/orgs/me/filters/${signal}`);
|
||||
const response = await ApiBaseInstance.get(`orgs/me/filters/${signal}`);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import axios from 'api';
|
||||
import { ApiBaseInstance } from 'api';
|
||||
import { AxiosError } from 'axios';
|
||||
import { SuccessResponse } from 'types/api';
|
||||
import { UpdateCustomFiltersProps } from 'types/api/quickFilters/updateCustomFilters';
|
||||
@@ -6,7 +6,7 @@ import { UpdateCustomFiltersProps } from 'types/api/quickFilters/updateCustomFil
|
||||
const updateCustomFiltersAPI = async (
|
||||
props: UpdateCustomFiltersProps,
|
||||
): Promise<SuccessResponse<void> | AxiosError> =>
|
||||
axios.put(`/orgs/me/filters`, {
|
||||
ApiBaseInstance.put(`orgs/me/filters`, {
|
||||
...props.data,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import axios from 'api';
|
||||
import { ApiBaseInstance } from 'api';
|
||||
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
|
||||
@@ -9,12 +9,15 @@ const listOverview = async (
|
||||
): Promise<SuccessResponseV2<PayloadProps>> => {
|
||||
const { start, end, show_ip: showIp, filter } = props;
|
||||
try {
|
||||
const response = await axios.post(`/third-party-apis/overview/list`, {
|
||||
start,
|
||||
end,
|
||||
show_ip: showIp,
|
||||
filter,
|
||||
});
|
||||
const response = await ApiBaseInstance.post(
|
||||
`/third-party-apis/overview/list`,
|
||||
{
|
||||
start,
|
||||
end,
|
||||
show_ip: showIp,
|
||||
filter,
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
httpStatusCode: response.status,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import axios from 'api';
|
||||
import { ApiBaseInstance } from 'api';
|
||||
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
|
||||
@@ -11,7 +11,7 @@ const getSpanPercentiles = async (
|
||||
props: GetSpanPercentilesProps,
|
||||
): Promise<SuccessResponseV2<GetSpanPercentilesResponseDataProps>> => {
|
||||
try {
|
||||
const response = await axios.post('/span_percentile', {
|
||||
const response = await ApiBaseInstance.post('/span_percentile', {
|
||||
...props,
|
||||
});
|
||||
|
||||
|
||||
@@ -836,7 +836,7 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
|
||||
})}
|
||||
data-overlayscrollbars-initialize
|
||||
>
|
||||
<Sentry.ErrorBoundary fallback={<ErrorBoundaryFallback />} key={pathname}>
|
||||
<Sentry.ErrorBoundary fallback={<ErrorBoundaryFallback />}>
|
||||
<LayoutContent data-overlayscrollbars-initialize>
|
||||
<OverlayScrollbar>
|
||||
<ChildrenContainer>
|
||||
|
||||
@@ -17,6 +17,12 @@ export const Card = styled(CardComponent)<CardProps>`
|
||||
overflow: hidden;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--bg-slate-500);
|
||||
background: linear-gradient(
|
||||
0deg,
|
||||
rgba(171, 189, 255, 0) 0%,
|
||||
rgba(171, 189, 255, 0) 100%
|
||||
),
|
||||
#0b0c0e;
|
||||
|
||||
${({ isDarkMode }): StyledCSS =>
|
||||
!isDarkMode &&
|
||||
|
||||
@@ -90,9 +90,8 @@ export function QueryTable({
|
||||
column: any,
|
||||
tableColumns: any,
|
||||
): void => {
|
||||
e.stopPropagation();
|
||||
if (isQueryTypeBuilder && enableDrillDown) {
|
||||
e.stopPropagation();
|
||||
|
||||
onClick({ x: e.clientX, y: e.clientY }, { record, column, tableColumns });
|
||||
}
|
||||
},
|
||||
|
||||
@@ -245,81 +245,5 @@ describe('useQueryBuilderOperations - Empty Aggregate Attribute Type', () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should reset operators when going from gauge -> empty -> gauge', () => {
|
||||
// Start with a gauge metric
|
||||
const gaugeQuery: IBuilderQuery = {
|
||||
...defaultMockQuery,
|
||||
aggregateAttribute: {
|
||||
key: 'original_gauge',
|
||||
dataType: DataTypes.Float64,
|
||||
type: ATTRIBUTE_TYPES.GAUGE,
|
||||
} as BaseAutocompleteData,
|
||||
aggregations: [
|
||||
{
|
||||
timeAggregation: MetricAggregateOperator.COUNT_DISTINCT,
|
||||
metricName: 'original_gauge',
|
||||
temporality: '',
|
||||
spaceAggregation: '',
|
||||
},
|
||||
],
|
||||
};
|
||||
const { result, rerender } = renderHook(
|
||||
({ query }) =>
|
||||
useQueryOperations({
|
||||
query,
|
||||
index: 0,
|
||||
entityVersion: ENTITY_VERSION_V5,
|
||||
}),
|
||||
{
|
||||
initialProps: { query: gaugeQuery },
|
||||
},
|
||||
);
|
||||
|
||||
// Re-render with empty attribute
|
||||
const emptyAttribute: BaseAutocompleteData = {
|
||||
key: '',
|
||||
dataType: DataTypes.Float64,
|
||||
type: '',
|
||||
};
|
||||
const emptyQuery: IBuilderQuery = {
|
||||
...defaultMockQuery,
|
||||
aggregateAttribute: emptyAttribute,
|
||||
aggregations: [
|
||||
{
|
||||
timeAggregation: MetricAggregateOperator.COUNT,
|
||||
metricName: '',
|
||||
temporality: '',
|
||||
spaceAggregation: MetricAggregateOperator.SUM,
|
||||
},
|
||||
],
|
||||
};
|
||||
rerender({ query: emptyQuery });
|
||||
|
||||
// Change to a new gauge metric
|
||||
const newGaugeAttribute: BaseAutocompleteData = {
|
||||
key: 'new_gauge',
|
||||
dataType: DataTypes.Float64,
|
||||
type: ATTRIBUTE_TYPES.GAUGE,
|
||||
};
|
||||
act(() => {
|
||||
result.current.handleChangeAggregatorAttribute(newGaugeAttribute);
|
||||
});
|
||||
|
||||
expect(mockHandleSetQueryData).toHaveBeenLastCalledWith(
|
||||
0,
|
||||
expect.objectContaining({
|
||||
aggregateAttribute: newGaugeAttribute,
|
||||
aggregations: [
|
||||
{
|
||||
timeAggregation: MetricAggregateOperator.AVG,
|
||||
metricName: 'new_gauge',
|
||||
temporality: '',
|
||||
spaceAggregation: '',
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -89,8 +89,6 @@ export const useQueryOperations: UseQueryOperations = ({
|
||||
name: metricName,
|
||||
type: metricType,
|
||||
});
|
||||
} else {
|
||||
setPreviousMetricInfo(null);
|
||||
}
|
||||
}
|
||||
}, [query]);
|
||||
@@ -297,6 +295,7 @@ export const useQueryOperations: UseQueryOperations = ({
|
||||
|
||||
if (!isEditMode) {
|
||||
// Get current metric info
|
||||
const currentMetricName = newQuery.aggregateAttribute?.key || '';
|
||||
const currentMetricType = newQuery.aggregateAttribute?.type || '';
|
||||
|
||||
const prevMetricType = previousMetricInfo?.type
|
||||
@@ -379,6 +378,14 @@ export const useQueryOperations: UseQueryOperations = ({
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Update the tracked metric info for next comparison only if we have valid data
|
||||
if (currentMetricName && currentMetricType) {
|
||||
setPreviousMetricInfo({
|
||||
name: currentMetricName,
|
||||
type: currentMetricType,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,20 +16,8 @@
|
||||
|
||||
// https://tobyzerner.github.io/placement.js/dist/index.js
|
||||
|
||||
/**
|
||||
* Positions an element (tooltip/popover) relative to a reference element.
|
||||
* Automatically flips to the opposite side if there's insufficient space.
|
||||
*
|
||||
* @param element - The HTMLElement to position
|
||||
* @param reference - Reference element/Range or bounding rect
|
||||
* @param side - Preferred side: 'top', 'bottom', 'left', 'right' (default: 'bottom')
|
||||
* @param align - Alignment: 'start', 'center', 'end' (default: 'center')
|
||||
* @param options - Optional bounds for constraining the element
|
||||
* - bound: Custom boundary rect/element
|
||||
* - followCursor: { x, y } - If provided, tooltip follows cursor with smart positioning
|
||||
*/
|
||||
export const placement = (function () {
|
||||
const AXIS_PROPS = {
|
||||
const e = {
|
||||
size: ['height', 'width'],
|
||||
clientSize: ['clientHeight', 'clientWidth'],
|
||||
offsetSize: ['offsetHeight', 'offsetWidth'],
|
||||
@@ -40,241 +28,87 @@ export const placement = (function () {
|
||||
marginAfter: ['marginBottom', 'marginRight'],
|
||||
scrollOffset: ['pageYOffset', 'pageXOffset'],
|
||||
};
|
||||
|
||||
function extractRect(source) {
|
||||
return {
|
||||
top: source.top,
|
||||
bottom: source.bottom,
|
||||
left: source.left,
|
||||
right: source.right,
|
||||
};
|
||||
function t(e) {
|
||||
return { top: e.top, bottom: e.bottom, left: e.left, right: e.right };
|
||||
}
|
||||
|
||||
return function (element, reference, side, align, options) {
|
||||
// Default parameters
|
||||
void 0 === side && (side = 'bottom');
|
||||
void 0 === align && (align = 'center');
|
||||
void 0 === options && (options = {});
|
||||
|
||||
// Handle cursor following mode
|
||||
if (options.followCursor) {
|
||||
const cursorX = options.followCursor.x;
|
||||
const cursorY = options.followCursor.y;
|
||||
const offset = options.followCursor.offset || 10; // Default 10px offset from cursor
|
||||
|
||||
element.style.position = 'absolute';
|
||||
element.style.maxWidth = '';
|
||||
element.style.maxHeight = '';
|
||||
|
||||
const elementWidth = element.offsetWidth;
|
||||
const elementHeight = element.offsetHeight;
|
||||
|
||||
// Use viewport bounds for cursor following (not chart bounds)
|
||||
const viewportBounds = {
|
||||
top: 0,
|
||||
left: 0,
|
||||
bottom: window.innerHeight,
|
||||
right: window.innerWidth,
|
||||
};
|
||||
|
||||
// Vertical positioning: follow cursor Y with offset, clamped to viewport
|
||||
const topPosition = cursorY + offset;
|
||||
const clampedTop = Math.max(
|
||||
viewportBounds.top,
|
||||
Math.min(topPosition, viewportBounds.bottom - elementHeight),
|
||||
);
|
||||
element.style.top = `${clampedTop}px`;
|
||||
element.style.bottom = 'auto';
|
||||
|
||||
// Horizontal positioning: auto-detect left or right based on available space
|
||||
const spaceOnRight = viewportBounds.right - cursorX;
|
||||
const spaceOnLeft = cursorX - viewportBounds.left;
|
||||
|
||||
if (spaceOnRight >= elementWidth + offset) {
|
||||
// Enough space on the right
|
||||
element.style.left = `${cursorX + offset}px`;
|
||||
element.style.right = 'auto';
|
||||
element.dataset.side = 'right';
|
||||
} else if (spaceOnLeft >= elementWidth + offset) {
|
||||
// Not enough space on right, use left
|
||||
element.style.left = `${cursorX - elementWidth - offset}px`;
|
||||
element.style.right = 'auto';
|
||||
element.dataset.side = 'left';
|
||||
} else if (spaceOnRight > spaceOnLeft) {
|
||||
// Not enough space on either side, pick the side with more space
|
||||
const leftPos = cursorX + offset;
|
||||
const clampedLeft = Math.max(
|
||||
viewportBounds.left,
|
||||
Math.min(leftPos, viewportBounds.right - elementWidth),
|
||||
);
|
||||
element.style.left = `${clampedLeft}px`;
|
||||
element.style.right = 'auto';
|
||||
element.dataset.side = 'right';
|
||||
} else {
|
||||
const leftPos = cursorX - elementWidth - offset;
|
||||
const clampedLeft = Math.max(
|
||||
viewportBounds.left,
|
||||
Math.min(leftPos, viewportBounds.right - elementWidth),
|
||||
);
|
||||
element.style.left = `${clampedLeft}px`;
|
||||
element.style.right = 'auto';
|
||||
element.dataset.side = 'left';
|
||||
}
|
||||
|
||||
element.dataset.align = 'cursor';
|
||||
return; // Exit early, don't run normal positioning logic
|
||||
}
|
||||
|
||||
// Normalize reference to rect object
|
||||
(reference instanceof Element || reference instanceof Range) &&
|
||||
(reference = extractRect(reference.getBoundingClientRect()));
|
||||
|
||||
// Create anchor rect with swapped opposite edges for positioning
|
||||
const anchorRect = {
|
||||
top: reference.bottom,
|
||||
bottom: reference.top,
|
||||
left: reference.right,
|
||||
right: reference.left,
|
||||
...reference,
|
||||
return function (o, r, f, a, i) {
|
||||
void 0 === f && (f = 'bottom'),
|
||||
void 0 === a && (a = 'center'),
|
||||
void 0 === i && (i = {}),
|
||||
(r instanceof Element || r instanceof Range) &&
|
||||
(r = t(r.getBoundingClientRect()));
|
||||
const n = {
|
||||
top: r.bottom,
|
||||
bottom: r.top,
|
||||
left: r.right,
|
||||
right: r.left,
|
||||
...r,
|
||||
};
|
||||
|
||||
// Viewport bounds (can be overridden via options.bound)
|
||||
const bounds = {
|
||||
const s = {
|
||||
top: 0,
|
||||
left: 0,
|
||||
bottom: window.innerHeight,
|
||||
right: window.innerWidth,
|
||||
};
|
||||
|
||||
options.bound &&
|
||||
((options.bound instanceof Element || options.bound instanceof Range) &&
|
||||
(options.bound = extractRect(options.bound.getBoundingClientRect())),
|
||||
Object.assign(bounds, options.bound));
|
||||
|
||||
const styles = getComputedStyle(element);
|
||||
const isVertical = side === 'top' || side === 'bottom';
|
||||
|
||||
// Build axis property maps based on orientation
|
||||
const mainAxis = {}; // Properties for the main positioning axis
|
||||
const crossAxis = {}; // Properties for the perpendicular axis
|
||||
|
||||
for (const prop in AXIS_PROPS) {
|
||||
mainAxis[prop] = AXIS_PROPS[prop][isVertical ? 0 : 1];
|
||||
crossAxis[prop] = AXIS_PROPS[prop][isVertical ? 1 : 0];
|
||||
}
|
||||
|
||||
// Reset element positioning
|
||||
element.style.position = 'absolute';
|
||||
element.style.maxWidth = '';
|
||||
element.style.maxHeight = '';
|
||||
|
||||
// Cross-axis: calculate and apply max size constraint
|
||||
const crossMarginBefore = parseInt(styles[crossAxis.marginBefore]);
|
||||
const crossMarginAfter = parseInt(styles[crossAxis.marginAfter]);
|
||||
const crossMarginTotal = crossMarginBefore + crossMarginAfter;
|
||||
const crossAvailableSpace =
|
||||
bounds[crossAxis.after] - bounds[crossAxis.before] - crossMarginTotal;
|
||||
const crossMaxSize = parseInt(styles[crossAxis.maxSize]);
|
||||
|
||||
(!crossMaxSize || crossAvailableSpace < crossMaxSize) &&
|
||||
(element.style[crossAxis.maxSize] = `${crossAvailableSpace}px`);
|
||||
|
||||
// Main-axis: calculate space on both sides
|
||||
const mainMarginTotal =
|
||||
parseInt(styles[mainAxis.marginBefore]) +
|
||||
parseInt(styles[mainAxis.marginAfter]);
|
||||
const spaceBefore =
|
||||
anchorRect[mainAxis.before] - bounds[mainAxis.before] - mainMarginTotal;
|
||||
const spaceAfter =
|
||||
bounds[mainAxis.after] - anchorRect[mainAxis.after] - mainMarginTotal;
|
||||
|
||||
// Auto-flip to the side with more space if needed
|
||||
((side === mainAxis.before && element[mainAxis.offsetSize] > spaceBefore) ||
|
||||
(side === mainAxis.after && element[mainAxis.offsetSize] > spaceAfter)) &&
|
||||
(side = spaceBefore > spaceAfter ? mainAxis.before : mainAxis.after);
|
||||
|
||||
// Apply main-axis max size constraint
|
||||
const mainAvailableSpace =
|
||||
side === mainAxis.before ? spaceBefore : spaceAfter;
|
||||
const mainMaxSize = parseInt(styles[mainAxis.maxSize]);
|
||||
|
||||
(!mainMaxSize || mainAvailableSpace < mainMaxSize) &&
|
||||
(element.style[mainAxis.maxSize] = `${mainAvailableSpace}px`);
|
||||
|
||||
// Position on main axis
|
||||
const mainScrollOffset = window[mainAxis.scrollOffset];
|
||||
const clampMainPosition = function (pos) {
|
||||
return Math.max(
|
||||
bounds[mainAxis.before],
|
||||
Math.min(
|
||||
pos,
|
||||
bounds[mainAxis.after] - element[mainAxis.offsetSize] - mainMarginTotal,
|
||||
),
|
||||
);
|
||||
i.bound &&
|
||||
((i.bound instanceof Element || i.bound instanceof Range) &&
|
||||
(i.bound = t(i.bound.getBoundingClientRect())),
|
||||
Object.assign(s, i.bound));
|
||||
const l = getComputedStyle(o);
|
||||
const m = {};
|
||||
const b = {};
|
||||
for (const g in e)
|
||||
(m[g] = e[g][f === 'top' || f === 'bottom' ? 0 : 1]),
|
||||
(b[g] = e[g][f === 'top' || f === 'bottom' ? 1 : 0]);
|
||||
(o.style.position = 'absolute'),
|
||||
(o.style.maxWidth = ''),
|
||||
(o.style.maxHeight = '');
|
||||
const d = parseInt(l[b.marginBefore]);
|
||||
const c = parseInt(l[b.marginAfter]);
|
||||
const u = d + c;
|
||||
const p = s[b.after] - s[b.before] - u;
|
||||
const h = parseInt(l[b.maxSize]);
|
||||
(!h || p < h) && (o.style[b.maxSize] = `${p}px`);
|
||||
const x = parseInt(l[m.marginBefore]) + parseInt(l[m.marginAfter]);
|
||||
const y = n[m.before] - s[m.before] - x;
|
||||
const z = s[m.after] - n[m.after] - x;
|
||||
((f === m.before && o[m.offsetSize] > y) ||
|
||||
(f === m.after && o[m.offsetSize] > z)) &&
|
||||
(f = y > z ? m.before : m.after);
|
||||
const S = f === m.before ? y : z;
|
||||
const v = parseInt(l[m.maxSize]);
|
||||
(!v || S < v) && (o.style[m.maxSize] = `${S}px`);
|
||||
const w = window[m.scrollOffset];
|
||||
const O = function (e) {
|
||||
return Math.max(s[m.before], Math.min(e, s[m.after] - o[m.offsetSize] - x));
|
||||
};
|
||||
|
||||
side === mainAxis.before
|
||||
? ((element.style[mainAxis.before] = `${
|
||||
mainScrollOffset +
|
||||
clampMainPosition(
|
||||
anchorRect[mainAxis.before] -
|
||||
element[mainAxis.offsetSize] -
|
||||
mainMarginTotal,
|
||||
)
|
||||
}px`),
|
||||
(element.style[mainAxis.after] = 'auto'))
|
||||
: ((element.style[mainAxis.before] = `${
|
||||
mainScrollOffset + clampMainPosition(anchorRect[mainAxis.after])
|
||||
}px`),
|
||||
(element.style[mainAxis.after] = 'auto'));
|
||||
|
||||
// Position on cross axis based on alignment
|
||||
const crossScrollOffset = window[crossAxis.scrollOffset];
|
||||
const clampCrossPosition = function (pos) {
|
||||
return Math.max(
|
||||
bounds[crossAxis.before],
|
||||
Math.min(
|
||||
pos,
|
||||
bounds[crossAxis.after] - element[crossAxis.offsetSize] - crossMarginTotal,
|
||||
),
|
||||
);
|
||||
f === m.before
|
||||
? ((o.style[m.before] = `${w + O(n[m.before] - o[m.offsetSize] - x)}px`),
|
||||
(o.style[m.after] = 'auto'))
|
||||
: ((o.style[m.before] = `${w + O(n[m.after])}px`),
|
||||
(o.style[m.after] = 'auto'));
|
||||
const B = window[b.scrollOffset];
|
||||
const I = function (e) {
|
||||
return Math.max(s[b.before], Math.min(e, s[b.after] - o[b.offsetSize] - u));
|
||||
};
|
||||
|
||||
switch (align) {
|
||||
switch (a) {
|
||||
case 'start':
|
||||
(element.style[crossAxis.before] = `${
|
||||
crossScrollOffset +
|
||||
clampCrossPosition(anchorRect[crossAxis.before] - crossMarginBefore)
|
||||
}px`),
|
||||
(element.style[crossAxis.after] = 'auto');
|
||||
(o.style[b.before] = `${B + I(n[b.before] - d)}px`),
|
||||
(o.style[b.after] = 'auto');
|
||||
break;
|
||||
case 'end':
|
||||
(element.style[crossAxis.before] = 'auto'),
|
||||
(element.style[crossAxis.after] = `${
|
||||
crossScrollOffset +
|
||||
clampCrossPosition(
|
||||
document.documentElement[crossAxis.clientSize] -
|
||||
anchorRect[crossAxis.after] -
|
||||
crossMarginAfter,
|
||||
)
|
||||
(o.style[b.before] = 'auto'),
|
||||
(o.style[b.after] = `${
|
||||
B + I(document.documentElement[b.clientSize] - n[b.after] - c)
|
||||
}px`);
|
||||
break;
|
||||
default:
|
||||
// 'center'
|
||||
var crossSize = anchorRect[crossAxis.after] - anchorRect[crossAxis.before];
|
||||
(element.style[crossAxis.before] = `${
|
||||
crossScrollOffset +
|
||||
clampCrossPosition(
|
||||
anchorRect[crossAxis.before] +
|
||||
crossSize / 2 -
|
||||
element[crossAxis.offsetSize] / 2 -
|
||||
crossMarginBefore,
|
||||
)
|
||||
var H = n[b.after] - n[b.before];
|
||||
(o.style[b.before] = `${
|
||||
B + I(n[b.before] + H / 2 - o[b.offsetSize] / 2 - d)
|
||||
}px`),
|
||||
(element.style[crossAxis.after] = 'auto');
|
||||
(o.style[b.after] = 'auto');
|
||||
}
|
||||
|
||||
// Store final placement as data attributes
|
||||
(element.dataset.side = side), (element.dataset.align = align);
|
||||
(o.dataset.side = f), (o.dataset.align = a);
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -3,71 +3,7 @@ import { themeColors } from 'constants/theme';
|
||||
import { generateColor } from 'lib/uPlotLib/utils/generateColor';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
|
||||
function isSeriesValueValid(seriesValue: number | undefined | null): boolean {
|
||||
return (
|
||||
seriesValue !== undefined &&
|
||||
seriesValue !== null &&
|
||||
!Number.isNaN(seriesValue)
|
||||
);
|
||||
}
|
||||
|
||||
// Helper function to get the focused/highlighted series at a specific position
|
||||
function resolveSeriesColor(series: uPlot.Series, index: number): string {
|
||||
let color = '#000000';
|
||||
if (typeof series.stroke === 'string') {
|
||||
color = series.stroke;
|
||||
} else if (typeof series.fill === 'string') {
|
||||
color = series.fill;
|
||||
} else {
|
||||
const seriesLabel = series.label || `Series ${index}`;
|
||||
const isDarkMode = !document.body.classList.contains('lightMode');
|
||||
color = generateColor(
|
||||
seriesLabel,
|
||||
isDarkMode ? themeColors.chartcolors : themeColors.lightModeColor,
|
||||
);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
function getPreferredSeriesIndex(
|
||||
u: uPlot,
|
||||
timestampIndex: number,
|
||||
e: MouseEvent,
|
||||
): number {
|
||||
const bbox = u.over.getBoundingClientRect();
|
||||
const top = e.clientY - bbox.top;
|
||||
// Prefer series explicitly marked as focused
|
||||
for (let i = 1; i < u.series.length; i++) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const isSeriesFocused = u.series[i]?._focus === true;
|
||||
const isSeriesShown = u.series[i].show !== false;
|
||||
const seriesValue = u.data[i]?.[timestampIndex];
|
||||
if (isSeriesFocused && isSeriesShown && isSeriesValueValid(seriesValue)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: choose series with Y closest to mouse position
|
||||
let focusedSeriesIndex = -1;
|
||||
let closestPixelDiff = Infinity;
|
||||
for (let i = 1; i < u.series.length; i++) {
|
||||
const series = u.data[i];
|
||||
const seriesValue = series?.[timestampIndex];
|
||||
|
||||
if (isSeriesValueValid(seriesValue) && u.series[i].show !== false) {
|
||||
const yPx = u.valToPos(seriesValue as number, 'y');
|
||||
const diff = Math.abs(yPx - top);
|
||||
if (diff < closestPixelDiff) {
|
||||
closestPixelDiff = diff;
|
||||
focusedSeriesIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return focusedSeriesIndex;
|
||||
}
|
||||
|
||||
export const getFocusedSeriesAtPosition = (
|
||||
e: MouseEvent,
|
||||
u: uPlot,
|
||||
@@ -81,28 +17,74 @@ export const getFocusedSeriesAtPosition = (
|
||||
} | null => {
|
||||
const bbox = u.over.getBoundingClientRect();
|
||||
const left = e.clientX - bbox.left;
|
||||
const top = e.clientY - bbox.top;
|
||||
|
||||
const timestampIndex = u.posToIdx(left);
|
||||
const preferredIndex = getPreferredSeriesIndex(u, timestampIndex, e);
|
||||
let focusedSeriesIndex = -1;
|
||||
let closestPixelDiff = Infinity;
|
||||
|
||||
// Check all series (skip index 0 which is the x-axis)
|
||||
for (let i = 1; i < u.data.length; i++) {
|
||||
const series = u.data[i];
|
||||
const seriesValue = series[timestampIndex];
|
||||
|
||||
if (
|
||||
seriesValue !== undefined &&
|
||||
seriesValue !== null &&
|
||||
!Number.isNaN(seriesValue)
|
||||
) {
|
||||
const seriesYPx = u.valToPos(seriesValue, 'y');
|
||||
const pixelDiff = Math.abs(seriesYPx - top);
|
||||
|
||||
if (pixelDiff < closestPixelDiff) {
|
||||
closestPixelDiff = pixelDiff;
|
||||
focusedSeriesIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we found a focused series, return its data
|
||||
if (focusedSeriesIndex > 0) {
|
||||
const series = u.series[focusedSeriesIndex];
|
||||
const seriesValue = u.data[focusedSeriesIndex][timestampIndex];
|
||||
|
||||
// Ensure we have a valid value
|
||||
if (
|
||||
seriesValue !== undefined &&
|
||||
seriesValue !== null &&
|
||||
!Number.isNaN(seriesValue)
|
||||
) {
|
||||
// Get color - try series stroke first, then generate based on label
|
||||
let color = '#000000';
|
||||
if (typeof series.stroke === 'string') {
|
||||
color = series.stroke;
|
||||
} else if (typeof series.fill === 'string') {
|
||||
color = series.fill;
|
||||
} else {
|
||||
// Generate color based on series label (like the tooltip plugin does)
|
||||
const seriesLabel = series.label || `Series ${focusedSeriesIndex}`;
|
||||
// Detect theme mode by checking body class
|
||||
const isDarkMode = !document.body.classList.contains('lightMode');
|
||||
color = generateColor(
|
||||
seriesLabel,
|
||||
isDarkMode ? themeColors.chartcolors : themeColors.lightModeColor,
|
||||
);
|
||||
}
|
||||
|
||||
if (preferredIndex > 0) {
|
||||
const series = u.series[preferredIndex];
|
||||
const seriesValue = u.data[preferredIndex][timestampIndex];
|
||||
if (isSeriesValueValid(seriesValue)) {
|
||||
const color = resolveSeriesColor(series, preferredIndex);
|
||||
return {
|
||||
seriesIndex: preferredIndex,
|
||||
seriesName: series.label || `Series ${preferredIndex}`,
|
||||
seriesIndex: focusedSeriesIndex,
|
||||
seriesName: series.label || `Series ${focusedSeriesIndex}`,
|
||||
value: seriesValue as number,
|
||||
color,
|
||||
show: series.show !== false,
|
||||
isFocused: true,
|
||||
isFocused: true, // This indicates it's the highlighted/bold one
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export interface OnClickPluginOpts {
|
||||
onClick: (
|
||||
xValue: number,
|
||||
@@ -155,31 +137,50 @@ function onClickPlugin(opts: OnClickPluginOpts): uPlot.Plugin {
|
||||
const yValue = u.posToVal(event.offsetY, 'y');
|
||||
|
||||
// Get the focused/highlighted series (the one that would be bold in hover)
|
||||
const focusedSeriesData = getFocusedSeriesAtPosition(event, u);
|
||||
const focusedSeries = getFocusedSeriesAtPosition(event, u);
|
||||
|
||||
let metric = {};
|
||||
const { series } = u;
|
||||
const apiResult = opts.apiResponse?.data?.result || [];
|
||||
const outputMetric = {
|
||||
queryName: '',
|
||||
inFocusOrNot: false,
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
if (
|
||||
focusedSeriesData &&
|
||||
focusedSeriesData.seriesIndex <= apiResult.length
|
||||
) {
|
||||
const { metric: focusedMetric, queryName } =
|
||||
apiResult[focusedSeriesData.seriesIndex - 1] || {};
|
||||
metric = focusedMetric;
|
||||
outputMetric.queryName = queryName;
|
||||
outputMetric.inFocusOrNot = true;
|
||||
// this is to get the metric value of the focused series
|
||||
if (Array.isArray(series) && series.length > 0) {
|
||||
series.forEach((item, index) => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
if (item?.show && item?._focus) {
|
||||
const { metric: focusedMetric, queryName } = apiResult[index - 1] || [];
|
||||
metric = focusedMetric;
|
||||
outputMetric.queryName = queryName;
|
||||
outputMetric.inFocusOrNot = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!outputMetric.queryName) {
|
||||
// Get the focused series data
|
||||
const focusedSeriesData = getFocusedSeriesAtPosition(event, u);
|
||||
|
||||
// If we found a valid focused series, get its data
|
||||
if (
|
||||
focusedSeriesData &&
|
||||
focusedSeriesData.seriesIndex <= apiResult.length
|
||||
) {
|
||||
const { metric: focusedMetric, queryName } =
|
||||
apiResult[focusedSeriesData.seriesIndex - 1] || [];
|
||||
metric = focusedMetric;
|
||||
outputMetric.queryName = queryName;
|
||||
outputMetric.inFocusOrNot = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the actual data point timestamp from the focused series
|
||||
let actualDataTimestamp = xValue; // fallback to click position timestamp
|
||||
if (focusedSeriesData) {
|
||||
if (focusedSeries) {
|
||||
// Get the data index from the focused series
|
||||
const dataIndex = u.posToIdx(event.offsetX);
|
||||
// Get the actual timestamp from the x-axis data (u.data[0])
|
||||
@@ -208,7 +209,7 @@ function onClickPlugin(opts: OnClickPluginOpts): uPlot.Plugin {
|
||||
absoluteMouseX,
|
||||
absoluteMouseY,
|
||||
axesData,
|
||||
focusedSeriesData,
|
||||
focusedSeries,
|
||||
);
|
||||
};
|
||||
u.over.addEventListener('click', handleClick);
|
||||
|
||||
@@ -415,11 +415,7 @@ ToolTipPluginProps): any => {
|
||||
}
|
||||
// Clear and set new content in one operation
|
||||
overlay.replaceChildren(content);
|
||||
placement(overlay, anchor, 'right', 'start', {
|
||||
bound,
|
||||
followCursor: { x: anchor.left, y: anchor.top, offset: 4 },
|
||||
});
|
||||
|
||||
placement(overlay, anchor, 'right', 'start', { bound });
|
||||
showOverlay();
|
||||
} else {
|
||||
hideOverlay();
|
||||
|
||||
@@ -16,6 +16,6 @@ export const topTracesTableColumns = [
|
||||
title: 'STEP TRANSITION DURATION',
|
||||
dataIndex: 'duration_ms',
|
||||
key: 'duration_ms',
|
||||
render: (value: string): string => getYAxisFormattedValue(`${value}`, 'ms'),
|
||||
render: (value: string): string => getYAxisFormattedValue(value, 'ms'),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -401,14 +401,14 @@ body {
|
||||
font-size: 12px;
|
||||
position: absolute;
|
||||
margin: 0.5rem;
|
||||
background: var(--bg-ink-300);
|
||||
background: rgba(0, 0, 0);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
color: var(--bg-vanilla-100);
|
||||
color: #fff;
|
||||
z-index: 10000;
|
||||
// pointer-events: none;
|
||||
overflow: auto;
|
||||
max-height: 480px !important;
|
||||
max-width: 300px !important;
|
||||
max-width: 240px !important;
|
||||
border-radius: 5px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
|
||||
@@ -571,12 +571,6 @@ body {
|
||||
}
|
||||
|
||||
.lightMode {
|
||||
#overlay {
|
||||
color: var(--bg-ink-500);
|
||||
background: var(--bg-vanilla-100);
|
||||
border: 1px solid var(--bg-vanilla-300);
|
||||
}
|
||||
|
||||
.ant-dropdown-menu {
|
||||
border: 1px solid var(--bg-vanilla-300);
|
||||
background: var(--bg-vanilla-100);
|
||||
|
||||
@@ -42,4 +42,4 @@ type URLShareableOptions struct {
|
||||
SelectColumns []v3.AttributeKey `json:"selectColumns"`
|
||||
}
|
||||
|
||||
var PredefinedAlertLabels = []string{ruletypes.LabelThresholdName, ruletypes.LabelSeverityName, ruletypes.LabelLastSeen}
|
||||
var PredefinedAlertLabels = []string{ruletypes.LabelThresholdName}
|
||||
|
||||
@@ -94,8 +94,6 @@ type SigNozAgentConfig struct {
|
||||
IngestionKey string `json:"ingestion_key"`
|
||||
SigNozAPIUrl string `json:"signoz_api_url"`
|
||||
SigNozAPIKey string `json:"signoz_api_key"`
|
||||
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
type GenerateConnectionUrlResponse struct {
|
||||
@@ -116,10 +114,8 @@ func (c *Controller) GenerateConnectionUrl(ctx context.Context, orgId string, cl
|
||||
return nil, model.WrapApiError(apiErr, "couldn't upsert cloud account")
|
||||
}
|
||||
|
||||
agentVersion := "v0.0.6"
|
||||
if req.AgentConfig.Version != "" {
|
||||
agentVersion = req.AgentConfig.Version
|
||||
}
|
||||
// TODO(Raj): parameterized this in follow up changes
|
||||
agentVersion := "v0.0.5"
|
||||
|
||||
connectionUrl := fmt.Sprintf(
|
||||
"https://%s.console.aws.amazon.com/cloudformation/home?region=%s#/stacks/quickcreate?",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"description": "This dashboard provides a high-level overview of your MongoDB. It includes read/write performance, most-used replicas, collection metrics etc...",
|
||||
"id": "mongo-overview",
|
||||
"description": "This dashboard provides a high-level overview of your MongoDB. It includes read/write performance, most-used replicas, collection metrics etc...",
|
||||
"layout": [
|
||||
{
|
||||
"h": 3,
|
||||
@@ -92,7 +92,6 @@
|
||||
"type": "QUERY"
|
||||
}
|
||||
},
|
||||
"version": "v5",
|
||||
"widgets": [
|
||||
{
|
||||
"description": "Total number of operations",
|
||||
@@ -106,20 +105,37 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "mongodb_operation_count",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "rate"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "mongodb_operation_count--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "mongodb_operation_count",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "sum_rate",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "a468a30b",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -131,13 +147,12 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "{{operation}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -181,20 +196,37 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "mongodb_operation_time",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "rate"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "mongodb_operation_time--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "mongodb_operation_time",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "sum_rate",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "31be3166",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -206,13 +238,12 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "{{operation}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -256,20 +287,37 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "mongodb_cache_operations",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "rate"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "mongodb_cache_operations--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "mongodb_cache_operations",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "sum_rate",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "01b45814",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -281,13 +329,12 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "{{type}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -331,29 +378,58 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "mongodb_operation_latency_time",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "max",
|
||||
"temporality": null,
|
||||
"timeAggregation": "max"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "mongodb_operation_latency_time--float64--Gauge--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "mongodb_operation_latency_time",
|
||||
"type": "Gauge"
|
||||
},
|
||||
"aggregateOperator": "max",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "(operation = 'read' AND host_name IN $host_name)"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "2e165319",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "operation--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "operation",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "=",
|
||||
"value": "read"
|
||||
},
|
||||
{
|
||||
"id": "888e920b",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Latency",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -397,29 +473,58 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "mongodb_operation_latency_time",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "max",
|
||||
"temporality": null,
|
||||
"timeAggregation": "max"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "mongodb_operation_latency_time--float64--Gauge--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "mongodb_operation_latency_time",
|
||||
"type": "Gauge"
|
||||
},
|
||||
"aggregateOperator": "max",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "(host_name IN $host_name AND operation = 'write')"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "53b37ca7",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "9862c46c",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "operation--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "operation",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "=",
|
||||
"value": "write"
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Latency",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -463,29 +568,58 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "mongodb_operation_latency_time",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "max",
|
||||
"temporality": null,
|
||||
"timeAggregation": "max"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "mongodb_operation_latency_time--float64--Gauge--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "mongodb_operation_latency_time",
|
||||
"type": "Gauge"
|
||||
},
|
||||
"aggregateOperator": "max",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "(host_name IN $host_name AND operation = 'command')"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "c33ad4b6",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "c70ecfd0",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "operation--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "operation",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "=",
|
||||
"value": "command"
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Latency",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -529,20 +663,37 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "mongodb_network_io_receive",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "avg",
|
||||
"temporality": null,
|
||||
"timeAggregation": "avg"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "mongodb_network_io_receive--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "mongodb_network_io_receive",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "avg",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "5c9d7fe3",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -554,30 +705,46 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Bytes received :: {{host_name}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
},
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "mongodb_network_io_transmit",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "avg",
|
||||
"temporality": null,
|
||||
"timeAggregation": "avg"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "mongodb_network_io_transmit--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "mongodb_network_io_transmit",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "avg",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "B",
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "96520885",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -589,13 +756,12 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Bytes transmitted :: {{host_name}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "B",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"description": "This dashboard provides a high-level overview of your MongoDB. It includes read/write performance, most-used replicas, collection metrics etc...",
|
||||
"id": "mongo-overview",
|
||||
"description": "This dashboard provides a high-level overview of your MongoDB. It includes read/write performance, most-used replicas, collection metrics etc...",
|
||||
"layout": [
|
||||
{
|
||||
"h": 3,
|
||||
@@ -92,7 +92,6 @@
|
||||
"type": "QUERY"
|
||||
}
|
||||
},
|
||||
"version": "v5",
|
||||
"widgets": [
|
||||
{
|
||||
"description": "Total number of operations",
|
||||
@@ -106,20 +105,37 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "mongodb.operation.count",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "rate"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "mongodb.operation.count--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "mongodb.operation.count",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "sum_rate",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host.name IN $host.name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "a468a30b",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -131,13 +147,12 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "{{operation}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -181,20 +196,37 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "mongodb.operation.time",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "rate"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "mongodb.operation.time--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "mongodb.operation.time",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "sum_rate",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host.name IN $host.name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "31be3166",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -206,13 +238,12 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "{{operation}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -256,20 +287,37 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "mongodb.cache.operations",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "rate"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "mongodb.cache.operations--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "mongodb.cache.operations",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "sum_rate",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host.name IN $host.name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "01b45814",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -281,13 +329,12 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "{{type}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -331,29 +378,58 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "mongodb.operation.latency.time",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "max",
|
||||
"temporality": null,
|
||||
"timeAggregation": "max"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "mongodb.operation.latency.time--float64--Gauge--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "mongodb.operation.latency.time",
|
||||
"type": "Gauge"
|
||||
},
|
||||
"aggregateOperator": "max",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "(operation = 'read' AND host.name IN $host.name)"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "2e165319",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "operation--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "operation",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "=",
|
||||
"value": "read"
|
||||
},
|
||||
{
|
||||
"id": "888e920b",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Latency",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -397,29 +473,58 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "mongodb.operation.latency.time",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "max",
|
||||
"temporality": null,
|
||||
"timeAggregation": "max"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "mongodb.operation.latency.time--float64--Gauge--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "mongodb.operation.latency.time",
|
||||
"type": "Gauge"
|
||||
},
|
||||
"aggregateOperator": "max",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "(host.name IN $host.name AND operation = 'write')"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "53b37ca7",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "9862c46c",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "operation--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "operation",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "=",
|
||||
"value": "write"
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Latency",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -463,29 +568,58 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "mongodb.operation.latency.time",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "max",
|
||||
"temporality": null,
|
||||
"timeAggregation": "max"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "mongodb.operation.latency.time--float64--Gauge--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "mongodb.operation.latency.time",
|
||||
"type": "Gauge"
|
||||
},
|
||||
"aggregateOperator": "max",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "(host.name IN $host.name AND operation = 'command')"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "c33ad4b6",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "c70ecfd0",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "operation--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "operation",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "=",
|
||||
"value": "command"
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Latency",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -529,20 +663,37 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "mongodb.network.io.receive",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "avg",
|
||||
"temporality": null,
|
||||
"timeAggregation": "avg"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "mongodb.network.io.receive--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "mongodb.network.io.receive",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "avg",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host.name IN $host.name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "5c9d7fe3",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -554,30 +705,46 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Bytes received :: {{host.name}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
},
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "mongodb.network.io.transmit",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "avg",
|
||||
"temporality": null,
|
||||
"timeAggregation": "avg"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "mongodb.network.io.transmit--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "mongodb.network.io.transmit",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "avg",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "B",
|
||||
"filter": {
|
||||
"expression": "host.name IN $host.name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "96520885",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -589,13 +756,12 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Bytes transmitted :: {{host.name}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "B",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -628,4 +794,4 @@
|
||||
"yAxisUnit": "bytes"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"description": "This dashboard shows the Redis instance overview. It includes latency, hit/miss rate, connections, and memory information.\n",
|
||||
"id": "redis-overview",
|
||||
"description": "This dashboard shows the Redis instance overview. It includes latency, hit/miss rate, connections, and memory information.\n",
|
||||
"layout": [
|
||||
{
|
||||
"h": 3,
|
||||
@@ -111,7 +111,6 @@
|
||||
"type": "QUERY"
|
||||
}
|
||||
},
|
||||
"version": "v5",
|
||||
"widgets": [
|
||||
{
|
||||
"description": "Rate successful lookup of keys in the main dictionary",
|
||||
@@ -125,29 +124,45 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis_keyspace_hits",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "rate"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis_keyspace_hits--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis_keyspace_hits",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "sum_rate",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "e99669ea",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Hit/s across all hosts",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -191,29 +206,45 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis_clients_blocked",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "sum"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis_clients_blocked--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis_clients_blocked",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "sum",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "97247f25",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Blocked clients across all hosts",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -257,26 +288,28 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis_db_keys",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "sum"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "",
|
||||
"id": "redis_db_keys------false",
|
||||
"isColumn": false,
|
||||
"key": "redis_db_keys",
|
||||
"type": ""
|
||||
},
|
||||
"aggregateOperator": "sum",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"groupBy": [],
|
||||
"having": {
|
||||
"expression": ""
|
||||
"filters": {
|
||||
"items": [],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [],
|
||||
"having": [],
|
||||
"legend": "",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -320,29 +353,45 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis_rdb_changes_since_last_save",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "sum"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis_rdb_changes_since_last_save--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis_rdb_changes_since_last_save",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "sum",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "d4aef346",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Number of unsaved changes",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -386,29 +435,45 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis_commands",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "sum"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis_commands--float64--Gauge--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis_commands",
|
||||
"type": "Gauge"
|
||||
},
|
||||
"aggregateOperator": "sum",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "458dc402",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "ops/s",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -452,20 +517,37 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis_memory_used",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "sum"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis_memory_used--float64--Gauge--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis_memory_used",
|
||||
"type": "Gauge"
|
||||
},
|
||||
"aggregateOperator": "sum",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "394a537e",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -477,30 +559,46 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Used::{{host_name}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
},
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis_maxmemory",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "max",
|
||||
"temporality": null,
|
||||
"timeAggregation": "max"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis_maxmemory--float64--Gauge--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis_maxmemory",
|
||||
"type": "Gauge"
|
||||
},
|
||||
"aggregateOperator": "max",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "B",
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "0c0754da",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -512,13 +610,12 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Max::{{host_name}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "B",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -562,20 +659,37 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis_memory_rss",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "sum"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis_memory_rss--float64--Gauge--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis_memory_rss",
|
||||
"type": "Gauge"
|
||||
},
|
||||
"aggregateOperator": "sum",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "4dc9ae49",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -587,13 +701,12 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Rss::{{host_name}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -637,20 +750,37 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis_memory_fragmentation_ratio",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "avg",
|
||||
"temporality": null,
|
||||
"timeAggregation": "avg"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis_memory_fragmentation_ratio--float64--Gauge--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis_memory_fragmentation_ratio",
|
||||
"type": "Gauge"
|
||||
},
|
||||
"aggregateOperator": "avg",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "79dc25f3",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -662,13 +792,12 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Rss::{{host_name}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -712,20 +841,37 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis_keys_evicted",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "rate"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis_keys_evicted--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis_keys_evicted",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "sum_rate",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host_name IN $host_name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "53d189ac",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host_name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host_name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host_name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -737,13 +883,12 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Rss::{{host_name}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"description": "This dashboard shows the Redis instance overview. It includes latency, hit/miss rate, connections, and memory information.\n",
|
||||
"id": "redis-overview",
|
||||
"description": "This dashboard shows the Redis instance overview. It includes latency, hit/miss rate, connections, and memory information.\n",
|
||||
"layout": [
|
||||
{
|
||||
"h": 3,
|
||||
@@ -111,7 +111,6 @@
|
||||
"type": "QUERY"
|
||||
}
|
||||
},
|
||||
"version": "v5",
|
||||
"widgets": [
|
||||
{
|
||||
"description": "Rate successful lookup of keys in the main dictionary",
|
||||
@@ -125,29 +124,45 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis.keyspace.hits",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "rate"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis.keyspace.hits--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis.keyspace.hits",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "sum_rate",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host.name IN $host.name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "e99669ea",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Hit/s across all hosts",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -191,29 +206,45 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis.clients.blocked",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "sum"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis.clients.blocked--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis.clients.blocked",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "sum",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host.name IN $host.name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "97247f25",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Blocked clients across all hosts",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -257,26 +288,28 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis.db.keys",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "sum"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "",
|
||||
"id": "redis.db.keys------false",
|
||||
"isColumn": false,
|
||||
"key": "redis.db.keys",
|
||||
"type": ""
|
||||
},
|
||||
"aggregateOperator": "sum",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"groupBy": [],
|
||||
"having": {
|
||||
"expression": ""
|
||||
"filters": {
|
||||
"items": [],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [],
|
||||
"having": [],
|
||||
"legend": "",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -320,29 +353,45 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis.rdb.changes_since_last_save",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "sum"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis.rdb.changes_since_last_save--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis.rdb.changes_since_last_save",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "sum",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host.name IN $host.name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "d4aef346",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Number of unsaved changes",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -386,29 +435,45 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis.commands",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "sum"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis.commands--float64--Gauge--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis.commands",
|
||||
"type": "Gauge"
|
||||
},
|
||||
"aggregateOperator": "sum",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host.name IN $host.name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "458dc402",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "ops/s",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -452,20 +517,37 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis.memory.used",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "sum"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis.memory.used--float64--Gauge--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis.memory.used",
|
||||
"type": "Gauge"
|
||||
},
|
||||
"aggregateOperator": "sum",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host.name IN $host.name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "394a537e",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -477,30 +559,46 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Used::{{host.name}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
},
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis.maxmemory",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "max",
|
||||
"temporality": null,
|
||||
"timeAggregation": "max"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis.maxmemory--float64--Gauge--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis.maxmemory",
|
||||
"type": "Gauge"
|
||||
},
|
||||
"aggregateOperator": "max",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "B",
|
||||
"filter": {
|
||||
"expression": "host.name IN $host.name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "0c0754da",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -512,13 +610,12 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Max::{{host.name}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "B",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -562,20 +659,37 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis.memory.rss",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "sum"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis.memory.rss--float64--Gauge--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis.memory.rss",
|
||||
"type": "Gauge"
|
||||
},
|
||||
"aggregateOperator": "sum",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host.name IN $host.name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "4dc9ae49",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -587,13 +701,12 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Rss::{{host.name}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -637,20 +750,37 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis.memory.fragmentation_ratio",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "avg",
|
||||
"temporality": null,
|
||||
"timeAggregation": "avg"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis.memory.fragmentation_ratio--float64--Gauge--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis.memory.fragmentation_ratio",
|
||||
"type": "Gauge"
|
||||
},
|
||||
"aggregateOperator": "avg",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host.name IN $host.name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "79dc25f3",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -662,13 +792,12 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Rss::{{host.name}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -712,20 +841,37 @@
|
||||
"builder": {
|
||||
"queryData": [
|
||||
{
|
||||
"aggregations": [
|
||||
{
|
||||
"metricName": "redis.keys.evicted",
|
||||
"reduceTo": "sum",
|
||||
"spaceAggregation": "sum",
|
||||
"temporality": null,
|
||||
"timeAggregation": "rate"
|
||||
}
|
||||
],
|
||||
"aggregateAttribute": {
|
||||
"dataType": "float64",
|
||||
"id": "redis.keys.evicted--float64--Sum--true",
|
||||
"isColumn": true,
|
||||
"isJSON": false,
|
||||
"key": "redis.keys.evicted",
|
||||
"type": "Sum"
|
||||
},
|
||||
"aggregateOperator": "sum_rate",
|
||||
"dataSource": "metrics",
|
||||
"disabled": false,
|
||||
"expression": "A",
|
||||
"filter": {
|
||||
"expression": "host.name IN $host.name"
|
||||
"filters": {
|
||||
"items": [
|
||||
{
|
||||
"id": "53d189ac",
|
||||
"key": {
|
||||
"dataType": "string",
|
||||
"id": "host.name--string--tag--false",
|
||||
"isColumn": false,
|
||||
"isJSON": false,
|
||||
"key": "host.name",
|
||||
"type": "tag"
|
||||
},
|
||||
"op": "in",
|
||||
"value": [
|
||||
"{{.host.name}}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"op": "AND"
|
||||
},
|
||||
"groupBy": [
|
||||
{
|
||||
@@ -737,13 +883,12 @@
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"having": {
|
||||
"expression": ""
|
||||
},
|
||||
"having": [],
|
||||
"legend": "Rss::{{host.name}}",
|
||||
"limit": null,
|
||||
"orderBy": [],
|
||||
"queryName": "A",
|
||||
"reduceTo": "sum",
|
||||
"stepInterval": 60
|
||||
}
|
||||
],
|
||||
@@ -776,4 +921,4 @@
|
||||
"yAxisUnit": "short"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/SigNoz/signoz/pkg/types/thirdpartyapitypes"
|
||||
"math"
|
||||
"net/http"
|
||||
"sort"
|
||||
@@ -14,8 +15,6 @@ import (
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/types/thirdpartyapitypes"
|
||||
|
||||
"github.com/SigNoz/govaluate"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/app/integrations/messagingQueues/kafka"
|
||||
queues2 "github.com/SigNoz/signoz/pkg/query-service/app/integrations/messagingQueues/queues"
|
||||
|
||||
@@ -467,7 +467,7 @@ func (r *ThresholdRule) buildAndRunQuery(ctx context.Context, orgID valuer.UUID,
|
||||
r.logger.InfoContext(ctx, "no data found for rule condition", "rule_id", r.ID())
|
||||
lbls := labels.NewBuilder(labels.Labels{})
|
||||
if !r.lastTimestampWithDatapoints.IsZero() {
|
||||
lbls.Set(ruletypes.LabelLastSeen, r.lastTimestampWithDatapoints.Format(constants.AlertTimeFormat))
|
||||
lbls.Set("lastSeen", r.lastTimestampWithDatapoints.Format(constants.AlertTimeFormat))
|
||||
}
|
||||
resultVector = append(resultVector, ruletypes.Sample{
|
||||
Metric: lbls.Labels(),
|
||||
@@ -544,7 +544,7 @@ func (r *ThresholdRule) buildAndRunQueryV5(ctx context.Context, orgID valuer.UUI
|
||||
r.logger.InfoContext(ctx, "no data found for rule condition", "rule_id", r.ID())
|
||||
lbls := labels.NewBuilder(labels.Labels{})
|
||||
if !r.lastTimestampWithDatapoints.IsZero() {
|
||||
lbls.Set(ruletypes.LabelLastSeen, r.lastTimestampWithDatapoints.Format(constants.AlertTimeFormat))
|
||||
lbls.Set("lastSeen", r.lastTimestampWithDatapoints.Format(constants.AlertTimeFormat))
|
||||
}
|
||||
resultVector = append(resultVector, ruletypes.Sample{
|
||||
Metric: lbls.Labels(),
|
||||
|
||||
@@ -54,6 +54,8 @@ func (r *aggExprRewriter) Rewrite(
|
||||
expr string,
|
||||
rateInterval uint64,
|
||||
keys map[string][]*telemetrytypes.TelemetryFieldKey,
|
||||
startNs uint64,
|
||||
endNs uint64,
|
||||
) (string, []any, error) {
|
||||
|
||||
wrapped := fmt.Sprintf("SELECT %s", expr)
|
||||
@@ -83,6 +85,8 @@ func (r *aggExprRewriter) Rewrite(
|
||||
r.conditionBuilder,
|
||||
r.jsonBodyPrefix,
|
||||
r.jsonKeyToKey,
|
||||
startNs,
|
||||
endNs,
|
||||
)
|
||||
// Rewrite the first select item (our expression)
|
||||
if err := sel.SelectItems[0].Accept(visitor); err != nil {
|
||||
@@ -101,12 +105,14 @@ func (r *aggExprRewriter) RewriteMulti(
|
||||
exprs []string,
|
||||
rateInterval uint64,
|
||||
keys map[string][]*telemetrytypes.TelemetryFieldKey,
|
||||
startNs uint64,
|
||||
endNs uint64,
|
||||
) ([]string, [][]any, error) {
|
||||
out := make([]string, len(exprs))
|
||||
var errs []error
|
||||
var chArgsList [][]any
|
||||
for i, e := range exprs {
|
||||
w, chArgs, err := r.Rewrite(ctx, e, rateInterval, keys)
|
||||
w, chArgs, err := r.Rewrite(ctx, e, rateInterval, keys, startNs, endNs)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
out[i] = e
|
||||
@@ -134,6 +140,8 @@ type exprVisitor struct {
|
||||
Modified bool
|
||||
chArgs []any
|
||||
isRate bool
|
||||
startNs uint64
|
||||
endNs uint64
|
||||
}
|
||||
|
||||
func newExprVisitor(
|
||||
@@ -144,6 +152,8 @@ func newExprVisitor(
|
||||
conditionBuilder qbtypes.ConditionBuilder,
|
||||
jsonBodyPrefix string,
|
||||
jsonKeyToKey qbtypes.JsonKeyToFieldFunc,
|
||||
startNs uint64,
|
||||
endNs uint64,
|
||||
) *exprVisitor {
|
||||
return &exprVisitor{
|
||||
logger: logger,
|
||||
@@ -153,6 +163,8 @@ func newExprVisitor(
|
||||
conditionBuilder: conditionBuilder,
|
||||
jsonBodyPrefix: jsonBodyPrefix,
|
||||
jsonKeyToKey: jsonKeyToKey,
|
||||
startNs: startNs,
|
||||
endNs: endNs,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +202,7 @@ func (v *exprVisitor) VisitFunctionExpr(fn *chparser.FunctionExpr) error {
|
||||
if aggFunc.FuncCombinator {
|
||||
// Map the predicate (last argument)
|
||||
origPred := args[len(args)-1].String()
|
||||
whereClause, err := PrepareWhereClause(
|
||||
whereClause, err := PrepareWhereClause(
|
||||
origPred,
|
||||
FilterExprVisitorOpts{
|
||||
Logger: v.logger,
|
||||
@@ -200,7 +212,7 @@ func (v *exprVisitor) VisitFunctionExpr(fn *chparser.FunctionExpr) error {
|
||||
FullTextColumn: v.fullTextColumn,
|
||||
JsonBodyPrefix: v.jsonBodyPrefix,
|
||||
JsonKeyToKey: v.jsonKeyToKey,
|
||||
}, 0, 0,
|
||||
}, v.startNs, v.endNs,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -350,6 +350,8 @@ func (b *logQueryStatementBuilder) buildTimeSeriesQuery(
|
||||
ctx, agg.Expression,
|
||||
uint64(query.StepInterval.Seconds()),
|
||||
keys,
|
||||
start,
|
||||
end,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -499,6 +501,8 @@ func (b *logQueryStatementBuilder) buildScalarQuery(
|
||||
ctx, aggExpr.Expression,
|
||||
rateInterval,
|
||||
keys,
|
||||
start,
|
||||
end,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -592,7 +596,7 @@ func (b *logQueryStatementBuilder) addFilterCondition(
|
||||
JsonBodyPrefix: b.jsonBodyPrefix,
|
||||
JsonKeyToKey: b.jsonKeyToKey,
|
||||
Variables: variables,
|
||||
}, start, end)
|
||||
}, start, end)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -512,6 +512,8 @@ func (b *traceQueryStatementBuilder) buildTimeSeriesQuery(
|
||||
ctx, agg.Expression,
|
||||
uint64(query.StepInterval.Seconds()),
|
||||
keys,
|
||||
start,
|
||||
end,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -657,6 +659,8 @@ func (b *traceQueryStatementBuilder) buildScalarQuery(
|
||||
ctx, aggExpr.Expression,
|
||||
rateInterval,
|
||||
keys,
|
||||
start,
|
||||
end,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -746,7 +750,7 @@ func (b *traceQueryStatementBuilder) addFilterCondition(
|
||||
FieldKeys: keys,
|
||||
SkipResourceFilter: true,
|
||||
Variables: variables,
|
||||
}, start, end)
|
||||
}, start, end)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -237,7 +237,7 @@ func (b *traceOperatorCTEBuilder) buildQueryCTE(ctx context.Context, queryName s
|
||||
ConditionBuilder: b.stmtBuilder.cb,
|
||||
FieldKeys: keys,
|
||||
SkipResourceFilter: true,
|
||||
}, b.start, b.end,
|
||||
}, b.start, b.end,
|
||||
)
|
||||
if err != nil {
|
||||
b.stmtBuilder.logger.ErrorContext(ctx, "Failed to prepare where clause", "error", err, "filter", query.Filter.Expression)
|
||||
@@ -575,6 +575,8 @@ func (b *traceOperatorCTEBuilder) buildTimeSeriesQuery(ctx context.Context, sele
|
||||
agg.Expression,
|
||||
uint64(b.operator.StepInterval.Seconds()),
|
||||
keys,
|
||||
b.start,
|
||||
b.end,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.NewInvalidInputf(
|
||||
@@ -687,6 +689,8 @@ func (b *traceOperatorCTEBuilder) buildTraceQuery(ctx context.Context, selectFro
|
||||
agg.Expression,
|
||||
rateInterval,
|
||||
keys,
|
||||
b.start,
|
||||
b.end,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.NewInvalidInputf(
|
||||
@@ -825,6 +829,8 @@ func (b *traceOperatorCTEBuilder) buildScalarQuery(ctx context.Context, selectFr
|
||||
agg.Expression,
|
||||
uint64((b.end-b.start)/querybuilder.NsToSeconds),
|
||||
keys,
|
||||
b.start,
|
||||
b.end,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.NewInvalidInputf(
|
||||
|
||||
@@ -93,13 +93,10 @@ func NewConfigFromStoreableConfig(sc *StoreableConfig) (*Config, error) {
|
||||
}
|
||||
|
||||
func NewDefaultConfig(globalConfig GlobalConfig, routeConfig RouteConfig, orgID string) (*Config, error) {
|
||||
// Mergo treats an explicit false as zero-value and overwrites it to true, so we save it in smtpRequireTLS and restore the user-specified value.
|
||||
smtpRequireTLS := globalConfig.SMTPRequireTLS
|
||||
err := mergo.Merge(&globalConfig, config.DefaultGlobalConfig())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
globalConfig.SMTPRequireTLS = smtpRequireTLS
|
||||
|
||||
route, err := NewRouteFromRouteConfig(nil, routeConfig)
|
||||
if err != nil {
|
||||
@@ -170,13 +167,10 @@ func (c *Config) CopyWithReset() (*Config, error) {
|
||||
}
|
||||
|
||||
func (c *Config) SetGlobalConfig(globalConfig GlobalConfig) error {
|
||||
// Mergo treats an explicit false as zero-value and overwrites it to true, so we save it in smtpRequireTLS and restore the user-specified value.
|
||||
smtpRequireTLS := globalConfig.SMTPRequireTLS
|
||||
err := mergo.Merge(&globalConfig, config.DefaultGlobalConfig())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
globalConfig.SMTPRequireTLS = smtpRequireTLS
|
||||
|
||||
c.alertmanagerConfig.Global = &globalConfig
|
||||
c.storeableConfig.Config = string(newRawFromConfig(c.alertmanagerConfig))
|
||||
|
||||
@@ -282,50 +282,3 @@ func TestUTF8Validation(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDefaultConfigPreservesSMTPRequireTLS(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
globalConfig GlobalConfig
|
||||
expect bool
|
||||
}{
|
||||
{"False", GlobalConfig{SMTPRequireTLS: false}, false},
|
||||
{"True", GlobalConfig{SMTPRequireTLS: true}, true},
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
global := tt.globalConfig
|
||||
route := RouteConfig{
|
||||
GroupInterval: time.Minute,
|
||||
GroupWait: time.Minute,
|
||||
RepeatInterval: time.Minute,
|
||||
}
|
||||
cfg, err := NewDefaultConfig(global, route, "1")
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expect, cfg.alertmanagerConfig.Global.SMTPRequireTLS)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetGlobalConfigPreservesSMTPRequireTLS(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
globalConfig GlobalConfig
|
||||
expect bool
|
||||
}{
|
||||
{"False", GlobalConfig{SMTPRequireTLS: false}, false},
|
||||
{"True", GlobalConfig{SMTPRequireTLS: true}, true},
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := NewConfig(&config.Config{}, "1")
|
||||
global := tt.globalConfig
|
||||
err := c.SetGlobalConfig(global)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expect, c.alertmanagerConfig.Global.SMTPRequireTLS)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@ type ConditionBuilder interface {
|
||||
|
||||
type AggExprRewriter interface {
|
||||
// Rewrite rewrites the aggregation expression to be used in the query.
|
||||
Rewrite(ctx context.Context, expr string, rateInterval uint64, keys map[string][]*telemetrytypes.TelemetryFieldKey) (string, []any, error)
|
||||
RewriteMulti(ctx context.Context, exprs []string, rateInterval uint64, keys map[string][]*telemetrytypes.TelemetryFieldKey) ([]string, [][]any, error)
|
||||
Rewrite(ctx context.Context, expr string, rateInterval uint64, keys map[string][]*telemetrytypes.TelemetryFieldKey, startNs uint64, endNs uint64) (string, []any, error)
|
||||
RewriteMulti(ctx context.Context, exprs []string, rateInterval uint64, keys map[string][]*telemetrytypes.TelemetryFieldKey, startNs uint64, endNs uint64) ([]string, [][]any, error)
|
||||
}
|
||||
|
||||
type Statement struct {
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
package ruletypes
|
||||
|
||||
const (
|
||||
CriticalThresholdName = "critical"
|
||||
ErrorThresholdName = "error"
|
||||
WarningThresholdName = "warning"
|
||||
InfoThresholdName = "info"
|
||||
LabelThresholdName = "threshold.name"
|
||||
LabelSeverityName = "severity"
|
||||
LabelLastSeen = "lastSeen"
|
||||
LabelRuleId = "ruleId"
|
||||
)
|
||||
const CriticalThresholdName = "CRITICAL"
|
||||
const LabelThresholdName = "threshold.name"
|
||||
const LabelRuleId = "ruleId"
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/query-service/converter"
|
||||
@@ -199,10 +198,7 @@ func (b BasicRuleThreshold) shouldAlert(series v3.Series, ruleUnit string) (Samp
|
||||
|
||||
target := b.target(ruleUnit)
|
||||
|
||||
// TODO(srikanthccv): is it better to move the logic to notifier instead of
|
||||
// adding two labels?
|
||||
lbls = append(lbls, labels.Label{Name: LabelThresholdName, Value: b.Name})
|
||||
lbls = append(lbls, labels.Label{Name: LabelSeverityName, Value: strings.ToLower(b.Name)})
|
||||
|
||||
series.Points = removeGroupinSetPoints(series)
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package ruletypes
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -22,7 +21,7 @@ func TestBasicRuleThresholdShouldAlert_UnitConversion(t *testing.T) {
|
||||
{
|
||||
name: "milliseconds to seconds conversion - should alert",
|
||||
threshold: BasicRuleThreshold{
|
||||
Name: CriticalThresholdName,
|
||||
Name: "test",
|
||||
TargetValue: &target, // 100ms
|
||||
TargetUnit: "ms",
|
||||
MatchType: AtleastOnce,
|
||||
@@ -40,7 +39,7 @@ func TestBasicRuleThresholdShouldAlert_UnitConversion(t *testing.T) {
|
||||
{
|
||||
name: "milliseconds to seconds conversion - should not alert",
|
||||
threshold: BasicRuleThreshold{
|
||||
Name: WarningThresholdName,
|
||||
Name: "test",
|
||||
TargetValue: &target, // 100ms
|
||||
TargetUnit: "ms",
|
||||
MatchType: AtleastOnce,
|
||||
@@ -58,7 +57,7 @@ func TestBasicRuleThresholdShouldAlert_UnitConversion(t *testing.T) {
|
||||
{
|
||||
name: "seconds to milliseconds conversion - should alert",
|
||||
threshold: BasicRuleThreshold{
|
||||
Name: CriticalThresholdName,
|
||||
Name: "test",
|
||||
TargetValue: &target, // 100s
|
||||
TargetUnit: "s",
|
||||
MatchType: AtleastOnce,
|
||||
@@ -77,7 +76,7 @@ func TestBasicRuleThresholdShouldAlert_UnitConversion(t *testing.T) {
|
||||
{
|
||||
name: "bytes to kibibytes conversion - should alert",
|
||||
threshold: BasicRuleThreshold{
|
||||
Name: InfoThresholdName,
|
||||
Name: "test",
|
||||
TargetValue: &target, // 100 bytes
|
||||
TargetUnit: "bytes",
|
||||
MatchType: AtleastOnce,
|
||||
@@ -95,7 +94,7 @@ func TestBasicRuleThresholdShouldAlert_UnitConversion(t *testing.T) {
|
||||
{
|
||||
name: "kibibytes to mebibytes conversion - should alert",
|
||||
threshold: BasicRuleThreshold{
|
||||
Name: ErrorThresholdName,
|
||||
Name: "test",
|
||||
TargetValue: &target, // 100KiB
|
||||
TargetUnit: "kbytes",
|
||||
MatchType: AtleastOnce,
|
||||
@@ -114,7 +113,7 @@ func TestBasicRuleThresholdShouldAlert_UnitConversion(t *testing.T) {
|
||||
{
|
||||
name: "milliseconds to seconds with ValueIsBelow - should alert",
|
||||
threshold: BasicRuleThreshold{
|
||||
Name: WarningThresholdName,
|
||||
Name: "test",
|
||||
TargetValue: &target, // 100ms
|
||||
TargetUnit: "ms",
|
||||
MatchType: AtleastOnce,
|
||||
@@ -132,7 +131,7 @@ func TestBasicRuleThresholdShouldAlert_UnitConversion(t *testing.T) {
|
||||
{
|
||||
name: "milliseconds to seconds with OnAverage - should alert",
|
||||
threshold: BasicRuleThreshold{
|
||||
Name: CriticalThresholdName,
|
||||
Name: "test",
|
||||
TargetValue: &target, // 100ms
|
||||
TargetUnit: "ms",
|
||||
MatchType: OnAverage,
|
||||
@@ -152,7 +151,7 @@ func TestBasicRuleThresholdShouldAlert_UnitConversion(t *testing.T) {
|
||||
{
|
||||
name: "decimal megabytes to gigabytes with InTotal - should alert",
|
||||
threshold: BasicRuleThreshold{
|
||||
Name: WarningThresholdName,
|
||||
Name: "test",
|
||||
TargetValue: &target, // 100MB
|
||||
TargetUnit: "decmbytes",
|
||||
MatchType: InTotal,
|
||||
@@ -172,7 +171,7 @@ func TestBasicRuleThresholdShouldAlert_UnitConversion(t *testing.T) {
|
||||
{
|
||||
name: "milliseconds to seconds with AllTheTimes - should alert",
|
||||
threshold: BasicRuleThreshold{
|
||||
Name: InfoThresholdName,
|
||||
Name: "test",
|
||||
TargetValue: &target, // 100ms
|
||||
TargetUnit: "ms",
|
||||
MatchType: AllTheTimes,
|
||||
@@ -192,7 +191,7 @@ func TestBasicRuleThresholdShouldAlert_UnitConversion(t *testing.T) {
|
||||
{
|
||||
name: "kilobytes to megabytes with Last - should not alert",
|
||||
threshold: BasicRuleThreshold{
|
||||
Name: ErrorThresholdName,
|
||||
Name: "test",
|
||||
TargetValue: &target, // 100kB
|
||||
TargetUnit: "deckbytes",
|
||||
MatchType: Last,
|
||||
@@ -212,7 +211,7 @@ func TestBasicRuleThresholdShouldAlert_UnitConversion(t *testing.T) {
|
||||
{
|
||||
name: "bytes per second to kilobytes per second - should alert",
|
||||
threshold: BasicRuleThreshold{
|
||||
Name: CriticalThresholdName,
|
||||
Name: "test",
|
||||
TargetValue: &target, // 100 bytes/s
|
||||
TargetUnit: "Bps",
|
||||
MatchType: AtleastOnce,
|
||||
@@ -231,7 +230,7 @@ func TestBasicRuleThresholdShouldAlert_UnitConversion(t *testing.T) {
|
||||
{
|
||||
name: "same unit - no conversion needed - should alert",
|
||||
threshold: BasicRuleThreshold{
|
||||
Name: InfoThresholdName,
|
||||
Name: "test",
|
||||
TargetValue: &target, // 100ms
|
||||
TargetUnit: "ms",
|
||||
MatchType: AtleastOnce,
|
||||
@@ -250,7 +249,7 @@ func TestBasicRuleThresholdShouldAlert_UnitConversion(t *testing.T) {
|
||||
{
|
||||
name: "empty unit - no conversion - should alert",
|
||||
threshold: BasicRuleThreshold{
|
||||
Name: ErrorThresholdName,
|
||||
Name: "test",
|
||||
TargetValue: &target, // 100 (unitless)
|
||||
TargetUnit: "",
|
||||
MatchType: AtleastOnce,
|
||||
@@ -281,20 +280,12 @@ func TestBasicRuleThresholdShouldAlert_UnitConversion(t *testing.T) {
|
||||
|
||||
hasThresholdLabel := false
|
||||
for _, label := range sample.Metric {
|
||||
if label.Name == LabelThresholdName && label.Value == tt.threshold.Name {
|
||||
if label.Name == LabelThresholdName && label.Value == "test" {
|
||||
hasThresholdLabel = true
|
||||
break
|
||||
}
|
||||
}
|
||||
assert.True(t, hasThresholdLabel)
|
||||
hasSeverityLabel := false
|
||||
for _, label := range sample.Metric {
|
||||
if label.Name == LabelSeverityName && label.Value == strings.ToLower(tt.threshold.Name) {
|
||||
hasSeverityLabel = true
|
||||
break
|
||||
}
|
||||
}
|
||||
assert.True(t, hasSeverityLabel)
|
||||
assert.Equal(t, *tt.threshold.TargetValue, sample.Target)
|
||||
assert.Equal(t, tt.threshold.TargetUnit, sample.TargetUnit)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user