Skip to content

Commit 966ce80

Browse files
committed
#RI-2640 - base implementation for Profiler logs
1 parent 0ea1063 commit 966ce80

File tree

14 files changed

+358
-79
lines changed

14 files changed

+358
-79
lines changed

redisinsight/ui/src/components/monitor-config/MonitorConfig.tsx

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import { io } from 'socket.io-client'
66
import {
77
setSocket,
88
monitorSelector,
9-
toggleRunMonitor,
109
concatMonitorItems,
1110
stopMonitor,
1211
setError,
13-
resetMonitorItems
12+
resetMonitorItems,
13+
setStartTimestamp
1414
} from 'uiSrc/slices/cli/monitor'
1515
import { getBaseApiUrl } from 'uiSrc/utils'
1616
import { MonitorErrorMessages, MonitorEvent, SocketErrors, SocketEvent } from 'uiSrc/constants'
@@ -25,7 +25,7 @@ interface IProps {
2525
}
2626
const MonitorConfig = ({ retryDelay = 10000 } : IProps) => {
2727
const { id: instanceId = '' } = useSelector(connectedInstanceSelector)
28-
const { socket, isRunning, isMinimizedMonitor, isShowMonitor } = useSelector(monitorSelector)
28+
const { socket, isRunning, isPaused, isSaveToFile, isMinimizedMonitor, isShowMonitor } = useSelector(monitorSelector)
2929

3030
const dispatch = useDispatch()
3131

@@ -79,7 +79,13 @@ const MonitorConfig = ({ retryDelay = 10000 } : IProps) => {
7979
newSocket.on(SocketEvent.Connect, () => {
8080
// Trigger Monitor event
8181
clearTimeout(retryTimer)
82-
newSocket.emit(MonitorEvent.Monitor, handleMonitorEvents)
82+
const timestampStart = Date.now()
83+
dispatch(setStartTimestamp(timestampStart))
84+
newSocket.emit(
85+
MonitorEvent.Monitor,
86+
{ logFileId: isSaveToFile ? timestampStart.toString() : null },
87+
handleMonitorEvents
88+
)
8389
})
8490

8591
// Catch exceptions
@@ -93,7 +99,7 @@ const MonitorConfig = ({ retryDelay = 10000 } : IProps) => {
9399

94100
payloads.push({ isError: true, time: `${Date.now()}`, ...payload })
95101
setNewItems(payloads, () => { payloads.length = 0 })
96-
dispatch(toggleRunMonitor())
102+
dispatch(stopMonitor())
97103
})
98104

99105
// Catch disconnect
@@ -109,12 +115,19 @@ const MonitorConfig = ({ retryDelay = 10000 } : IProps) => {
109115
newSocket.on(SocketEvent.ConnectionError, (error) => {
110116
payloads.push({ isError: true, time: `${Date.now()}`, message: getErrorMessage(error) })
111117
setNewItems(payloads, () => { payloads.length = 0 })
112-
dispatch(toggleRunMonitor())
118+
dispatch(stopMonitor())
113119
})
114-
}, [instanceId, isRunning])
120+
}, [instanceId, isRunning, isSaveToFile])
121+
122+
useEffect(() => {
123+
if (!isRunning) return
124+
!isPaused && socket?.emit(MonitorEvent.Monitor)
125+
isPaused && socket?.emit(MonitorEvent.Pause)
126+
}, [isPaused, isRunning])
115127

