From: Michal Klobukowski Date: Fri, 31 Aug 2018 13:42:55 +0000 (+0200) Subject: Create actions and reducer for process logs panel X-Git-Tag: 1.3.0~122^2~6 X-Git-Url: https://git.arvados.org/arvados-workbench2.git/commitdiff_plain/54d815ef6c96fca27ffc20019114539383f9c892 Create actions and reducer for process logs panel Feature #14100 Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski --- diff --git a/src/store/process-logs-panel/process-logs-panel-actions.ts b/src/store/process-logs-panel/process-logs-panel-actions.ts new file mode 100644 index 00000000..dce104eb --- /dev/null +++ b/src/store/process-logs-panel/process-logs-panel-actions.ts @@ -0,0 +1,79 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import { unionize, ofType, UnionOf } from "~/common/unionize"; +import { ProcessLogs } from './process-logs-panel'; +import { LogEventType } from '~/models/log'; +import { RootState } from '~/store/store'; +import { ServiceRepository } from '~/services/services'; +import { Dispatch } from 'redux'; +import { FilterBuilder } from '~/common/api/filter-builder'; +import { groupBy } from 'lodash'; +import { loadProcess } from '~/store/processes/processes-actions'; +import { OrderBuilder } from '~/common/api/order-builder'; +import { LogResource } from '~/models/log'; +import { LogService } from '~/services/log-service/log-service'; + +export const processLogsPanelActions = unionize({ + INIT_PROCESS_LOGS_PANEL: ofType<{ filters: string[], logs: ProcessLogs }>(), + SET_PROCESS_LOGS_PANEL_FILTER: ofType(), + ADD_PROCESS_LOGS_PANEL_ITEM: ofType<{ logType: string, log: string }>(), +}); + +export type ProcessLogsPanelAction = UnionOf; + +export const initProcessLogsPanel = (processUuid: string) => + async (dispatch: Dispatch, getState: () => RootState, { logService }: ServiceRepository) => { + const process = await dispatch(loadProcess(processUuid)); + if (process.container) { + const logResources = await loadContainerLogs(process.container.uuid, logService); + const initialState = createInitialLogPanelState(logResources); + dispatch(processLogsPanelActions.INIT_PROCESS_LOGS_PANEL(initialState)); + } + }; + +const loadContainerLogs = async (containerUuid: string, logService: LogService) => { + const requestFilters = new FilterBuilder() + .addEqual('objectUuid', containerUuid) + .addIn('eventType', PROCESS_PANEL_LOG_EVENT_TYPES) + .getFilters(); + const requestOrder = new OrderBuilder() + .addAsc('eventAt') + .getOrder(); + const requestParams = { + limit: 10000, + filters: requestFilters, + order: requestOrder, + }; + const { items } = await logService.list(requestParams); + return items; +}; + +const createInitialLogPanelState = (logResources: LogResource[]) => { + const allLogs = logResources.map(({ properties }) => properties.text); + const groupedLogResources = groupBy(logResources, log => log.eventType); + const groupedLogs = Object + .keys(groupedLogResources) + .reduce((grouped, key) => ({ + ...grouped, + [key]: groupedLogResources[key].map(({ properties }) => properties.text) + }), {}); + const filters = [SUMMARIZED_FILTER_TYPE, ...Object.keys(groupedLogs)]; + const logs = { [SUMMARIZED_FILTER_TYPE]: allLogs, ...groupedLogs }; + return { filters, logs }; +}; + + +const SUMMARIZED_FILTER_TYPE = 'Summarized'; + +const PROCESS_PANEL_LOG_EVENT_TYPES = [ + LogEventType.ARV_MOUNT, + LogEventType.CRUNCH_RUN, + LogEventType.CRUNCHSTAT, + LogEventType.DISPATCH, + LogEventType.HOSTSTAT, + LogEventType.NODE_INFO, + LogEventType.STDERR, + LogEventType.STDOUT, +]; diff --git a/src/store/process-logs-panel/process-logs-panel-reducer.ts b/src/store/process-logs-panel/process-logs-panel-reducer.ts new file mode 100644 index 00000000..39a448b0 --- /dev/null +++ b/src/store/process-logs-panel/process-logs-panel-reducer.ts @@ -0,0 +1,32 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import { ProcessLogsPanel } from './process-logs-panel'; +import { RootState } from '~/store/store'; +import { ProcessLogsPanelAction, processLogsPanelActions } from './process-logs-panel-actions'; + +const initialState: ProcessLogsPanel = { + filters: [], + selectedFilter: '', + logs: { '': [] }, +}; + +export const processLogsPanelReducer = (state = initialState, action: ProcessLogsPanelAction): ProcessLogsPanel => + processLogsPanelActions.match(action, { + INIT_PROCESS_LOGS_PANEL: ({ filters, logs }) => ({ + filters, + logs, + selectedFilter: filters[0] || '', + }), + SET_PROCESS_LOGS_PANEL_FILTER: selectedFilter => ({ + ...state, + selectedFilter + }), + ADD_PROCESS_LOGS_PANEL_ITEM: ({ logType, log }) => { + const logsOfType = [...state.logs[logType], log]; + const logs = { ...state.logs, [logType]: logsOfType }; + return { ...state, logs }; + }, + default: () => state, + }); diff --git a/src/store/process-logs-panel/process-logs-panel.ts b/src/store/process-logs-panel/process-logs-panel.ts new file mode 100644 index 00000000..9575c4e5 --- /dev/null +++ b/src/store/process-logs-panel/process-logs-panel.ts @@ -0,0 +1,18 @@ +import { LogEventType } from '../../models/log'; +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +export interface ProcessLogsPanel { + filters: string[]; + selectedFilter: string; + logs: ProcessLogs; +} + +export interface ProcessLogs { + [logType: string]: string[]; +} + +export const getProcessLogs = ({ selectedFilter, logs }: ProcessLogsPanel) => { + return logs[selectedFilter]; +}; diff --git a/src/store/processes/processes-actions.ts b/src/store/processes/processes-actions.ts index be9266b6..d94cc01e 100644 --- a/src/store/processes/processes-actions.ts +++ b/src/store/processes/processes-actions.ts @@ -8,16 +8,19 @@ import { ServiceRepository } from '~/services/services'; import { updateResources } from '~/store/resources/resources-actions'; import { FilterBuilder } from '~/common/api/filter-builder'; import { ContainerRequestResource } from '../../models/container-request'; +import { Process } from './process'; export const loadProcess = (containerRequestUuid: string) => - async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { + async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository): Promise => { const containerRequest = await services.containerRequestService.get(containerRequestUuid); dispatch(updateResources([containerRequest])); if (containerRequest.containerUuid) { const container = await services.containerService.get(containerRequest.containerUuid); dispatch(updateResources([container])); await dispatch(loadSubprocesses(containerRequest.containerUuid)); + return { containerRequest, container }; } + return { containerRequest }; }; export const loadSubprocesses = (containerUuid: string) => diff --git a/src/store/store.ts b/src/store/store.ts index 4fe0f97a..d0c0dd67 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -28,6 +28,7 @@ import { resourcesReducer } from '~/store/resources/resources-reducer'; import { propertiesReducer } from './properties/properties-reducer'; import { RootState } from './store'; import { fileUploaderReducer } from './file-uploader/file-uploader-reducer'; +import { processLogsPanelReducer } from './process-logs-panel/process-logs-panel-reducer'; const composeEnhancers = (process.env.NODE_ENV === 'development' && @@ -68,6 +69,7 @@ const createRootReducer = (services: ServiceRepository) => combineReducers({ dialog: dialogReducer, favorites: favoritesReducer, form: formReducer, + processLogsPanel: processLogsPanelReducer, properties: propertiesReducer, resources: resourcesReducer, router: routerReducer,