Skip to content

Commit

Permalink
Merge pull request elastic#9 from Elastic-AWP-Platform/alerted_processes
Browse files Browse the repository at this point in the history
Session view now loads process events by process.entry.entity_id
  • Loading branch information
mitodrummer authored Nov 15, 2021
2 parents 1556340 + 5ca9c80 commit 43edfbe
Show file tree
Hide file tree
Showing 12 changed files with 388 additions and 281 deletions.
4 changes: 4 additions & 0 deletions x-pack/plugins/session_view/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,9 @@ export const BASE_PATH = '/app/sessionView';
// Internal APIs are recommended to have the INTERNAL- suffix
export const INTERNAL_TEST_ROUTE = '/internal/session_view/test_route';
export const INTERNAL_TEST_SAVED_OBJECT_ROUTE = '/internal/session_view/test_saved_object_route';
export const PROCESS_EVENTS_ROUTE = '/internal/session_view/process_events_route';
export const RECENT_SESSION_ROUTE = '/internal/session_view/recent_session_route';

export const TEST_SAVED_OBJECT = 'session_view_test_saved_object';

export const PROCESS_EVENTS_PER_PAGE = 2000;
26 changes: 13 additions & 13 deletions x-pack/plugins/session_view/common/test/mock_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { Action, ProcessEvent } from '../../public/hooks/use_process_tree';
import { EventAction, ProcessEvent } from '../../public/hooks/use_process_tree';
import uuid from 'uuid';

