mirror of
https://github.com/SigNoz/signoz.git
synced 2026-09-24 12:20:41 +01:00
Compare commits
5 Commits
feat/updat
...
chore/aler
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e454ac92f9 | ||
|
|
cad93a8063 | ||
|
|
aed096bf27 | ||
|
|
6b66ab64c8 | ||
|
|
362d3a4fdf |
2
.github/workflows/integrationci.yaml
vendored
2
.github/workflows/integrationci.yaml
vendored
@@ -38,7 +38,6 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
suite:
|
||||
- alerts
|
||||
- alertmanager
|
||||
- alertmanagerrotation
|
||||
- basepath
|
||||
@@ -64,6 +63,7 @@ jobs:
|
||||
- querierauthz
|
||||
- role
|
||||
- rootuser
|
||||
- rules
|
||||
- savedview
|
||||
- semconvfamilies
|
||||
- serviceaccount
|
||||
|
||||
@@ -114,8 +114,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.beta-tag {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ export default function NavItem({
|
||||
data-testid={dataTestId}
|
||||
>
|
||||
{showIcon && <div className="nav-item-active-marker" />}
|
||||
<div className={cx('nav-item-data', isBeta ? 'beta-tag' : '')}>
|
||||
<div className="nav-item-data">
|
||||
{showIcon && (
|
||||
<div className={cx('nav-item-icon', isEarlyAccess ? 'noz-wave' : '')}>
|
||||
{icon}
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
import {
|
||||
type BuilderField,
|
||||
panelTypeDataSourceFormValuesMap,
|
||||
type PartialPanelTypes,
|
||||
} from 'lib/query/panelTypeDataSourceFormValuesMap';
|
||||
import { isStaticPanelKind } from 'pages/DashboardPage/DashboardContainer/Panels/capabilities';
|
||||
import { PANEL_KIND_TO_PANEL_TYPE } from 'pages/DashboardPage/DashboardContainer/Panels/types/panelKind';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
/**
|
||||
* The map is composed from a few shape rules rather than spelled out per panel type
|
||||
* and data source. These specs pin the rules themselves — each one fails only when a
|
||||
* rule changes, which is the moment to stop and decide, rather than whenever any
|
||||
* field moves.
|
||||
*
|
||||
* The composition it replaced was checked cell by cell against the previous literal
|
||||
* table, which is in git history at `main:frontend/src/lib/query/panelQuery.ts`.
|
||||
*/
|
||||
function fieldsFor(
|
||||
panelType: keyof PartialPanelTypes,
|
||||
dataSource: DataSource,
|
||||
): BuilderField[] {
|
||||
return panelTypeDataSourceFormValuesMap[panelType][dataSource].builder
|
||||
.queryData;
|
||||
}
|
||||
|
||||
/** Fields present in `to` but not in `from`. */
|
||||
function added(from: BuilderField[], to: BuilderField[]): BuilderField[] {
|
||||
return to.filter((field) => !from.includes(field)).sort();
|
||||
}
|
||||
|
||||
/** Panel types built on the aggregating field list. */
|
||||
const AGGREGATING_TYPES: (keyof PartialPanelTypes)[] = [
|
||||
PANEL_TYPES.AREA,
|
||||
PANEL_TYPES.BAR,
|
||||
PANEL_TYPES.HISTOGRAM,
|
||||
PANEL_TYPES.TABLE,
|
||||
PANEL_TYPES.PIE,
|
||||
];
|
||||
|
||||
/** Panel types that reduce each series to one cell or slice. */
|
||||
const SCALAR_TYPES: (keyof PartialPanelTypes)[] = [
|
||||
PANEL_TYPES.TABLE,
|
||||
PANEL_TYPES.PIE,
|
||||
];
|
||||
|
||||
describe('panelTypeDataSourceFormValuesMap', () => {
|
||||
const seriesLogs = fieldsFor(PANEL_TYPES.TIME_SERIES, DataSource.LOGS);
|
||||
const seriesMetrics = fieldsFor(PANEL_TYPES.TIME_SERIES, DataSource.METRICS);
|
||||
|
||||
// A kind with no entry throws on switch: handleQueryChange reads
|
||||
// map[panelType][dataSource] straight through, and the cast at its call site
|
||||
// hides the gap. Static kinds return before that call, so they are exempt.
|
||||
it('covers every panel kind that can be switched to', () => {
|
||||
const uncovered = Object.entries(PANEL_KIND_TO_PANEL_TYPE)
|
||||
.filter(([kind]) => !isStaticPanelKind(kind as never))
|
||||
.map(([, panelType]) => panelType)
|
||||
.filter((panelType) => !(panelType in panelTypeDataSourceFormValuesMap));
|
||||
|
||||
expect(uncovered).toStrictEqual([]);
|
||||
});
|
||||
|
||||
it('shares one builder surface between logs and traces', () => {
|
||||
Object.values(panelTypeDataSourceFormValuesMap).forEach((sources) => {
|
||||
expect(sources[DataSource.LOGS].builder.queryData).toStrictEqual(
|
||||
sources[DataSource.TRACES].builder.queryData,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// The provider pushes onto the list it reads from this map, so two cells backed by
|
||||
// one instance would leak fields into each other.
|
||||
it('gives every cell its own array instance', () => {
|
||||
const arrays = Object.values(panelTypeDataSourceFormValuesMap).flatMap(
|
||||
(sources) =>
|
||||
Object.values(sources).map((source) => source.builder.queryData),
|
||||
);
|
||||
|
||||
expect(new Set(arrays).size).toBe(arrays.length);
|
||||
});
|
||||
|
||||
// One consequence of composing: the aggregating types share a single field list, so
|
||||
// an edit meant for charts reaches table and pie too.
|
||||
it.each(AGGREGATING_TYPES)(
|
||||
'gives %s the same non-metrics fields as a time series',
|
||||
(panelType) => {
|
||||
expect(fieldsFor(panelType, DataSource.LOGS)).toStrictEqual(seriesLogs);
|
||||
},
|
||||
);
|
||||
|
||||
it('adds both metrics aggregation steps for metrics', () => {
|
||||
expect(added(seriesLogs, seriesMetrics)).toStrictEqual([
|
||||
'spaceAggregation',
|
||||
'timeAggregation',
|
||||
]);
|
||||
});
|
||||
|
||||
it.each(SCALAR_TYPES)('offers reduceTo to %s on metrics only', (panelType) => {
|
||||
expect(
|
||||
added(seriesMetrics, fieldsFor(panelType, DataSource.METRICS)),
|
||||
).toStrictEqual(['reduceTo']);
|
||||
expect(fieldsFor(panelType, DataSource.LOGS)).not.toContain('reduceTo');
|
||||
});
|
||||
|
||||
it('drops grouping, paging and ordering for a single value', () => {
|
||||
const value = fieldsFor(PANEL_TYPES.VALUE, DataSource.LOGS);
|
||||
|
||||
expect(added(value, seriesLogs)).toStrictEqual([
|
||||
'groupBy',
|
||||
'limit',
|
||||
'orderBy',
|
||||
]);
|
||||
expect(value).toContain('reduceTo');
|
||||
});
|
||||
|
||||
it('offers no aggregation fields to raw rows', () => {
|
||||
const rows = fieldsFor(PANEL_TYPES.LIST, DataSource.LOGS);
|
||||
|
||||
expect(rows).not.toContain('aggregateAttribute');
|
||||
expect(rows).not.toContain('aggregateOperator');
|
||||
expect(rows).not.toContain('groupBy');
|
||||
expect(rows).not.toContain('having');
|
||||
expect(rows).not.toContain('stepInterval');
|
||||
});
|
||||
|
||||
it('drops paging and ordering for metrics rows', () => {
|
||||
expect(
|
||||
added(
|
||||
fieldsFor(PANEL_TYPES.LIST, DataSource.METRICS),
|
||||
fieldsFor(PANEL_TYPES.LIST, DataSource.LOGS),
|
||||
),
|
||||
).toStrictEqual(['functions', 'limit', 'orderBy']);
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Panel query shaping shared by the dashboard panel editor and the query
|
||||
* builder: the per-panel-type field allowlist, the panel-type switch, and the
|
||||
* dirty-check used to decide whether a panel has unsaved query edits.
|
||||
* builder: the panel-type switch and the dirty-check used to decide whether a
|
||||
* panel has unsaved query edits.
|
||||
*/
|
||||
import {
|
||||
initialQueryBuilderFormValuesMap,
|
||||
@@ -9,7 +9,11 @@ import {
|
||||
} from 'constants/queryBuilder';
|
||||
import { cloneDeep, isEqual, set, unset } from 'lodash-es';
|
||||
import { IBuilderQuery, Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import {
|
||||
panelTypeDataSourceFormValuesMap,
|
||||
PartialPanelTypes,
|
||||
} from 'lib/query/panelTypeDataSourceFormValuesMap';
|
||||
|
||||
// Asks "would saving the current panel change the persisted widget spec?".
|
||||
//
|
||||
@@ -91,453 +95,6 @@ export const getIsQueryModified = (
|
||||
);
|
||||
};
|
||||
|
||||
export type PartialPanelTypes = {
|
||||
[PANEL_TYPES.BAR]: 'bar';
|
||||
[PANEL_TYPES.LIST]: 'list';
|
||||
[PANEL_TYPES.TABLE]: 'table';
|
||||
[PANEL_TYPES.TIME_SERIES]: 'graph';
|
||||
[PANEL_TYPES.VALUE]: 'value';
|
||||
[PANEL_TYPES.PIE]: 'pie';
|
||||
[PANEL_TYPES.HISTOGRAM]: 'histogram';
|
||||
};
|
||||
|
||||
export const panelTypeDataSourceFormValuesMap: Record<
|
||||
keyof PartialPanelTypes,
|
||||
Record<DataSource, any>
|
||||
> = {
|
||||
[PANEL_TYPES.BAR]: {
|
||||
[DataSource.LOGS]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'filters',
|
||||
'filter',
|
||||
'groupBy',
|
||||
'limit',
|
||||
'having',
|
||||
'orderBy',
|
||||
'functions',
|
||||
'stepInterval',
|
||||
'disabled',
|
||||
'queryName',
|
||||
'legend',
|
||||
'expression',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
[DataSource.METRICS]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'timeAggregation',
|
||||
'filters',
|
||||
'filter',
|
||||
'spaceAggregation',
|
||||
'groupBy',
|
||||
'limit',
|
||||
'having',
|
||||
'orderBy',
|
||||
'stepInterval',
|
||||
'legend',
|
||||
'queryName',
|
||||
'disabled',
|
||||
'functions',
|
||||
'expression',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
[DataSource.TRACES]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'filters',
|
||||
'filter',
|
||||
'groupBy',
|
||||
'limit',
|
||||
'having',
|
||||
'orderBy',
|
||||
'functions',
|
||||
'stepInterval',
|
||||
'disabled',
|
||||
'queryName',
|
||||
'legend',
|
||||
'expression',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
[PANEL_TYPES.TIME_SERIES]: {
|
||||
[DataSource.LOGS]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'filters',
|
||||
'filter',
|
||||
'groupBy',
|
||||
'limit',
|
||||
'having',
|
||||
'orderBy',
|
||||
'functions',
|
||||
'stepInterval',
|
||||
'disabled',
|
||||
'queryName',
|
||||
'legend',
|
||||
'expression',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
[DataSource.METRICS]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'timeAggregation',
|
||||
'filters',
|
||||
'filter',
|
||||
'spaceAggregation',
|
||||
'groupBy',
|
||||
'limit',
|
||||
'having',
|
||||
'orderBy',
|
||||
'stepInterval',
|
||||
'legend',
|
||||
'queryName',
|
||||
'disabled',
|
||||
'functions',
|
||||
'expression',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
[DataSource.TRACES]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'filters',
|
||||
'filter',
|
||||
'groupBy',
|
||||
'limit',
|
||||
'having',
|
||||
'orderBy',
|
||||
'functions',
|
||||
'stepInterval',
|
||||
'disabled',
|
||||
'queryName',
|
||||
'legend',
|
||||
'expression',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
[PANEL_TYPES.HISTOGRAM]: {
|
||||
[DataSource.LOGS]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'filters',
|
||||
'filter',
|
||||
'groupBy',
|
||||
'limit',
|
||||
'having',
|
||||
'orderBy',
|
||||
'functions',
|
||||
'stepInterval',
|
||||
'disabled',
|
||||
'queryName',
|
||||
'legend',
|
||||
'expression',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
[DataSource.METRICS]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'timeAggregation',
|
||||
'filters',
|
||||
'filter',
|
||||
'spaceAggregation',
|
||||
'groupBy',
|
||||
'limit',
|
||||
'having',
|
||||
'orderBy',
|
||||
'stepInterval',
|
||||
'legend',
|
||||
'queryName',
|
||||
'disabled',
|
||||
'functions',
|
||||
'expression',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
[DataSource.TRACES]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'filters',
|
||||
'filter',
|
||||
'groupBy',
|
||||
'limit',
|
||||
'having',
|
||||
'orderBy',
|
||||
'functions',
|
||||
'stepInterval',
|
||||
'disabled',
|
||||
'queryName',
|
||||
'legend',
|
||||
'expression',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
[PANEL_TYPES.TABLE]: {
|
||||
[DataSource.LOGS]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'filters',
|
||||
'filter',
|
||||
'groupBy',
|
||||
'limit',
|
||||
'having',
|
||||
'orderBy',
|
||||
'functions',
|
||||
'stepInterval',
|
||||
'disabled',
|
||||
'queryName',
|
||||
'expression',
|
||||
'legend',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
[DataSource.METRICS]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'timeAggregation',
|
||||
'filters',
|
||||
'filter',
|
||||
'spaceAggregation',
|
||||
'groupBy',
|
||||
'reduceTo',
|
||||
'limit',
|
||||
'having',
|
||||
'orderBy',
|
||||
'stepInterval',
|
||||
'legend',
|
||||
'queryName',
|
||||
'expression',
|
||||
'disabled',
|
||||
'functions',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
[DataSource.TRACES]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'filters',
|
||||
'filter',
|
||||
'groupBy',
|
||||
'limit',
|
||||
'having',
|
||||
'orderBy',
|
||||
'functions',
|
||||
'stepInterval',
|
||||
'disabled',
|
||||
'queryName',
|
||||
'expression',
|
||||
'legend',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
[PANEL_TYPES.PIE]: {
|
||||
[DataSource.LOGS]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'filters',
|
||||
'filter',
|
||||
'groupBy',
|
||||
'limit',
|
||||
'having',
|
||||
'orderBy',
|
||||
'functions',
|
||||
'stepInterval',
|
||||
'disabled',
|
||||
'queryName',
|
||||
'expression',
|
||||
'legend',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
[DataSource.METRICS]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'timeAggregation',
|
||||
'filters',
|
||||
'filter',
|
||||
'spaceAggregation',
|
||||
'groupBy',
|
||||
'reduceTo',
|
||||
'limit',
|
||||
'having',
|
||||
'orderBy',
|
||||
'stepInterval',
|
||||
'legend',
|
||||
'queryName',
|
||||
'expression',
|
||||
'disabled',
|
||||
'functions',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
[DataSource.TRACES]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'filters',
|
||||
'filter',
|
||||
'groupBy',
|
||||
'limit',
|
||||
'having',
|
||||
'orderBy',
|
||||
'functions',
|
||||
'stepInterval',
|
||||
'disabled',
|
||||
'queryName',
|
||||
'expression',
|
||||
'legend',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
[PANEL_TYPES.LIST]: {
|
||||
[DataSource.LOGS]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'queryName',
|
||||
'filters',
|
||||
'filter',
|
||||
'limit',
|
||||
'orderBy',
|
||||
'functions',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
[DataSource.METRICS]: {
|
||||
builder: {
|
||||
queryData: ['queryName', 'filters', 'filter', 'aggregations'],
|
||||
},
|
||||
},
|
||||
[DataSource.TRACES]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'queryName',
|
||||
'filters',
|
||||
'filter',
|
||||
'limit',
|
||||
'orderBy',
|
||||
'functions',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
[PANEL_TYPES.VALUE]: {
|
||||
[DataSource.LOGS]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'filters',
|
||||
'filter',
|
||||
'reduceTo',
|
||||
'having',
|
||||
'functions',
|
||||
'stepInterval',
|
||||
'queryName',
|
||||
'expression',
|
||||
'disabled',
|
||||
'legend',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
[DataSource.METRICS]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'timeAggregation',
|
||||
'filters',
|
||||
'filter',
|
||||
'spaceAggregation',
|
||||
'having',
|
||||
'reduceTo',
|
||||
'stepInterval',
|
||||
'legend',
|
||||
'queryName',
|
||||
'expression',
|
||||
'disabled',
|
||||
'functions',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
[DataSource.TRACES]: {
|
||||
builder: {
|
||||
queryData: [
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'filters',
|
||||
'filter',
|
||||
'reduceTo',
|
||||
'having',
|
||||
'functions',
|
||||
'stepInterval',
|
||||
'queryName',
|
||||
'expression',
|
||||
'disabled',
|
||||
'legend',
|
||||
'aggregations',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export function handleQueryChange(
|
||||
newPanelType: keyof PartialPanelTypes,
|
||||
supersetQuery: Query,
|
||||
@@ -555,7 +112,7 @@ export function handleQueryChange(
|
||||
panelTypeDataSourceFormValuesMap[newPanelType][dataSource].builder
|
||||
.queryData;
|
||||
|
||||
fieldsToSelect.forEach((field: keyof IBuilderQuery) => {
|
||||
fieldsToSelect.forEach((field) => {
|
||||
set(tempQuery, field, supersetQuery.builder.queryData[index][field]);
|
||||
});
|
||||
|
||||
|
||||
140
frontend/src/lib/query/panelTypeDataSourceFormValuesMap.ts
Normal file
140
frontend/src/lib/query/panelTypeDataSourceFormValuesMap.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Builder fields carried across a panel-type switch, per panel type and data source.
|
||||
* Each shape is cut from the widest one by omission.
|
||||
*/
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
export type PartialPanelTypes = {
|
||||
[PANEL_TYPES.BAR]: 'bar';
|
||||
[PANEL_TYPES.LIST]: 'list';
|
||||
[PANEL_TYPES.TABLE]: 'table';
|
||||
[PANEL_TYPES.TIME_SERIES]: 'graph';
|
||||
[PANEL_TYPES.AREA]: 'area';
|
||||
[PANEL_TYPES.VALUE]: 'value';
|
||||
[PANEL_TYPES.PIE]: 'pie';
|
||||
[PANEL_TYPES.HISTOGRAM]: 'histogram';
|
||||
};
|
||||
|
||||
export type BuilderField = keyof IBuilderQuery;
|
||||
|
||||
export type PanelTypeFormValues = {
|
||||
builder: { queryData: BuilderField[] };
|
||||
};
|
||||
|
||||
/** A field added to `IBuilderQuery` fails to compile here until answered either way. */
|
||||
const IS_CARRIED = {
|
||||
queryName: true,
|
||||
aggregateOperator: true,
|
||||
aggregateAttribute: true,
|
||||
aggregations: true,
|
||||
timeAggregation: true,
|
||||
spaceAggregation: true,
|
||||
functions: true,
|
||||
filter: true,
|
||||
filters: true,
|
||||
groupBy: true,
|
||||
expression: true,
|
||||
disabled: true,
|
||||
having: true,
|
||||
limit: true,
|
||||
stepInterval: true,
|
||||
orderBy: true,
|
||||
reduceTo: true,
|
||||
legend: true,
|
||||
// `dataSource` is appended by the provider; the rest drive surfaces this switch
|
||||
// does not reach.
|
||||
dataSource: false,
|
||||
temporality: false,
|
||||
pageSize: false,
|
||||
offset: false,
|
||||
selectColumns: false,
|
||||
source: false,
|
||||
builderQueryType: false,
|
||||
} satisfies Record<BuilderField, boolean>;
|
||||
|
||||
function omit(
|
||||
fields: readonly BuilderField[],
|
||||
...omitted: BuilderField[]
|
||||
): BuilderField[] {
|
||||
return fields.filter((field) => !omitted.includes(field));
|
||||
}
|
||||
|
||||
const METRICS_AGGREGATION: readonly BuilderField[] = [
|
||||
'timeAggregation',
|
||||
'spaceAggregation',
|
||||
];
|
||||
|
||||
const SCALAR_METRICS: readonly BuilderField[] = (
|
||||
Object.entries(IS_CARRIED) as [BuilderField, boolean][]
|
||||
)
|
||||
.filter(([, carried]) => carried)
|
||||
.map(([field]) => field);
|
||||
|
||||
// `reduceTo` is offered for metrics only, an asymmetry carried over from the old table.
|
||||
const SERIES_METRICS: readonly BuilderField[] = omit(
|
||||
SCALAR_METRICS,
|
||||
'reduceTo',
|
||||
);
|
||||
|
||||
const SERIES: readonly BuilderField[] = omit(
|
||||
SERIES_METRICS,
|
||||
...METRICS_AGGREGATION,
|
||||
);
|
||||
|
||||
const SINGLE_VALUE_METRICS: readonly BuilderField[] = omit(
|
||||
SCALAR_METRICS,
|
||||
'groupBy',
|
||||
'limit',
|
||||
'orderBy',
|
||||
);
|
||||
const SINGLE_VALUE: readonly BuilderField[] = omit(
|
||||
SINGLE_VALUE_METRICS,
|
||||
...METRICS_AGGREGATION,
|
||||
);
|
||||
|
||||
const RAW_ROWS: readonly BuilderField[] = omit(
|
||||
SERIES,
|
||||
'aggregateAttribute',
|
||||
'aggregateOperator',
|
||||
'groupBy',
|
||||
'having',
|
||||
'stepInterval',
|
||||
'disabled',
|
||||
'legend',
|
||||
'expression',
|
||||
);
|
||||
const RAW_ROWS_METRICS: readonly BuilderField[] = omit(
|
||||
RAW_ROWS,
|
||||
'limit',
|
||||
'orderBy',
|
||||
'functions',
|
||||
);
|
||||
|
||||
/** Each cell gets its own copy; a shared instance would let cells contaminate
|
||||
* each other. */
|
||||
function bySource(
|
||||
logsAndTraces: readonly BuilderField[],
|
||||
metrics: readonly BuilderField[],
|
||||
): Record<DataSource, PanelTypeFormValues> {
|
||||
return {
|
||||
[DataSource.LOGS]: { builder: { queryData: [...logsAndTraces] } },
|
||||
[DataSource.TRACES]: { builder: { queryData: [...logsAndTraces] } },
|
||||
[DataSource.METRICS]: { builder: { queryData: [...metrics] } },
|
||||
};
|
||||
}
|
||||
|
||||
export const panelTypeDataSourceFormValuesMap: Record<
|
||||
keyof PartialPanelTypes,
|
||||
Record<DataSource, PanelTypeFormValues>
|
||||
> = {
|
||||
[PANEL_TYPES.TIME_SERIES]: bySource(SERIES, SERIES_METRICS),
|
||||
[PANEL_TYPES.AREA]: bySource(SERIES, SERIES_METRICS),
|
||||
[PANEL_TYPES.BAR]: bySource(SERIES, SERIES_METRICS),
|
||||
[PANEL_TYPES.HISTOGRAM]: bySource(SERIES, SERIES_METRICS),
|
||||
[PANEL_TYPES.TABLE]: bySource(SERIES, SCALAR_METRICS),
|
||||
[PANEL_TYPES.PIE]: bySource(SERIES, SCALAR_METRICS),
|
||||
[PANEL_TYPES.VALUE]: bySource(SINGLE_VALUE, SINGLE_VALUE_METRICS),
|
||||
[PANEL_TYPES.LIST]: bySource(RAW_ROWS, RAW_ROWS_METRICS),
|
||||
};
|
||||
@@ -7,10 +7,8 @@ import type {
|
||||
TelemetrytypesSignalDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import type { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import {
|
||||
handleQueryChange,
|
||||
type PartialPanelTypes,
|
||||
} from 'lib/query/panelQuery';
|
||||
import { handleQueryChange } from 'lib/query/panelQuery';
|
||||
import type { PartialPanelTypes } from 'lib/query/panelTypeDataSourceFormValuesMap';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { DashboardDetailEvents } from 'pages/DashboardPage/constants/events';
|
||||
import type {
|
||||
|
||||
@@ -32,7 +32,7 @@ import ROUTES from 'constants/routes';
|
||||
import {
|
||||
panelTypeDataSourceFormValuesMap,
|
||||
PartialPanelTypes,
|
||||
} from 'lib/query/panelQuery';
|
||||
} from 'lib/query/panelTypeDataSourceFormValuesMap';
|
||||
import { OptionsQuery } from 'container/OptionsMenu/types';
|
||||
import { useGetCompositeQueryParam } from 'hooks/queryBuilder/useGetCompositeQueryParam';
|
||||
import { updateStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
||||
@@ -767,12 +767,11 @@ export function QueryBuilderProvider({
|
||||
queryItem.dataSource
|
||||
].builder.queryData;
|
||||
|
||||
// `dataSource` travels with the panel type's fields, but is appended to a
|
||||
// copy: `propsRequired` is the list held in
|
||||
// `panelTypeDataSourceFormValuesMap`, and pushing onto it grew that
|
||||
// module-level array by one entry on every call.
|
||||
// `dataSource` travels with the panel type's fields, but on a copy:
|
||||
// `propsRequired` is the list the map holds, and pushing onto it grew
|
||||
// that array by one entry on every call.
|
||||
if (propsRequired) {
|
||||
[...propsRequired, 'dataSource'].forEach((p: any) => {
|
||||
[...propsRequired, 'dataSource'].forEach((p) => {
|
||||
set(queryItem, p, get(newQueryItem, p));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -255,6 +255,8 @@ func NewSQLMigrationProviderFactories(
|
||||
sqlmigration.NewNormalizeQuickFilterFieldsFactory(sqlstore),
|
||||
sqlmigration.NewAddSpanMapperOriginFactory(sqlstore, sqlschema),
|
||||
sqlmigration.NewAddCloudIntegrationTuplesFactory(sqlstore),
|
||||
sqlmigration.NewAddNotificationChannelTuplesFactory(sqlstore),
|
||||
sqlmigration.NewAddAIObservabilityQuickFiltersFactory(sqlstore),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
140
pkg/sqlmigration/129_add_notification_channel_tuples.go
Normal file
140
pkg/sqlmigration/129_add_notification_channel_tuples.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
"github.com/oklog/ulid/v2"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/dialect"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addNotificationChannelTuples struct {
|
||||
sqlstore sqlstore.SQLStore
|
||||
}
|
||||
|
||||
func NewAddNotificationChannelTuplesFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_notification_channel_tuples"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return &addNotificationChannelTuples{sqlstore: sqlstore}, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (migration *addNotificationChannelTuples) Register(migrations *migrate.Migrations) error {
|
||||
return migrations.Register(migration.Up, migration.Down)
|
||||
}
|
||||
|
||||
func (migration *addNotificationChannelTuples) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
var storeID string
|
||||
err = tx.QueryRowContext(ctx, `SELECT id FROM store WHERE name = ? LIMIT 1`, "signoz").Scan(&storeID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var orgIDs []string
|
||||
err = tx.NewSelect().
|
||||
Table("organizations").
|
||||
Column("id").
|
||||
Scan(ctx, &orgIDs)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
|
||||
isPG := migration.sqlstore.BunDB().Dialect().Name() == dialect.PG
|
||||
|
||||
// notification-channel moved from legacy role gates to CheckResources. Existing
|
||||
// organizations need the same tuples that new organizations receive from the
|
||||
// managed-role registry at bootstrap.
|
||||
tuples := []migrationTuple{
|
||||
{authtypes.SigNozAdminRoleName, "metaresource", "notification-channel", "create"},
|
||||
{authtypes.SigNozAdminRoleName, "metaresource", "notification-channel", "read"},
|
||||
{authtypes.SigNozAdminRoleName, "metaresource", "notification-channel", "update"},
|
||||
{authtypes.SigNozAdminRoleName, "metaresource", "notification-channel", "delete"},
|
||||
{authtypes.SigNozAdminRoleName, "metaresource", "notification-channel", "list"},
|
||||
{authtypes.SigNozEditorRoleName, "metaresource", "notification-channel", "read"},
|
||||
{authtypes.SigNozEditorRoleName, "metaresource", "notification-channel", "list"},
|
||||
{authtypes.SigNozViewerRoleName, "metaresource", "notification-channel", "read"},
|
||||
{authtypes.SigNozViewerRoleName, "metaresource", "notification-channel", "list"},
|
||||
}
|
||||
|
||||
for _, orgID := range orgIDs {
|
||||
for _, tuple := range tuples {
|
||||
entropy := ulid.DefaultEntropy()
|
||||
now := time.Now().UTC()
|
||||
tupleID := ulid.MustNew(ulid.Timestamp(now), entropy).String()
|
||||
|
||||
objectID := "organization/" + orgID + "/" + tuple.objectName + "/*"
|
||||
roleSubject := "organization/" + orgID + "/role/" + tuple.roleName
|
||||
|
||||
if isPG {
|
||||
user := "role:" + roleSubject + "#assignee"
|
||||
result, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO tuple (store, object_type, object_id, relation, _user, user_type, ulid, inserted_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT (store, object_type, object_id, relation, _user) DO NOTHING`,
|
||||
storeID, tuple.objectType, objectID, tuple.relation, user, "userset", tupleID, now,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rowsAffected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if rowsAffected == 0 {
|
||||
continue
|
||||
}
|
||||
_, err = tx.ExecContext(ctx, `
|
||||
INSERT INTO changelog (store, object_type, object_id, relation, _user, operation, ulid, inserted_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT (store, ulid, object_type) DO NOTHING`,
|
||||
storeID, tuple.objectType, objectID, tuple.relation, user, 0, tupleID, now,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
result, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO tuple (store, object_type, object_id, relation, user_object_type, user_object_id, user_relation, user_type, ulid, inserted_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT (store, object_type, object_id, relation, user_object_type, user_object_id, user_relation) DO NOTHING`,
|
||||
storeID, tuple.objectType, objectID, tuple.relation, "role", roleSubject, "assignee", "userset", tupleID, now,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rowsAffected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if rowsAffected == 0 {
|
||||
continue
|
||||
}
|
||||
_, err = tx.ExecContext(ctx, `
|
||||
INSERT INTO changelog (store, object_type, object_id, relation, user_object_type, user_object_id, user_relation, operation, ulid, inserted_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT (store, ulid, object_type) DO NOTHING`,
|
||||
storeID, tuple.objectType, objectID, tuple.relation, "role", roleSubject, "assignee", 0, tupleID, now,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (migration *addNotificationChannelTuples) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
91
pkg/sqlmigration/130_add_ai_observability_quick_filters.go
Normal file
91
pkg/sqlmigration/130_add_ai_observability_quick_filters.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
)
|
||||
|
||||
type storableAIObservabilityQuickFilter struct {
|
||||
bun.BaseModel `bun:"table:quick_filter"`
|
||||
|
||||
ID valuer.UUID `bun:"id,pk,type:text"`
|
||||
OrgID string `bun:"org_id,type:text,notnull"`
|
||||
Filter string `bun:"filter,type:text,notnull"`
|
||||
Source string `bun:"source,type:text,notnull"`
|
||||
CreatedAt time.Time `bun:"created_at"`
|
||||
UpdatedAt time.Time `bun:"updated_at"`
|
||||
}
|
||||
|
||||
type addAIObservabilityQuickFilters struct{}
|
||||
|
||||
func NewAddAIObservabilityQuickFiltersFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_ai_o11y_quick_filters"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return &addAIObservabilityQuickFilters{}, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (migration *addAIObservabilityQuickFilters) Register(migrations *migrate.Migrations) error {
|
||||
return migrations.Register(migration.Up, migration.Down)
|
||||
}
|
||||
|
||||
func (migration *addAIObservabilityQuickFilters) Up(ctx context.Context, db *bun.DB) error {
|
||||
filters := []telemetryFieldKeyOutput{
|
||||
{Name: "deployment.environment", FieldContext: "resource", FieldDataType: "string"},
|
||||
{Name: "gen_ai.operation.name", FieldContext: "attribute", FieldDataType: "string"},
|
||||
{Name: "gen_ai.provider.name", FieldContext: "attribute", FieldDataType: "string"},
|
||||
{Name: "gen_ai.request.model", FieldContext: "attribute", FieldDataType: "string"},
|
||||
{Name: "service.name", FieldContext: "resource", FieldDataType: "string"},
|
||||
{Name: "gen_ai.tool.name", FieldContext: "attribute", FieldDataType: "string"},
|
||||
{Name: "gen_ai.agent.name", FieldContext: "attribute", FieldDataType: "string"},
|
||||
}
|
||||
|
||||
filterJSON, err := marshalUnescaped(filters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
var orgIDs []string
|
||||
if err := tx.NewSelect().Table("organizations").Column("id").Scan(ctx, &orgIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(orgIDs) == 0 {
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
rows := make([]*storableAIObservabilityQuickFilter, 0, len(orgIDs))
|
||||
for _, orgID := range orgIDs {
|
||||
rows = append(rows, &storableAIObservabilityQuickFilter{
|
||||
ID: valuer.GenerateUUID(),
|
||||
OrgID: orgID,
|
||||
Filter: string(filterJSON),
|
||||
Source: "ai_observability",
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
})
|
||||
}
|
||||
|
||||
if _, err := tx.NewInsert().Model(&rows).On("CONFLICT (org_id, source) DO NOTHING").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (migration *addAIObservabilityQuickFilters) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -47,7 +47,7 @@ var (
|
||||
ResourceRole = NewResourceRole()
|
||||
ResourceServiceAccount = NewResourceServiceAccount()
|
||||
ResourceUser = NewResourceUser()
|
||||
ResourceMetaResourceNotificationChannel = NewResourceMetaResource(KindNotificationChannel)
|
||||
ResourceMetaResourceNotificationChannel = NewResourceMetaResource(KindNotificationChannel, VerbCreate, VerbList, VerbRead, VerbUpdate, VerbDelete)
|
||||
ResourceMetaResourceRoutePolicy = NewResourceMetaResource(KindRoutePolicy)
|
||||
ResourceMetaResourceApdexSetting = NewResourceMetaResource(KindApdexSetting)
|
||||
ResourceMetaResourceAuthDomain = NewResourceMetaResource(KindAuthDomain)
|
||||
|
||||
@@ -31,11 +31,11 @@ logger = setup_logger(__name__)
|
||||
NOTIFIERS_TEST = [
|
||||
types.AlertManagerNotificationTestCase(
|
||||
name="slack_notifier_default_templating",
|
||||
rule_path="alerts/test_scenarios/threshold_above_at_least_once/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_above_at_least_once/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_above_at_least_once/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_above_at_least_once/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
channel_config=slack_default_config,
|
||||
@@ -64,11 +64,11 @@ NOTIFIERS_TEST = [
|
||||
),
|
||||
types.AlertManagerNotificationTestCase(
|
||||
name="msteams_notifier_default_templating",
|
||||
rule_path="alerts/test_scenarios/threshold_above_at_least_once/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_above_at_least_once/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_above_at_least_once/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_above_at_least_once/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
channel_config=msteams_default_config,
|
||||
@@ -149,11 +149,11 @@ NOTIFIERS_TEST = [
|
||||
),
|
||||
types.AlertManagerNotificationTestCase(
|
||||
name="pagerduty_notifier_default_templating",
|
||||
rule_path="alerts/test_scenarios/threshold_above_at_least_once/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_above_at_least_once/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_above_at_least_once/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_above_at_least_once/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
channel_config=pagerduty_default_config,
|
||||
@@ -194,11 +194,11 @@ NOTIFIERS_TEST = [
|
||||
),
|
||||
types.AlertManagerNotificationTestCase(
|
||||
name="opsgenie_notifier_default_templating",
|
||||
rule_path="alerts/test_scenarios/threshold_above_at_least_once/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_above_at_least_once/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_above_at_least_once/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_above_at_least_once/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
channel_config=opsgenie_default_config,
|
||||
@@ -226,11 +226,11 @@ NOTIFIERS_TEST = [
|
||||
),
|
||||
types.AlertManagerNotificationTestCase(
|
||||
name="webhook_notifier_default_templating",
|
||||
rule_path="alerts/test_scenarios/threshold_above_at_least_once/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_above_at_least_once/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_above_at_least_once/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_above_at_least_once/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
channel_config=webhook_default_config,
|
||||
@@ -275,11 +275,11 @@ NOTIFIERS_TEST = [
|
||||
),
|
||||
types.AlertManagerNotificationTestCase(
|
||||
name="email_notifier_default_templating",
|
||||
rule_path="alerts/test_scenarios/threshold_above_at_least_once/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_above_at_least_once/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_above_at_least_once/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_above_at_least_once/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
channel_config=email_default_config,
|
||||
|
||||
@@ -21,12 +21,12 @@ from fixtures.logger import setup_logger
|
||||
TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_above_at_least_once",
|
||||
rule_path="alerts/test_scenarios/threshold_above_at_least_once/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_above_at_least_once/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
# active requests dummy data
|
||||
data_path="alerts/test_scenarios/threshold_above_at_least_once/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_above_at_least_once/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -44,11 +44,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_above_all_the_time",
|
||||
rule_path="alerts/test_scenarios/threshold_above_all_the_time/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_above_all_the_time/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_above_all_the_time/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_above_all_the_time/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -66,11 +66,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_above_in_total",
|
||||
rule_path="alerts/test_scenarios/threshold_above_in_total/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_above_in_total/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_above_in_total/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_above_in_total/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -96,11 +96,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_above_average",
|
||||
rule_path="alerts/test_scenarios/threshold_above_average/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_above_average/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="traces",
|
||||
data_path="alerts/test_scenarios/threshold_above_average/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_above_average/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -118,11 +118,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_above_last",
|
||||
rule_path="alerts/test_scenarios/threshold_above_last/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_above_last/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_above_last/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_above_last/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -140,11 +140,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_below_at_least_once",
|
||||
rule_path="alerts/test_scenarios/threshold_below_at_least_once/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_below_at_least_once/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="logs",
|
||||
data_path="alerts/test_scenarios/threshold_below_at_least_once/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_below_at_least_once/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -162,11 +162,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_below_all_the_time",
|
||||
rule_path="alerts/test_scenarios/threshold_below_all_the_time/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_below_all_the_time/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="logs",
|
||||
data_path="alerts/test_scenarios/threshold_below_all_the_time/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_below_all_the_time/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -184,12 +184,12 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_below_in_total",
|
||||
rule_path="alerts/test_scenarios/threshold_below_in_total/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_below_in_total/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
# one rate ~5 + rest 0.01 so it remains in total below 10
|
||||
data_path="alerts/test_scenarios/threshold_below_in_total/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_below_in_total/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -207,11 +207,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_below_average",
|
||||
rule_path="alerts/test_scenarios/threshold_below_average/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_below_average/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_below_average/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_below_average/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -229,11 +229,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_below_last",
|
||||
rule_path="alerts/test_scenarios/threshold_below_last/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_below_last/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_below_last/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_below_last/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -251,11 +251,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_equal_to_at_least_once",
|
||||
rule_path="alerts/test_scenarios/threshold_equal_to_at_least_once/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_equal_to_at_least_once/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_equal_to_at_least_once/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_equal_to_at_least_once/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -273,11 +273,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_equal_to_all_the_time",
|
||||
rule_path="alerts/test_scenarios/threshold_equal_to_all_the_time/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_equal_to_all_the_time/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_equal_to_all_the_time/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_equal_to_all_the_time/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -295,11 +295,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_equal_to_in_total",
|
||||
rule_path="alerts/test_scenarios/threshold_equal_to_in_total/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_equal_to_in_total/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_equal_to_in_total/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_equal_to_in_total/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -317,11 +317,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_equal_to_average",
|
||||
rule_path="alerts/test_scenarios/threshold_equal_to_average/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_equal_to_average/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_equal_to_average/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_equal_to_average/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -339,11 +339,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_equal_to_last",
|
||||
rule_path="alerts/test_scenarios/threshold_equal_to_last/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_equal_to_last/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_equal_to_last/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_equal_to_last/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -361,11 +361,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_not_equal_to_at_least_once",
|
||||
rule_path="alerts/test_scenarios/threshold_not_equal_to_at_least_once/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_not_equal_to_at_least_once/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_not_equal_to_at_least_once/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_not_equal_to_at_least_once/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -383,11 +383,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_not_equal_to_all_the_time",
|
||||
rule_path="alerts/test_scenarios/threshold_not_equal_to_all_the_time/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_not_equal_to_all_the_time/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_not_equal_to_all_the_time/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_not_equal_to_all_the_time/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -405,11 +405,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_not_equal_to_in_total",
|
||||
rule_path="alerts/test_scenarios/threshold_not_equal_to_in_total/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_not_equal_to_in_total/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_not_equal_to_in_total/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_not_equal_to_in_total/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -427,11 +427,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_not_equal_to_average",
|
||||
rule_path="alerts/test_scenarios/threshold_not_equal_to_average/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_not_equal_to_average/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_not_equal_to_average/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_not_equal_to_average/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -449,11 +449,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_threshold_not_equal_to_last",
|
||||
rule_path="alerts/test_scenarios/threshold_not_equal_to_last/rule.json",
|
||||
rule_path="rules/test_scenarios/threshold_not_equal_to_last/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/threshold_not_equal_to_last/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/threshold_not_equal_to_last/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -475,11 +475,11 @@ TEST_RULES_MATCH_TYPE_AND_COMPARE_OPERATORS = [
|
||||
TEST_RULES_UNIT_CONVERSION = [
|
||||
types.AlertTestCase(
|
||||
name="test_unit_conversion_bytes_to_mb",
|
||||
rule_path="alerts/test_scenarios/unit_conversion_bytes_to_mb/rule.json",
|
||||
rule_path="rules/test_scenarios/unit_conversion_bytes_to_mb/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/unit_conversion_bytes_to_mb/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/unit_conversion_bytes_to_mb/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -497,11 +497,11 @@ TEST_RULES_UNIT_CONVERSION = [
|
||||
),
|
||||
types.AlertTestCase(
|
||||
name="test_unit_conversion_ms_to_second",
|
||||
rule_path="alerts/test_scenarios/unit_conversion_ms_to_second/rule.json",
|
||||
rule_path="rules/test_scenarios/unit_conversion_ms_to_second/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/unit_conversion_ms_to_second/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/unit_conversion_ms_to_second/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -523,11 +523,11 @@ TEST_RULES_UNIT_CONVERSION = [
|
||||
TEST_RULES_MISCELLANEOUS = [
|
||||
types.AlertTestCase(
|
||||
name="test_no_data_rule_test",
|
||||
rule_path="alerts/test_scenarios/no_data_rule_test/rule.json",
|
||||
rule_path="rules/test_scenarios/no_data_rule_test/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/no_data_rule_test/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/no_data_rule_test/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -547,11 +547,11 @@ TEST_RULES_MISCELLANEOUS = [
|
||||
# after the [issue](https://github.com/SigNoz/engineering-pod/issues/3934) with alertManager is resolved
|
||||
# types.AlertTestCase(
|
||||
# name="test_multi_threshold_rule_test",
|
||||
# rule_path="alerts/test_scenarios/multi_threshold_rule_test/rule.json",
|
||||
# rule_path="rules/test_scenarios/multi_threshold_rule_test/rule.json",
|
||||
# alert_data=[
|
||||
# types.AlertData(
|
||||
# type="metrics",
|
||||
# data_path="alerts/test_scenarios/multi_threshold_rule_test/alert_data.jsonl",
|
||||
# data_path="rules/test_scenarios/multi_threshold_rule_test/alert_data.jsonl",
|
||||
# ),
|
||||
# ],
|
||||
# alert_expectation=types.AlertExpectation(
|
||||
@@ -29,10 +29,10 @@ def test_logs_rule_history_related_links(
|
||||
query_start_ms = int((datetime.now(tz=UTC) - timedelta(minutes=30)).timestamp() * 1000)
|
||||
|
||||
insert_alert_data(
|
||||
[types.AlertData(type="logs", data_path="alerts/test_scenarios/rule_state_history_logs/alert_data.jsonl")],
|
||||
[types.AlertData(type="logs", data_path="rules/test_scenarios/rule_state_history_logs/alert_data.jsonl")],
|
||||
base_time=datetime.now(tz=UTC) - timedelta(minutes=5),
|
||||
)
|
||||
rule_id = create_alert_rule_with_channel("alerts/test_scenarios/rule_state_history_logs/rule.json")
|
||||
rule_id = create_alert_rule_with_channel("rules/test_scenarios/rule_state_history_logs/rule.json")
|
||||
|
||||
(item, query_end_ms) = wait_for_firing_timeline_entry(signoz, token, rule_id, query_start_ms)
|
||||
|
||||
@@ -73,10 +73,10 @@ def test_traces_rule_history_related_links(
|
||||
query_start_ms = int((datetime.now(tz=UTC) - timedelta(minutes=30)).timestamp() * 1000)
|
||||
|
||||
insert_alert_data(
|
||||
[types.AlertData(type="traces", data_path="alerts/test_scenarios/rule_state_history_traces/alert_data.jsonl")],
|
||||
[types.AlertData(type="traces", data_path="rules/test_scenarios/rule_state_history_traces/alert_data.jsonl")],
|
||||
base_time=datetime.now(tz=UTC) - timedelta(minutes=5),
|
||||
)
|
||||
rule_id = create_alert_rule_with_channel("alerts/test_scenarios/rule_state_history_traces/rule.json")
|
||||
rule_id = create_alert_rule_with_channel("rules/test_scenarios/rule_state_history_traces/rule.json")
|
||||
|
||||
(item, query_end_ms) = wait_for_firing_timeline_entry(signoz, token, rule_id, query_start_ms)
|
||||
|
||||
@@ -117,10 +117,10 @@ def test_ai_traces_rule_history_related_links(
|
||||
query_start_ms = int((datetime.now(tz=UTC) - timedelta(minutes=30)).timestamp() * 1000)
|
||||
|
||||
insert_alert_data(
|
||||
[types.AlertData(type="traces", data_path="alerts/test_scenarios/rule_state_history_ai_traces/alert_data.jsonl")],
|
||||
[types.AlertData(type="traces", data_path="rules/test_scenarios/rule_state_history_ai_traces/alert_data.jsonl")],
|
||||
base_time=datetime.now(tz=UTC) - timedelta(minutes=5),
|
||||
)
|
||||
rule_id = create_alert_rule_with_channel("alerts/test_scenarios/rule_state_history_ai_traces/rule.json")
|
||||
rule_id = create_alert_rule_with_channel("rules/test_scenarios/rule_state_history_ai_traces/rule.json")
|
||||
|
||||
(item, query_end_ms) = wait_for_firing_timeline_entry(signoz, token, rule_id, query_start_ms)
|
||||
|
||||
@@ -14,11 +14,11 @@ from fixtures.fs import get_testdata_file_path
|
||||
|
||||
TEST_CASE = types.AlertTestCase(
|
||||
name="promql_subquery_no_step",
|
||||
rule_path="alerts/test_scenarios/promql_subquery_no_step/rule.json",
|
||||
rule_path="rules/test_scenarios/promql_subquery_no_step/rule.json",
|
||||
alert_data=[
|
||||
types.AlertData(
|
||||
type="metrics",
|
||||
data_path="alerts/test_scenarios/promql_subquery_no_step/alert_data.jsonl",
|
||||
data_path="rules/test_scenarios/promql_subquery_no_step/alert_data.jsonl",
|
||||
),
|
||||
],
|
||||
alert_expectation=types.AlertExpectation(
|
||||
@@ -40,7 +40,7 @@ def test_disabled_rule_does_not_evaluate_or_notify(
|
||||
A rule created with disabled: true must not be evaluated: its state must
|
||||
stay "disabled" and it must not send any notification, even though the
|
||||
inserted data would fire the rule if it were evaluated. The companion
|
||||
scenario threshold_above_at_least_once in 02_basic_alert_conditions.py
|
||||
scenario threshold_above_at_least_once in 01_basic_alert_conditions.py
|
||||
uses the same data shape and fires when the rule is enabled.
|
||||
"""
|
||||
token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
@@ -78,12 +78,12 @@ def test_disabled_rule_does_not_evaluate_or_notify(
|
||||
|
||||
# Insert alert data that would fire the rule if it were evaluated
|
||||
insert_alert_data(
|
||||
[types.AlertData(type="metrics", data_path="alerts/test_scenarios/disabled_rule/alert_data.jsonl")],
|
||||
[types.AlertData(type="metrics", data_path="rules/test_scenarios/disabled_rule/alert_data.jsonl")],
|
||||
base_time=datetime.now(tz=UTC) - timedelta(minutes=5),
|
||||
)
|
||||
|
||||
# Create the disabled alert rule
|
||||
rule_path = get_testdata_file_path("alerts/test_scenarios/disabled_rule/rule.json")
|
||||
rule_path = get_testdata_file_path("rules/test_scenarios/disabled_rule/rule.json")
|
||||
with open(rule_path, encoding="utf-8") as f:
|
||||
rule_data = json.loads(f.read())
|
||||
update_rule_channel_name(rule_data, notification_channel_name)
|
||||
Reference in New Issue
Block a user