Skip to content

Commit

Permalink
Adds event log for actions and alerting (#45081)
Browse files Browse the repository at this point in the history
initial code for event log

see issue #45083
  • Loading branch information
pmuellr authored Jan 21, 2020
1 parent db1a64d commit b78c1b1
Show file tree
Hide file tree
Showing 40 changed files with 2,443 additions and 16 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
# Kibana Alerting Services
/x-pack/legacy/plugins/alerting/ @elastic/kibana-alerting-services
/x-pack/legacy/plugins/actions/ @elastic/kibana-alerting-services
/x-pack/plugins/event_log/ @elastic/kibana-alerting-services
/x-pack/plugins/task_manager/ @elastic/kibana-alerting-services
/x-pack/test/alerting_api_integration/ @elastic/kibana-alerting-services
/x-pack/test/plugin_api_integration/plugins/task_manager/ @elastic/kibana-alerting-services
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
savedObjectsClientMock,
loggingServiceMock,
} from '../../../../../../src/core/server/mocks';
import { createEventLoggerMock } from '../../../../../plugins/event_log/server/event_logger.mock';

const actionExecutor = new ActionExecutor();
const savedObjectsClient = savedObjectsClientMock.create();
Expand Down Expand Up @@ -58,6 +59,7 @@ actionExecutor.initialize({
getServices,
actionTypeRegistry,
encryptedSavedObjectsPlugin,
eventLogger: createEventLoggerMock(),
});

beforeEach(() => jest.resetAllMocks());
Expand Down
70 changes: 57 additions & 13 deletions x-pack/legacy/plugins/actions/server/lib/action_executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ import {
GetServicesFunction,
RawAction,
} from '../types';
import { EVENT_LOG_ACTIONS } from '../plugin';
import { IEvent, IEventLogger } from '../../../../../plugins/event_log/server';

export interface ActionExecutorContext {
logger: Logger;
spaces: () => SpacesPluginStartContract | undefined;
getServices: GetServicesFunction;
encryptedSavedObjectsPlugin: EncryptedSavedObjectsStartContract;
actionTypeRegistry: ActionTypeRegistryContract;
eventLogger: IEventLogger;
}

