Connect process log view to store
[arvados-workbench2.git] / src / store / process-logs-panel / process-logs-panel-actions.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { unionize, ofType, UnionOf } from "~/common/unionize";
6 import { ProcessLogs } from './process-logs-panel';
7 import { LogEventType } from '~/models/log';
8 import { RootState } from '~/store/store';
9 import { ServiceRepository } from '~/services/services';
10 import { Dispatch } from 'redux';
11 import { FilterBuilder } from '~/common/api/filter-builder';
12 import { groupBy } from 'lodash';
13 import { loadProcess } from '~/store/processes/processes-actions';
14 import { OrderBuilder } from '~/common/api/order-builder';
15 import { LogResource } from '~/models/log';
16 import { LogService } from '~/services/log-service/log-service';
17
18 export const processLogsPanelActions = unionize({
19     INIT_PROCESS_LOGS_PANEL: ofType<{ filters: string[], logs: ProcessLogs }>(),
20     SET_PROCESS_LOGS_PANEL_FILTER: ofType<string>(),
21     ADD_PROCESS_LOGS_PANEL_ITEM: ofType<{ logType: string, log: string }>(),
22 });
23
24 export type ProcessLogsPanelAction = UnionOf<typeof processLogsPanelActions>;
25
26 export const setProcessLogsPanelFilter = (filter: string) =>
27     processLogsPanelActions.SET_PROCESS_LOGS_PANEL_FILTER(filter);
28
29 export const initProcessLogsPanel = (processUuid: string) =>
30     async (dispatch: Dispatch, getState: () => RootState, { logService }: ServiceRepository) => {
31         const process = await dispatch<any>(loadProcess(processUuid));
32         if (process.container) {
33             const logResources = await loadContainerLogs(process.container.uuid, logService);
34             const initialState = createInitialLogPanelState(logResources);
35             dispatch(processLogsPanelActions.INIT_PROCESS_LOGS_PANEL(initialState));
36         }
37     };
38
39 const loadContainerLogs = async (containerUuid: string, logService: LogService) => {
40     const requestFilters = new FilterBuilder()
41         .addEqual('objectUuid', containerUuid)
42         .addIn('eventType', PROCESS_PANEL_LOG_EVENT_TYPES)
43         .getFilters();
44     const requestOrder = new OrderBuilder<LogResource>()
45         .addAsc('eventAt')
46         .getOrder();
47     const requestParams = {
48         limit: MAX_AMOUNT_OF_LOGS,
49         filters: requestFilters,
50         order: requestOrder,
51     };
52     const { items } = await logService.list(requestParams);
53     return items;
54 };
55
56 const createInitialLogPanelState = (logResources: LogResource[]) => {
57     const allLogs = logsToLines(logResources);
58     const groupedLogResources = groupBy(logResources, log => log.eventType);
59     const groupedLogs = Object
60         .keys(groupedLogResources)
61         .reduce((grouped, key) => ({
62             ...grouped,
63             [key]: logsToLines(groupedLogResources[key])
64         }), {});
65     const filters = [SUMMARIZED_FILTER_TYPE, ...Object.keys(groupedLogs)];
66     const logs = { [SUMMARIZED_FILTER_TYPE]: allLogs, ...groupedLogs };
67     return { filters, logs };
68 };
69
70 const logsToLines = (logs: LogResource[]) => 
71     logs.map(({properties}) => properties.text);
72
73 const MAX_AMOUNT_OF_LOGS = 10000;
74
75 const SUMMARIZED_FILTER_TYPE = 'Summarized';
76
77 const PROCESS_PANEL_LOG_EVENT_TYPES = [
78     LogEventType.ARV_MOUNT,
79     LogEventType.CRUNCH_RUN,
80     LogEventType.CRUNCHSTAT,
81     LogEventType.DISPATCH,
82     LogEventType.HOSTSTAT,
83     LogEventType.NODE_INFO,
84     LogEventType.STDERR,
85     LogEventType.STDOUT,
86 ];