Skip to content

Commit

Permalink
Onboard Log Threshold rule type with FAAD (#178680)
Browse files Browse the repository at this point in the history
Towards: #169867

This PR onboards Log Threshold rule type with FAAD.

### To verify

Create a log threshold rule.
Example:
```
POST kbn:/api/alerting/rule
{
  "params": {
    "logView": {
      "logViewId": "Default",
      "type": "log-view-reference"
    },
    "timeSize": 5,
    "timeUnit": "m",
    "count": {
      "value": -1,
      "comparator": "more than"
    },
    "criteria": [
      {
        "field": "log.level",
        "comparator": "equals",
        "value": "error"
      }
    ]
  },
  "consumer": "alerts",
  "schedule": {
    "interval": "1m"
  },
  "tags": [],
  "name": "test",
  "rule_type_id": "logs.alert.document.count",
  "notify_when": "onActionGroupChange",
  "actions": []
}
```
Your rule should create an alert and should saved it in
`.internal.alerts-observability.metrics.alerts-default-000001`
Example:
```
GET .internal.alerts-*/_search
```
Then set `count.value: 75`

The alert should be recovered and the AAD in the above index should be
updated `kibana.alert.status: recovered`.
  • Loading branch information
doakalexi authored Mar 25, 2024
1 parent eed7069 commit e11e981
Show file tree
Hide file tree
Showing 4 changed files with 346 additions and 280 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import {
getGroupedESQuery,
processUngroupedResults,
processGroupByResults,
LogThresholdAlertFactory,
LogThresholdAlertLimit,
LogThresholdAlertReporter,
getUngroupedESQuery,
} from './log_threshold_executor';
import {
Expand Down Expand Up @@ -437,10 +436,14 @@ describe('Log threshold executor', () => {
describe('Results processors', () => {
describe('for ungrouped results', () => {
it('handles the ALERT state correctly', () => {
const alertFactoryMock: jest.MockedFunction<LogThresholdAlertFactory> = jest.fn();
const alertLimitMock: jest.Mocked<LogThresholdAlertLimit> = {
getValue: jest.fn().mockReturnValue(10),
setLimitReached: jest.fn(),
const alertReporterMock: jest.MockedFunction<LogThresholdAlertReporter> = jest.fn();
const alertsClientMock = {
report: jest.fn(),
getAlertLimitValue: jest.fn().mockReturnValue(10),
setAlertLimitReached: jest.fn(),
getRecoveredAlerts: jest.fn(),
setAlertData: jest.fn(),
isTrackedAlert: jest.fn(),
};

const ruleParams = {
Expand All @@ -455,10 +458,10 @@ describe('Log threshold executor', () => {
},
} as UngroupedSearchQueryResponse;

processUngroupedResults(results, ruleParams, alertFactoryMock, alertLimitMock);
processUngroupedResults(results, ruleParams, alertReporterMock, alertsClientMock);

// first call, fifth argument
expect(alertFactoryMock.mock.calls[0][4]).toEqual([
expect(alertReporterMock.mock.calls[0][4]).toEqual([
{
actionGroup: 'logs.threshold.fired',
context: {
Expand All @@ -473,10 +476,14 @@ describe('Log threshold executor', () => {
});

it('reports reaching a low limit when alerting', () => {
const alertFactoryMock: jest.MockedFunction<LogThresholdAlertFactory> = jest.fn();
const alertLimitMock: jest.Mocked<LogThresholdAlertLimit> = {
getValue: jest.fn().mockReturnValue(1),
setLimitReached: jest.fn(),
const alertReporterMock: jest.MockedFunction<LogThresholdAlertReporter> = jest.fn();
const alertsClientMock = {
report: jest.fn(),
getAlertLimitValue: jest.fn().mockReturnValue(1),
setAlertLimitReached: jest.fn(),
getRecoveredAlerts: jest.fn(),
setAlertData: jest.fn(),
isTrackedAlert: jest.fn(),
};

const ruleParams = {
Expand All @@ -491,17 +498,21 @@ describe('Log threshold executor', () => {
},
} as UngroupedSearchQueryResponse;

processUngroupedResults(results, ruleParams, alertFactoryMock, alertLimitMock);
processUngroupedResults(results, ruleParams, alertReporterMock, alertsClientMock);

expect(alertFactoryMock).toBeCalledTimes(1);
expect(alertLimitMock.setLimitReached).toHaveBeenCalledWith(true);
expect(alertReporterMock).toBeCalledTimes(1);
expect(alertsClientMock.setAlertLimitReached).toHaveBeenCalledWith(true);
});

it('reports not reaching a higher limit when alerting', () => {
const alertFactoryMock: jest.MockedFunction<LogThresholdAlertFactory> = jest.fn();
const alertLimitMock: jest.Mocked<LogThresholdAlertLimit> = {
getValue: jest.fn().mockReturnValue(10),
setLimitReached: jest.fn(),
const alertReporterMock: jest.MockedFunction<LogThresholdAlertReporter> = jest.fn();
const alertsClientMock = {
report: jest.fn(),
getAlertLimitValue: jest.fn().mockReturnValue(10),
setAlertLimitReached: jest.fn(),
getRecoveredAlerts: jest.fn(),
setAlertData: jest.fn(),
isTrackedAlert: jest.fn(),
};

const ruleParams = {
Expand All @@ -516,17 +527,21 @@ describe('Log threshold executor', () => {
},
} as UngroupedSearchQueryResponse;

processUngroupedResults(results, ruleParams, alertFactoryMock, alertLimitMock);
processUngroupedResults(results, ruleParams, alertReporterMock, alertsClientMock);

expect(alertFactoryMock).toBeCalledTimes(1);
expect(alertLimitMock.setLimitReached).toHaveBeenCalledWith(false);
expect(alertReporterMock).toBeCalledTimes(1);
expect(alertsClientMock.setAlertLimitReached).toHaveBeenCalledWith(false);
});

it('reports not reaching the limit without any alerts', () => {
const alertFactoryMock: jest.MockedFunction<LogThresholdAlertFactory> = jest.fn();
const alertLimitMock: jest.Mocked<LogThresholdAlertLimit> = {
getValue: jest.fn().mockReturnValue(0),
setLimitReached: jest.fn(),
const alertReporterMock: jest.MockedFunction<LogThresholdAlertReporter> = jest.fn();
const alertsClientMock = {
report: jest.fn(),
getAlertLimitValue: jest.fn().mockReturnValue(0),
setAlertLimitReached: jest.fn(),
getRecoveredAlerts: jest.fn(),
setAlertData: jest.fn(),
isTrackedAlert: jest.fn(),
};

const ruleParams = {
Expand All @@ -541,19 +556,23 @@ describe('Log threshold executor', () => {
},
} as UngroupedSearchQueryResponse;

processUngroupedResults(results, ruleParams, alertFactoryMock, alertLimitMock);
processUngroupedResults(results, ruleParams, alertReporterMock, alertsClientMock);

expect(alertFactoryMock).not.toHaveBeenCalled();
expect(alertLimitMock.setLimitReached).toHaveBeenCalledWith(false);
expect(alertReporterMock).not.toHaveBeenCalled();
expect(alertsClientMock.setAlertLimitReached).toHaveBeenCalledWith(false);
});
});

describe('for grouped results', () => {
it('handles the ALERT state correctly', () => {
const alertFactoryMock: jest.MockedFunction<LogThresholdAlertFactory> = jest.fn();
const alertLimitMock: jest.Mocked<LogThresholdAlertLimit> = {
getValue: jest.fn().mockReturnValue(2),
setLimitReached: jest.fn(),
const alertReporterMock: jest.MockedFunction<LogThresholdAlertReporter> = jest.fn();
const alertsClientMock = {
report: jest.fn(),
getAlertLimitValue: jest.fn().mockReturnValue(2),
setAlertLimitReached: jest.fn(),
getRecoveredAlerts: jest.fn(),
setAlertData: jest.fn(),
isTrackedAlert: jest.fn(),
};

const ruleParams = {
Expand Down Expand Up @@ -628,11 +647,11 @@ describe('Log threshold executor', () => {
},
] as GroupedSearchQueryResponse['aggregations']['groups']['buckets'];

processGroupByResults(results, ruleParams, alertFactoryMock, alertLimitMock);
expect(alertFactoryMock.mock.calls.length).toBe(2);
processGroupByResults(results, ruleParams, alertReporterMock, alertsClientMock);
expect(alertReporterMock.mock.calls.length).toBe(2);

// First call, fifth argument
expect(alertFactoryMock.mock.calls[0][4]).toEqual([
expect(alertReporterMock.mock.calls[0][4]).toEqual([
{
actionGroup: 'logs.threshold.fired',
context: {
Expand All @@ -658,7 +677,7 @@ describe('Log threshold executor', () => {
]);

// Second call, fifth argument
expect(alertFactoryMock.mock.calls[1][4]).toEqual([
expect(alertReporterMock.mock.calls[1][4]).toEqual([
{
actionGroup: 'logs.threshold.fired',
context: {
Expand All @@ -685,10 +704,14 @@ describe('Log threshold executor', () => {
});

it('respects and reports reaching a low limit when alerting', () => {
const alertFactoryMock: jest.MockedFunction<LogThresholdAlertFactory> = jest.fn();
const alertLimitMock: jest.Mocked<LogThresholdAlertLimit> = {
getValue: jest.fn().mockReturnValue(1),
setLimitReached: jest.fn(),
const alertReporterMock: jest.MockedFunction<LogThresholdAlertReporter> = jest.fn();
const alertsClientMock = {
report: jest.fn(),
getAlertLimitValue: jest.fn().mockReturnValue(1),
setAlertLimitReached: jest.fn(),
getRecoveredAlerts: jest.fn(),
setAlertData: jest.fn(),
isTrackedAlert: jest.fn(),
};

const ruleParams = {
Expand Down Expand Up @@ -763,17 +786,21 @@ describe('Log threshold executor', () => {
},
] as GroupedSearchQueryResponse['aggregations']['groups']['buckets'];

processGroupByResults(results, ruleParams, alertFactoryMock, alertLimitMock);
processGroupByResults(results, ruleParams, alertReporterMock, alertsClientMock);

expect(alertFactoryMock).toHaveBeenCalledTimes(1);
expect(alertLimitMock.setLimitReached).toHaveBeenCalledWith(true);
expect(alertReporterMock).toHaveBeenCalledTimes(1);
expect(alertsClientMock.setAlertLimitReached).toHaveBeenCalledWith(true);
});

it('reports not reaching a higher limit when alerting', () => {
const alertFactoryMock: jest.MockedFunction<LogThresholdAlertFactory> = jest.fn();
const alertLimitMock: jest.Mocked<LogThresholdAlertLimit> = {
getValue: jest.fn().mockReturnValue(10),
setLimitReached: jest.fn(),
const alertReporterMock: jest.MockedFunction<LogThresholdAlertReporter> = jest.fn();
const alertsClientMock = {
report: jest.fn(),
getAlertLimitValue: jest.fn().mockReturnValue(10),
setAlertLimitReached: jest.fn(),
getRecoveredAlerts: jest.fn(),
setAlertData: jest.fn(),
isTrackedAlert: jest.fn(),
};

const ruleParams = {
Expand Down Expand Up @@ -848,10 +875,10 @@ describe('Log threshold executor', () => {
},
] as GroupedSearchQueryResponse['aggregations']['groups']['buckets'];

processGroupByResults(results, ruleParams, alertFactoryMock, alertLimitMock);
processGroupByResults(results, ruleParams, alertReporterMock, alertsClientMock);

expect(alertFactoryMock).toHaveBeenCalledTimes(2);
expect(alertLimitMock.setLimitReached).toHaveBeenCalledWith(false);
expect(alertReporterMock).toHaveBeenCalledTimes(2);
expect(alertsClientMock.setAlertLimitReached).toHaveBeenCalledWith(false);
});
});
});
Expand Down
Loading

0 comments on commit e11e981

Please sign in to comment.