116128
useEffect(() => {
117129
if (!isRunning) {
130+
socket?.emit(MonitorEvent.FlushLogs)
118131
socket?.removeAllListeners()
119132
socket?.disconnect()
120133
}

redisinsight/ui/src/components/monitor/Monitor/Monitor.tsx

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
1-
import React from 'react'
1+
import React, { useState } from 'react'
22
import cx from 'classnames'
33
import {
44
EuiButtonIcon,
55
EuiFlexGroup,
66
EuiFlexItem,
77
EuiIcon,
8+
EuiSwitch,
89
EuiTextColor,
910
EuiToolTip,
1011
} from '@elastic/eui'
11-
import { AutoSizer } from 'react-virtualized'
12+
import AutoSizer from 'react-virtualized-auto-sizer'
1213

1314
import { IMonitorDataPayload } from 'uiSrc/slices/interfaces'
1415
import { ReactComponent as BanIcon } from 'uiSrc/assets/img/monitor/ban.svg'
1516

17+
import MonitorLog from '../MonitorLog/MonitorLog'
1618
import MonitorOutputList from '../MonitorOutputList'
1719

1820
import styles from './styles.module.scss'
@@ -22,10 +24,12 @@ export interface Props {
2224
error: string
2325
isStarted: boolean
2426
isRunning: boolean
27+
isPaused: boolean
2528
isShowHelper: boolean
29+
isSaveToFile: boolean
2630
isShowCli: boolean
2731
scrollViewOnAppear: boolean
28-
handleRunMonitor: () => void
32+
handleRunMonitor: (isSaveToLog?: boolean) => void
2933
}
3034

3135
const Monitor = (props: Props) => {
@@ -34,10 +38,13 @@ const Monitor = (props: Props) => {
3438
error = '',
3539
isRunning = false,
3640
isStarted = false,
41+
isPaused = false,
3742
isShowHelper = false,
3843
isShowCli = false,
44+
isSaveToFile = false,
3945
handleRunMonitor = () => {}
4046
} = props
47+
const [saveLogValue, setSaveLogValue] = useState(isSaveToFile)
4148

4249
const MonitorNotStarted = () => (
4350
<div className={styles.startContainer} data-testid="monitor-not-started">
@@ -47,16 +54,16 @@ const Monitor = (props: Props) => {
4754
display="inlineBlock"
4855
>
4956
<EuiButtonIcon
50-
iconType="play"
57+
iconType="playFilled"
5158
className={styles.startTitleIcon}
5259
size="m"
53-
onClick={handleRunMonitor}
60+
onClick={() => handleRunMonitor(saveLogValue)}
5461
aria-label="start monitor"
5562
data-testid="start-monitor"
5663
/>
5764
</EuiToolTip>
5865
<div className={styles.startTitle}>Start Profiler</div>
59-
<EuiFlexGroup responsive={false}>
66+
<EuiFlexGroup responsive={false} style={{ flexGrow: 0 }} gutterSize="none">
6067
<EuiFlexItem grow={false}>
6168
<EuiIcon
6269
className={cx(styles.iconWarning, 'warning--light')}
@@ -67,20 +74,36 @@ const Monitor = (props: Props) => {
6774
style={{ paddingTop: 2 }}
6875
/>
6976
</EuiFlexItem>
70-
<EuiFlexItem>
77+
<EuiFlexItem grow={false}>
7178
<EuiTextColor color="warning" className="warning--light" style={{ paddingLeft: 4 }} data-testid="monitor-warning-message">
7279
Running Profiler will decrease throughput, avoid running it in production databases
7380
</EuiTextColor>
7481
</EuiFlexItem>
7582
</EuiFlexGroup>
7683
</div>
84+
<div className={styles.saveLogContainer}>
85+
<EuiToolTip
86+
title="Allows you to download the generated log file after pausing the Profiler."
87+
content="Profiler log is saved to a file on your local machine with no size limitation.
88+
The temporary log file will be automatically rewritten when the Profiler is reset"
89+
>
90+
<>
91+
<EuiSwitch
92+
compressed
93+
label={<span>Save Log</span>}
94+
checked={saveLogValue}
95+
onChange={(e) => setSaveLogValue(e.target.checked)}
96+
/>
97+
</>
98+
</EuiToolTip>
99+
</div>
77100
</div>
78101
)
79102

80103
const MonitorError = () => (
81104
<div className={styles.startContainer} data-testid="monitor-error">
82105
<div className={cx(styles.startContent, styles.startContentError)}>
83-
<EuiFlexGroup responsive={false}>
106+
<EuiFlexGroup responsive={false} gutterSize="none">
84107
<EuiFlexItem grow={false}>
85108
<EuiIcon
86109
type={BanIcon}
@@ -99,42 +122,45 @@ const Monitor = (props: Props) => {
99122
</div>
100123
)
101124

102-
const isMonitorStopped = !!items?.length && !isRunning
103-
104125
return (
105126
<>
106127
<div className={styles.container} data-testid="monitor">
107128
{(error && !isRunning)
108129
? (<MonitorError />)
109130
: (
110131
<>
111-
{(!isStarted || (!isRunning && !items?.length)) && <MonitorNotStarted />}
112-
{!items?.length && isRunning && (
113-
<div data-testid="monitor-started" style={{ paddingTop: 10 }}>Profiler is started.</div>
132+
{!isStarted && <MonitorNotStarted />}
133+
{!items?.length && isRunning && !isPaused && (
134+
<div data-testid="monitor-started" style={{ paddingTop: 10, paddingLeft: 12 }}>
135+
Profiler is started.
136+
</div>
114137
)}
115138
</>
116139
)}
117-
{isStarted && !!items?.length && (
140+
{isStarted && (
118141
<div className={styles.content}>
119-
<AutoSizer>
120-
{({ width, height }) => (
121-
<>
142+
{!!items?.length && (
143+
<AutoSizer>
144+
{({ width, height }) => (
122145
<MonitorOutputList
123146
width={width}
124-
height={isMonitorStopped ? height - 30 : height}
147+
height={height}
125148
items={items}
126149
compressed={isShowCli || isShowHelper}
127150
/>
128-
{isMonitorStopped && (
129-
<div data-testid="monitor-stopped" style={{ width: 140, paddingTop: 15 }}>
130-
Profiler is stopped.
131-
</div>
132-
)}
133-
</>
134-
)}
135-
</AutoSizer>
151+
)}
152+
</AutoSizer>
153+
)}
136154
</div>
137155
)}
156+
{isStarted && isPaused && !isSaveToFile && (
157+
<div data-testid="monitor-stopped" className={styles.monitorStoppedText}>
158+
Profiler is paused.
159+
</div>
160+
)}
161+
{(isStarted && isPaused && isSaveToFile) && (
162+
<MonitorLog />
163+
)}
138164
</div>
139165
</>
140166
)

redisinsight/ui/src/components/monitor/Monitor/styles.module.scss

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
height: calc(100% - 34px);
88
position: relative;
99
width: 100%;
10-
padding-left: 12px;
10+
11+
display: flex;
12+
flex-direction: column;
1113

1214
background-color: var(--browserTableRowEven);
1315
text-align: left;
@@ -20,21 +22,17 @@
2022

2123
z-index: 10;
2224
overflow: auto;
23-
24-
:global {
25-
.euiFlexGroup, .euiFlexItem {
26-
margin: 0px !important;
27-
}
28-
}
2925
}
3026

3127
.listWrapper {
3228
@include euiScrollBar;
29+
flex: 1;
3330

3431
width: 100%;
3532
height: 100%;
3633
position: relative;
3734
overflow: auto;
35+
padding-left: 12px;
3836
}
3937

4038
.content {
@@ -45,6 +43,10 @@
4543
position: relative;
4644
overflow: auto;
4745

46+
display: flex;
47+
flex-direction: column;
48+
margin-bottom: 6px;
49+
4850
&:first-child {
4951
padding-top: 10px;
5052
}
@@ -61,17 +63,34 @@
6163
justify-content: center;
6264

6365
height: 100%;
66+
padding-left: 12px;
6467
}
6568

6669
.startContent {
6770
display: flex;
6871
align-items: center;
72+
justify-content: center;
73+
flex-grow: 1;
6974
max-width: 264px;
7075
flex-direction: column;
7176

7277
font: normal normal normal 12px/18px Graphik, sans-serif;
7378
}
7479

80+
.monitorStoppedText {
81+
padding-left: 12px;
82+
padding-bottom: 4px;
83+
}
84+
85+
.saveLogContainer {
86+
font: normal normal normal 13px/18px Graphik;
87+
letter-spacing: -0.13px;
88+
margin-bottom: 18px;
89+
:global(.euiSwitch__label) {
90+
padding-left: 0 !important;
91+
}
92+
}
93+
7594
.startContentError {
7695
max-width: 298px;
7796
padding-right: 12px;

redisinsight/ui/src/components/monitor/MonitorHeader/MonitorHeader.tsx

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export interface Props {
2929

3030
const MonitorHeader = ({ handleRunMonitor }: Props) => {
3131
const { instanceId = '' } = useParams<{ instanceId: string }>()
32-
const { isRunning, isStarted, items, error } = useSelector(monitorSelector)
32+
const { isRunning, isPaused, isStarted, items, error } = useSelector(monitorSelector)
3333
const isErrorShown = !!error && !isRunning
3434
const dispatch = useDispatch()
3535

@@ -44,7 +44,6 @@ const MonitorHeader = ({ handleRunMonitor }: Props) => {
4444
event: TelemetryEvent.PROFILER_CLOSED,
4545
eventData: { databaseId: instanceId }
4646
})
47-
4847
dispatch(setMonitorInitialState())
4948
}
5049

@@ -79,31 +78,33 @@ const MonitorHeader = ({ handleRunMonitor }: Props) => {
7978
<EuiIcon type="inspect" size="m" />
8079
<EuiText>Profiler</EuiText>
8180
</EuiFlexItem>
82-
<EuiFlexItem grow={false} className={styles.actions}>
83-
<EuiToolTip
84-
content={isErrorShown ? '' : (isRunning ? 'Stop' : 'Start')}
85-
anchorClassName="inline-flex"
86-
>
87-
<EuiButtonIcon
88-
iconType={isErrorShown ? BanIcon : (isRunning ? 'pause' : 'play')}
89-
onClick={handleRunMonitor}
90-
aria-label="start/stop monitor"
91-
data-testid="toggle-run-monitor"
92-
disabled={isErrorShown}
93-
/>
94-
</EuiToolTip>
95-
<EuiToolTip
96-
content={!isStarted || !items.length ? '' : 'Clear'}
97-
anchorClassName={cx('inline-flex', { transparent: !isStarted || !items.length })}
98-
>
99-
<EuiButtonIcon
100-
iconType="eraser"
101-
onClick={handleClearMonitor}
102-
aria-label="clear profiler"
103-
data-testid="clear-monitor"
104-
/>
105-
</EuiToolTip>
106-
</EuiFlexItem>
81+
{isStarted && (
82+
<EuiFlexItem grow={false} className={styles.actions}>
83+
<EuiToolTip
84+
content={isErrorShown ? '' : (!isPaused ? 'Pause' : 'Resume')}
85+
anchorClassName="inline-flex"
86+
>
87+
<EuiButtonIcon
88+
iconType={isErrorShown ? BanIcon : (!isPaused ? 'pause' : 'play')}
89+
onClick={() => handleRunMonitor()}
90+
aria-label="start/stop monitor"
91+
data-testid="toggle-run-monitor"
92+
disabled={isErrorShown}
93+
/>
94+
</EuiToolTip>
95+
<EuiToolTip
96+
content={!isStarted || !items.length ? '' : 'Clear Profiler window'}
97+
anchorClassName={cx('inline-flex', { transparent: !isStarted || !items.length })}
98+
>
99+
<EuiButtonIcon
100+
iconType="eraser"
101+
onClick={handleClearMonitor}
102+
aria-label="clear profiler"
103+
data-testid="clear-monitor"
104+
/>
105+
</EuiToolTip>
106+
</EuiFlexItem>
107+
)}
107108
<EuiFlexItem grow />
108109
<EuiFlexItem grow={false}>
109110
<EuiToolTip

0 commit comments

Comments
 (0)