Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filter out verbose events in the Console #4150

Merged
merged 11 commits into from
May 12, 2021
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ For details about compatibility between different releases, see the **Commitment
- RPC to find related events by correlation ID.
- CLI command `events find-related`.
- Support for loading Device Repository profiles from different vendors if specified. This allows reusing standard end device profiles from module makers and LoRaWAN end device stack vendors.
- Filtering out verbose events in the event views in the Console.

### Changed

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
"prop-types": "^15.7.2",
"query-string": "^6.14.0",
"react": "^17.0.1",
"react-ace": "^9.3.0",
"react-ace": "^6.6.0",
"react-display-name": "^0.2.5",
"react-dom": "^17.0.1",
"react-grid-system": "^7.1.1",
Expand Down
6 changes: 6 additions & 0 deletions pkg/webui/console/components/events/events.styl
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ $event-container-height = 40px

.actions
background-color: white
display: flex

.verbose-checkbox
margin-top: 0
color: $tc-subtle-gray
margin-right: $cs.s

.widget-container
border-normal()
Expand Down
34 changes: 33 additions & 1 deletion pkg/webui/console/components/events/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ import React, { useState, useCallback } from 'react'
import classnames from 'classnames'

import EVENT_STORE_LIMIT from '@console/constants/event-store-limit'
import { EVENT_VERBOSE_FILTERS_REGEXP } from '@console/constants/event-filters'
import hamburgerMenuClose from '@assets/misc/hamburger-menu-close.svg'

import Button from '@ttn-lw/components/button'
import Checkbox from '@ttn-lw/components/checkbox'
import Icon from '@ttn-lw/components/icon'

import Message from '@ttn-lw/lib/components/message'
Expand All @@ -35,7 +37,18 @@ import { getEventId } from './utils'
import style from './events.styl'