export interface ExecuteOptions {
Expand Down Expand Up @@ -54,11 +57,11 @@ export class ActionExecutor {
}

const {
logger,
spaces,
getServices,
encryptedSavedObjectsPlugin,
actionTypeRegistry,
eventLogger,
} = this.actionExecutorContext!;

const spacesPlugin = spaces();
Expand Down Expand Up @@ -89,9 +92,9 @@ export class ActionExecutor {
);
const actionType = actionTypeRegistry.get(actionTypeId);

let validatedParams;
let validatedConfig;
let validatedSecrets;
let validatedParams: Record<string, any>;
let validatedConfig: Record<string, any>;
let validatedSecrets: Record<string, any>;

try {
validatedParams = validateParams(actionType, params);
Expand All @@ -101,27 +104,68 @@ export class ActionExecutor {
return { status: 'error', actionId, message: err.message, retry: false };
}

let result: ActionTypeExecutorResult | null = null;
const actionLabel = `${actionId} - ${actionTypeId} - ${name}`;
const actionLabel = `${actionTypeId}:${actionId}: ${name}`;
const event: IEvent = {
event: { action: EVENT_LOG_ACTIONS.execute },
kibana: { namespace, saved_objects: [{ type: 'action', id: actionId }] },
};

eventLogger.startTiming(event);
let rawResult: ActionTypeExecutorResult | null | undefined | void;
try {
result = await actionType.executor({
rawResult = await actionType.executor({
actionId,
services,
params: validatedParams,
config: validatedConfig,
secrets: validatedSecrets,
});
} catch (err) {
logger.warn(`action executed unsuccessfully: ${actionLabel} - ${err.message}`);
throw err;
rawResult = {
actionId,
status: 'error',
message: 'an error occurred while running the action executor',
serviceMessage: err.message,
retry: false,
};
}
eventLogger.stopTiming(event);

logger.debug(`action executed successfully: ${actionLabel}`);

// return basic response if none provided
if (result == null) return { status: 'ok', actionId };
// allow null-ish return to indicate success
const result = rawResult || {
actionId,
status: 'ok',
};

if (result.status === 'ok') {
event.message = `action executed: ${actionLabel}`;
} else if (result.status === 'error') {
event.message = `action execution failure: ${actionLabel}`;
event.error = event.error || {};
event.error.message = actionErrorToMessage(result);
} else {
event.message = `action execution returned unexpected result: ${actionLabel}`;
event.error = event.error || {};
event.error.message = 'action execution returned unexpected result';
}

eventLogger.logEvent(event);
return result;
}
}

function actionErrorToMessage(result: ActionTypeExecutorResult): string {
let message = result.message || 'unknown error running action';

if (result.serviceMessage) {
message = `${message}: ${result.serviceMessage}`;
}

if (result.retry instanceof Date) {
message = `${message}; retry at ${result.retry.toISOString()}`;
} else if (result.retry) {
message = `${message}; retry: ${JSON.stringify(result.retry)}`;
}

return message;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
savedObjectsClientMock,
loggingServiceMock,
} from '../../../../../../src/core/server/mocks';
import { createEventLoggerMock } from '../../../../../plugins/event_log/server/event_logger.mock';

const spaceIdToNamespace = jest.fn();
const actionTypeRegistry = actionTypeRegistryMock.create();
Expand Down Expand Up @@ -62,6 +63,7 @@ const actionExecutorInitializerParams = {
actionTypeRegistry,
spaces: () => undefined,
encryptedSavedObjectsPlugin: mockedEncryptedSavedObjectsPlugin,
eventLogger: createEventLoggerMock(),
};
const taskRunnerFactoryInitializerParams = {
spaceIdToNamespace,
Expand Down
14 changes: 14 additions & 0 deletions x-pack/legacy/plugins/actions/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ import {
} from './routes';
import { extendRouteWithLicenseCheck } from './extend_route_with_license_check';
import { LicenseState } from './lib/license_state';
import { IEventLogger } from '../../../../plugins/event_log/server';

const EVENT_LOG_PROVIDER = 'actions';
export const EVENT_LOG_ACTIONS = {
execute: 'execute',
executeViaHttp: 'execute-via-http',
};

export interface PluginSetupContract {
registerType: ActionTypeRegistry['register'];
Expand All @@ -57,6 +64,7 @@ export class Plugin {
private actionExecutor?: ActionExecutor;
private defaultKibanaIndex?: string;
private licenseState: LicenseState | null = null;
private eventLogger?: IEventLogger;

constructor(initializerContext: ActionsPluginInitializerContext) {
this.logger = initializerContext.logger.get('plugins', 'actions');
Expand Down Expand Up @@ -88,6 +96,11 @@ export class Plugin {
attributesToEncrypt: new Set(['apiKey']),
});

plugins.event_log.registerProviderActions(EVENT_LOG_PROVIDER, Object.values(EVENT_LOG_ACTIONS));
this.eventLogger = plugins.event_log.getLogger({
event: { provider: EVENT_LOG_PROVIDER },
});

const actionExecutor = new ActionExecutor();
const taskRunnerFactory = new TaskRunnerFactory(actionExecutor);
const actionsConfigUtils = getActionsConfigurationUtilities(config as ActionsConfigType);
Expand Down Expand Up @@ -156,6 +169,7 @@ export class Plugin {
getServices,
encryptedSavedObjectsPlugin: plugins.encryptedSavedObjects,
actionTypeRegistry: actionTypeRegistry!,
eventLogger: this.eventLogger!,
});
taskRunnerFactory!.initialize({
encryptedSavedObjectsPlugin: plugins.encryptedSavedObjects,
Expand Down
3 changes: 3 additions & 0 deletions x-pack/legacy/plugins/actions/server/shim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
SavedObjectsLegacyService,
} from '../../../../../src/core/server';
import { LicensingPluginSetup } from '../../../../plugins/licensing/server';
import { IEventLogService } from '../../../../plugins/event_log/server';

export interface KibanaConfig {
index: string;
Expand Down Expand Up @@ -67,6 +68,7 @@ export interface ActionsPluginsSetup {
xpack_main: XPackMainPluginSetupContract;
encryptedSavedObjects: EncryptedSavedObjectsSetupContract;
licensing: LicensingPluginSetup;
event_log: IEventLogService;
}
export interface ActionsPluginsStart {
security?: SecurityPluginStartContract;
Expand Down Expand Up @@ -126,6 +128,7 @@ export function shim(
encryptedSavedObjects: newPlatform.setup.plugins
.encryptedSavedObjects as EncryptedSavedObjectsSetupContract,
licensing: newPlatform.setup.plugins.licensing as LicensingPluginSetup,
event_log: newPlatform.setup.plugins.event_log as IEventLogService,
};

const pluginsStart: ActionsPluginsStart = {
Expand Down
2 changes: 1 addition & 1 deletion x-pack/legacy/plugins/actions/server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export interface ActionTypeExecutorResult {
// signature of the action type executor function
export type ExecutorType = (
options: ActionTypeExecutorOptions
) => Promise<ActionTypeExecutorResult>;
) => Promise<ActionTypeExecutorResult | null | undefined | void>;

interface ValidatorType {
validate<T>(value: any): any;
Expand Down
Loading

0 comments on commit b78c1b1

Please sign in to comment.