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 committed Jan 21, 2020
1 parent fca83a6 commit 5c354ee
Show file tree
Hide file tree
Showing 39 changed files with 2,442 additions and 16 deletions.
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 5c354ee

Please sign in to comment.