const Events = React.memo(
({ events, scoped, paused, onClear, onPauseToggle, entityId, truncated }) => {
({
events,
scoped,
paused,
onClear,
onPauseToggle,
onFilterChange,
entityId,
truncated,
filter,
disableFiltering,
}) => {
const [focus, setFocus] = useState({ eventId: undefined, visible: false })
const onPause = useCallback(() => onPauseToggle(paused), [onPauseToggle, paused])
const handleRowClick = useCallback(
Expand All @@ -49,6 +62,10 @@ const Events = React.memo(
[focus],
)

const handleVerboseFilterChange = useCallback(() => {
onFilterChange(Boolean(filter) ? undefined : EVENT_VERBOSE_FILTERS_REGEXP)
}, [onFilterChange, filter])

const handleEventInfoCloseClick = useCallback(() => {
setFocus({ eventId: undefined, visible: false })
}, [])
Expand All @@ -65,6 +82,15 @@ const Events = React.memo(
<Message content={m.dataPreview} className={style.cellData} component="div" />
<div className={style.stickyContainer}>
<div className={style.actions}>
{!disableFiltering && (
<Checkbox
className={style.verboseCheckbox}
onChange={handleVerboseFilterChange}
label={m.verboseStream}
value={!Boolean(filter)}
name="verbose-stream"
/>
)}
<Button
onClick={onPause}
message={paused ? sharedMessages.resume : sharedMessages.pause}
Expand Down Expand Up @@ -125,19 +151,25 @@ const Events = React.memo(
)

Events.propTypes = {
disableFiltering: PropTypes.bool,
entityId: PropTypes.string.isRequired,
events: PropTypes.events.isRequired,
filter: PropTypes.string,
onClear: PropTypes.func,
onFilterChange: PropTypes.func,
onPauseToggle: PropTypes.func,
paused: PropTypes.bool.isRequired,
scoped: PropTypes.bool,
truncated: PropTypes.bool.isRequired,
}

Events.defaultProps = {
disableFiltering: false,
filter: undefined,
scoped: false,
onClear: () => null,
onPauseToggle: () => null,
onFilterChange: () => null,
}

Events.Widget = Widget
Expand Down
1 change: 1 addition & 0 deletions pkg/webui/console/components/events/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const messages = defineMessages({
eventsTruncated:
'Old events have been truncated to save memory. The current event limit per stream is {limit}.',
eventUnavailable: 'This event is not available anymore. It was likely truncated to save memory.',
verboseStream: 'Verbose stream',
})

export default messages
49 changes: 49 additions & 0 deletions pkg/webui/console/constants/event-filters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright © 2021 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

export const EVENT_VERBOSE_FILTERS = [
'as.*.drop',
'as.down.data.forward',
'as.up.data.forward',
'gs.down.send',
'gs.gateway.connect',
'gs.gateway.disconnect',
'gs.status.receive',
'gs.up.receive',
'js.join.accept',
'js.join.reject',
'ns.mac.*.answer.reject',
'*.warning',
'*.fail',
'organization.*',
'user.*',
'gateway.*',
'application.*',
'end_device.*',
'client.*',
'oauth.*',
]

// A RegExp converted from the glob list of filtered event names.
export const EVENT_VERBOSE_FILTERS_REGEXP = EVENT_VERBOSE_FILTERS.reduce(
(acc, cur, i) => `${acc}${i !== 0 ? '|' : ''}${cur.replace('.', '\\.').replace('*', '.*')}`,
'',
)

// A map that allows to translate back the filter list from the converted
// RegExp string. Useful to show a human readable filter list in the event
// stream, which only uses the RegExp string internally.
export const EVENT_FILTER_MAP = Object.freeze({
[EVENT_VERBOSE_FILTERS_REGEXP]: EVENT_VERBOSE_FILTERS,
})
21 changes: 20 additions & 1 deletion pkg/webui/console/containers/application-events/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,28 @@ import {
clearApplicationEventsStream,
pauseApplicationEventsStream,
resumeApplicationEventsStream,
setApplicationEventsFilter,
} from '@console/store/actions/applications'

import {
selectApplicationEvents,
selectApplicationEventsPaused,
selectApplicationEventsTruncated,
selectApplicationEventsFilter,
} from '@console/store/selectors/applications'

const ApplicationEvents = props => {
const { appId, events, widget, paused, onClear, onPauseToggle, truncated } = props
const {
appId,
events,
widget,
paused,
onClear,
onPauseToggle,
truncated,
onFilterChange,
filter,
} = props

if (widget) {
return (
Expand All @@ -51,15 +63,19 @@ const ApplicationEvents = props => {
paused={paused}
onClear={onClear}
truncated={truncated}
filter={filter}
onPauseToggle={onPauseToggle}
onFilterChange={onFilterChange}
/>
)
}

ApplicationEvents.propTypes = {
appId: PropTypes.string.isRequired,
events: PropTypes.events,
filter: PropTypes.string,
onClear: PropTypes.func.isRequired,
onFilterChange: PropTypes.func.isRequired,
onPauseToggle: PropTypes.func.isRequired,
paused: PropTypes.bool.isRequired,
truncated: PropTypes.bool.isRequired,
Expand All @@ -69,6 +85,7 @@ ApplicationEvents.propTypes = {
ApplicationEvents.defaultProps = {
widget: false,
events: [],
filter: undefined,
}

export default withFeatureRequirement(mayViewApplicationEvents)(
Expand All @@ -80,6 +97,7 @@ export default withFeatureRequirement(mayViewApplicationEvents)(
events: selectApplicationEvents(state, appId),
paused: selectApplicationEventsPaused(state, appId),
truncated: selectApplicationEventsTruncated(state, appId),
filter: selectApplicationEventsFilter(state, appId),
}
},
(dispatch, ownProps) => ({
Expand All @@ -88,6 +106,7 @@ export default withFeatureRequirement(mayViewApplicationEvents)(
paused
? dispatch(resumeApplicationEventsStream(ownProps.appId))
: dispatch(pauseApplicationEventsStream(ownProps.appId)),
onFilterChange: filter => dispatch(setApplicationEventsFilter(ownProps.appId, filter)),
}),
)(ApplicationEvents),
)
22 changes: 21 additions & 1 deletion pkg/webui/console/containers/device-events/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,29 @@ import {
clearDeviceEventsStream,
pauseDeviceEventsStream,
resumeDeviceEventsStream,
setDeviceEventsFilter,
} from '@console/store/actions/devices'

import {
selectDeviceEvents,
selectDeviceEventsPaused,
selectDeviceEventsTruncated,
selectDeviceEventsFilter,
} from '@console/store/selectors/devices'

const DeviceEvents = props => {
const { appId, devId, events, widget, paused, onClear, onPauseToggle, truncated } = props
const {
appId,
devId,
events,
widget,
paused,
onClear,
onPauseToggle,
onFilterChange,
truncated,
filter,
} = props

if (widget) {
return (
Expand All @@ -51,8 +64,10 @@ const DeviceEvents = props => {
events={events}
entityId={devId}
paused={paused}
filter={filter}
onClear={onClear}
onPauseToggle={onPauseToggle}
onFilterChange={onFilterChange}
truncated={truncated}
scoped
widget
Expand All @@ -70,7 +85,9 @@ DeviceEvents.propTypes = {
}),
}).isRequired,
events: PropTypes.events,
filter: PropTypes.string,
onClear: PropTypes.func.isRequired,
onFilterChange: PropTypes.func.isRequired,
onPauseToggle: PropTypes.func.isRequired,
paused: PropTypes.bool.isRequired,
truncated: PropTypes.bool.isRequired,
Expand All @@ -80,6 +97,7 @@ DeviceEvents.propTypes = {
DeviceEvents.defaultProps = {
widget: false,
events: [],
filter: undefined,
}

export default connect(
Expand All @@ -96,6 +114,7 @@ export default connect(
events: selectDeviceEvents(state, combinedId),
paused: selectDeviceEventsPaused(state, combinedId),
truncated: selectDeviceEventsTruncated(state, combinedId),
filter: selectDeviceEventsFilter(state, combinedId),
}
},
(dispatch, ownProps) => {
Expand All @@ -107,6 +126,7 @@ export default connect(
paused
? dispatch(resumeDeviceEventsStream(devIds))
: dispatch(pauseDeviceEventsStream(devIds)),
onFilterChange: filter => dispatch(setDeviceEventsFilter(devIds, filter)),
}
},
)(DeviceEvents)
21 changes: 20 additions & 1 deletion pkg/webui/console/containers/gateway-events/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,28 @@ import {
clearGatewayEventsStream,
pauseGatewayEventsStream,
resumeGatewayEventsStream,
setGatewayEventsFilter,
} from '@console/store/actions/gateways'

import {
selectGatewayEvents,
selectGatewayEventsPaused,
selectGatewayEventsTruncated,
selectGatewayEventsFilter,
} from '@console/store/selectors/gateways'

const GatewayEvents = props => {
const { gtwId, events, widget, paused, onPauseToggle, onClear, truncated } = props
const {
gtwId,
events,
widget,
paused,
onPauseToggle,
onClear,
onFilterChange,
truncated,
filter,
} = props

if (widget) {
return (
Expand All @@ -51,16 +63,20 @@ const GatewayEvents = props => {
paused={paused}
onClear={onClear}
onPauseToggle={onPauseToggle}
onFilterChange={onFilterChange}
truncated={truncated}
filter={filter}
scoped
/>
)
}

GatewayEvents.propTypes = {
events: PropTypes.events,
filter: PropTypes.string,
gtwId: PropTypes.string.isRequired,
onClear: PropTypes.func.isRequired,
onFilterChange: PropTypes.func.isRequired,
onPauseToggle: PropTypes.func.isRequired,
paused: PropTypes.bool.isRequired,
truncated: PropTypes.bool.isRequired,
Expand All @@ -70,6 +86,7 @@ GatewayEvents.propTypes = {
GatewayEvents.defaultProps = {
widget: false,
events: [],
filter: undefined,
}

export default withFeatureRequirement(mayViewGatewayEvents)(
Expand All @@ -81,6 +98,7 @@ export default withFeatureRequirement(mayViewGatewayEvents)(
events: selectGatewayEvents(state, gtwId),
paused: selectGatewayEventsPaused(state, gtwId),
truncated: selectGatewayEventsTruncated(state, gtwId),
filter: selectGatewayEventsFilter(state, gtwId),
}
},
(dispatch, ownProps) => ({
Expand All @@ -89,6 +107,7 @@ export default withFeatureRequirement(mayViewGatewayEvents)(
paused
? dispatch(resumeGatewayEventsStream(ownProps.gtwId))
: dispatch(pauseGatewayEventsStream(ownProps.gtwId)),
onFilterChange: filter => dispatch(setGatewayEventsFilter(ownProps.gtwId, filter)),
}),
)(GatewayEvents),
)
Loading