export const getStart = () => {
Expand All @@ -14,7 +14,7 @@ export const getStart = () => {
event: {
kind: 'event',
category: 'process',
action: Action.exec,
action: EventAction.exec,
},
process: {
args: ['bash'],
Expand Down Expand Up @@ -111,7 +111,7 @@ export const getEvent = () => {
event: {
kind: 'event',
category: 'process',
action: Action.exec,
action: EventAction.exec,
},
process: {
args: randomElement.args,
Expand Down Expand Up @@ -187,7 +187,7 @@ export const getEnd = () => {
event: {
kind: 'event',
category: 'process',
action: Action.exec,
action: EventAction.exec,
},
process: {
args: ['df'],
Expand Down Expand Up @@ -259,7 +259,7 @@ export const getEnd = () => {
event: {
kind: 'event',
category: 'process',
action: Action.fork,
action: EventAction.fork,
},
process: {
args: ['df', 'nested'],
Expand Down Expand Up @@ -333,7 +333,7 @@ export const getEnd = () => {
event: {
kind: 'event',
category: 'process',
action: Action.exec,
action: EventAction.exec,
},
process: {
args: ['df', 'nested'],
Expand Down Expand Up @@ -407,7 +407,7 @@ export const getEnd = () => {
event: {
kind: 'event',
category: 'process',
action: Action.end,
action: EventAction.end,
},
process: {
args: ['df', 'nested'],
Expand Down Expand Up @@ -487,7 +487,7 @@ export const mockData: ProcessEvent[] = [
event: {
kind: 'event',
category: 'process',
action: Action.exec,
action: EventAction.exec,
},
process: {
args: ['bash'],
Expand Down Expand Up @@ -561,7 +561,7 @@ export const mockData: ProcessEvent[] = [
event: {
kind: 'event',
category: 'process',
action: Action.exec,
action: EventAction.exec,
},
process: {
args: ['ls', '-l'],
Expand Down Expand Up @@ -633,7 +633,7 @@ export const mockData: ProcessEvent[] = [
event: {
kind: 'event',
category: 'process',
action: Action.exec,
action: EventAction.exec,
},
process: {
args: ['df'],
Expand Down Expand Up @@ -705,7 +705,7 @@ export const mockData: ProcessEvent[] = [
event: {
kind: 'event',
category: 'process',
action: Action.fork,
action: EventAction.fork,
},
process: {
args: ['df', 'nested'],
Expand Down Expand Up @@ -779,7 +779,7 @@ export const mockData: ProcessEvent[] = [
event: {
kind: 'event',
category: 'process',
action: Action.exec,
action: EventAction.exec,
},
process: {
args: ['df', 'nested'],
Expand Down Expand Up @@ -853,7 +853,7 @@ export const mockData: ProcessEvent[] = [
event: {
kind: 'event',
category: 'process',
action: Action.end,
action: EventAction.end,
},
process: {
args: ['df', 'nested'],
Expand Down
44 changes: 32 additions & 12 deletions x-pack/plugins/session_view/public/components/ProcessTree/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import { useScroll } from '../../hooks/use_scroll';
import { useStyles } from './styles';

interface ProcessTreeDeps {
// process.entity_id to act as root node
sessionId: string;
// process.entity_id to act as root node (typically a session (or entry session) leader).
sessionEntityId: string;

// bi-directional paging support. allows us to load
// processes before and after a particular process.entity_id
Expand All @@ -29,7 +29,7 @@ interface ProcessTreeDeps {
}

export const ProcessTree = ({
sessionId,
sessionEntityId,
forward,
backward,
searchQuery,
Expand All @@ -39,7 +39,7 @@ export const ProcessTree = ({
const styles = useStyles();

const { sessionLeader, orphans, searchResults } = useProcessTree({
sessionId,
sessionEntityId,
forward,
backward,
searchQuery,
Expand Down Expand Up @@ -89,10 +89,25 @@ export const ProcessTree = ({
}

// find the DOM element for the command which is selected by id
const processEl = scrollerRef.current.querySelector(`[data-id="${process.getEntityID()}"]`);
const processEl = scrollerRef.current.querySelector<HTMLElement>(`[data-id="${process.id}"]`);

if (processEl) {
processEl.prepend(selectionAreaEl);

const container = processEl.parentElement;

if (container) {
const cTop = container.scrollTop;
const cBottom = cTop + container.clientHeight;

const eTop = processEl.offsetTop;
const eBottom = eTop + processEl.clientHeight;
const isVisible = eTop >= cTop && eBottom <= cBottom;

if (!isVisible) {
processEl.scrollIntoView();
}
}
}
}, []);

Expand All @@ -102,13 +117,8 @@ export const ProcessTree = ({
}
}, [selectedProcess, selectProcess]);

// TODO: processes without parents.
// haven't decided whether to just add to session leader
// or some other UX treatment (reparenting to init?)
// eslint-disable-next-line no-console
console.log(orphans);

// TODO: search input and results navigation
// TODO: bubble the results up to parent component session_view, and show results navigation
// navigating should
// eslint-disable-next-line no-console
console.log(searchResults);

Expand All @@ -121,6 +131,16 @@ export const ProcessTree = ({
onProcessSelected={onProcessSelected}
/>
)}
{orphans.map((process) => {
return (
<ProcessTreeNode
key={process.id}
isOrphan
process={process}
onProcessSelected={onProcessSelected}
/>
);
})}
<div ref={selectionAreaRef} css={styles.selectionArea} />
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { useState, useEffect, MouseEvent } from 'react';
import React, { useMemo, useRef, useLayoutEffect, useState, useEffect, MouseEvent } from 'react';
import { EuiButton, EuiIcon } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { Process } from '../../hooks/use_process_tree';
Expand All @@ -20,6 +20,7 @@ import { useStyles } from './styles';
interface ProcessDeps {
process: Process;
isSessionLeader?: boolean;
isOrphan?: boolean;
depth?: number;
onProcessSelected(process: Process): void;
}
Expand All @@ -31,24 +32,46 @@ interface ProcessDeps {
export function ProcessTreeNode({
process,
isSessionLeader = false,
isOrphan,
depth = 0,
onProcessSelected,
}: ProcessDeps) {
const styles = useStyles({ depth });
const textRef = useRef<HTMLSpanElement>(null);

const [childrenExpanded, setChildrenExpanded] = useState(isSessionLeader || process.autoExpand);
const { searchMatched } = process;

useEffect(() => {
setChildrenExpanded(isSessionLeader || process.autoExpand);
}, [isSessionLeader, process.autoExpand]);

const event = process.getLatest();
useLayoutEffect(() => {
if (searchMatched !== null && textRef.current) {
const regex = new RegExp(searchMatched);

const text = textRef.current.innerText;
const html = text.replace(regex, (match) => {
return `<span style="${styles.searchHighlight}">${match}</span>`;
});

textRef.current.innerHTML = html;
}
}, [searchMatched]);

if (!event) {
const processDetails = useMemo(() => {
return process.getDetails();
}, [process.events.length]);

const hasExec = useMemo(() => {
return process.hasExec();
}, [process.events.length]);

if (!processDetails) {
return null;
}

const { interactive } = event.process;
const { interactive } = processDetails.process;

const renderChildren = () => {
const { children } = process;
Expand All @@ -64,7 +87,7 @@ export function ProcessTreeNode({
{children.map((child: Process) => {
return (
<ProcessTreeNode
key={child.getEntityID()}
key={child.id}
process={child}
depth={newDepth}
onProcessSelected={onProcessSelected}
Expand Down Expand Up @@ -93,12 +116,12 @@ export function ProcessTreeNode({
};

const renderSessionLeader = () => {
const { name, user } = process.getLatest().process;
const { name, executable, user } = process.getDetails().process;
const sessionIcon = interactive ? 'consoleApp' : 'compute';

return (
<>
<EuiIcon type={sessionIcon} /> <b css={styles.darkText}>{name}</b>
<EuiIcon type={sessionIcon} /> <b css={styles.darkText}>{name || executable}</b>
&nbsp;
<FormattedMessage id="kbn.sessionView.startedBy" defaultMessage="started by" />
&nbsp;
Expand All @@ -111,44 +134,34 @@ export function ProcessTreeNode({
const template = () => {
const {
args,
executable,
working_directory: workingDirectory,
exit_code: exitCode,
} = process.getLatest().process;
const { searchMatched } = process;

if (searchMatched !== null) {
const regex = new RegExp(searchMatched);

// TODO: should we allow some form of customization via settings?
let text = `${workingDirectory} ${args.join(' ')}`;

text = text.replace(regex, (match) => {
return `<span style="${styles.searchHighlight}">${match}</span>`;
});

} = process.getDetails().process;
if (hasExec) {
return (
<>
{/* eslint-disable-next-line react/no-danger */}
<span dangerouslySetInnerHTML={{ __html: text }} />
</>
<span ref={textRef}>
<span css={styles.workingDir}>{workingDirectory}</span>&nbsp;
<span css={styles.darkText}>{args[0]}</span>&nbsp;
{args.slice(1).join(' ')}
{exitCode && <small> [exit_code: {exitCode}]</small>}
</span>
);
} else {
return (
<span ref={textRef}>
<span css={styles.darkText}>{executable}</span>&nbsp;
</span>
);
}

return (
<span>
<span css={styles.workingDir}>{workingDirectory}</span>&nbsp;
<span css={styles.darkText}>{args[0]}</span>&nbsp;
{args.slice(1).join(' ')}
{exitCode && <small> [exit_code: {exitCode}]</small>}
</span>
);
};

const renderProcess = () => {
return (
<span>
{process.isUserEntered() && <EuiIcon css={styles.userEnteredIcon} type="user" />}
<EuiIcon type="console" /> {template()}
<EuiIcon type={hasExec ? 'console' : 'branch'} /> {template()}
{isOrphan ? '(orphaned)' : ''}
</span>
);
};
Expand All @@ -166,14 +179,11 @@ export function ProcessTreeNode({
onProcessSelected(process);
};

const id = process.getEntityID();

// eslint-disable-next-line
console.log(styles);
const id = process.id;

return (
<>
<div data-id={id} key={id} css={styles.processNode}>
<div data-id={id} key={id + searchMatched} css={styles.processNode}>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
<div css={styles.wrapper} onClick={onProcessClicked}>
{isSessionLeader ? renderSessionLeader() : renderProcess()}
Expand Down
Loading

0 comments on commit 43edfbe

Please sign in to comment.