parent
d2c5b52bf1
commit
9fe1069df0
@ -19,6 +19,7 @@
|
|||||||
- [Jobs] Fix `job.runSequence` method (PR [#5944](https://github.com/vatesfr/xen-orchestra/pull/5944))
|
- [Jobs] Fix `job.runSequence` method (PR [#5944](https://github.com/vatesfr/xen-orchestra/pull/5944))
|
||||||
- [Netbox] Fix error when testing plugin on versions older than 2.10 (PR [#5963](https://github.com/vatesfr/xen-orchestra/pull/5963))
|
- [Netbox] Fix error when testing plugin on versions older than 2.10 (PR [#5963](https://github.com/vatesfr/xen-orchestra/pull/5963))
|
||||||
- [Snapshot] Fix "Create VM from snapshot" creating a template instead of a VM (PR [#5955](https://github.com/vatesfr/xen-orchestra/pull/5955))
|
- [Snapshot] Fix "Create VM from snapshot" creating a template instead of a VM (PR [#5955](https://github.com/vatesfr/xen-orchestra/pull/5955))
|
||||||
|
- [Host/Logs] Improve the display of log content (PR [#5943](https://github.com/vatesfr/xen-orchestra/pull/5943))
|
||||||
|
|
||||||
### Packages to release
|
### Packages to release
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
|
import fromCallback from 'promise-toolbox/fromCallback'
|
||||||
import getStream from 'get-stream'
|
import getStream from 'get-stream'
|
||||||
import humanFormat from 'human-format'
|
import humanFormat from 'human-format'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReadableStream from 'readable-stream'
|
import ReadableStream from 'readable-stream'
|
||||||
|
import xml2js from 'xml2js'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { createPredicate } from 'value-matcher'
|
import { createPredicate } from 'value-matcher'
|
||||||
import { FormattedDate } from 'react-intl'
|
import { FormattedDate } from 'react-intl'
|
||||||
@ -9,6 +11,7 @@ import {
|
|||||||
clone,
|
clone,
|
||||||
every,
|
every,
|
||||||
forEach,
|
forEach,
|
||||||
|
get,
|
||||||
isEmpty,
|
isEmpty,
|
||||||
isFunction,
|
isFunction,
|
||||||
isPlainObject,
|
isPlainObject,
|
||||||
@ -215,6 +218,28 @@ function safeHumanFormat(value, opts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const formatLogs = logs =>
|
||||||
|
Promise.all(
|
||||||
|
map(logs, ({ body }, id) => {
|
||||||
|
const matches = /^value:\s*([0-9.]+)\s+config:\s*([^]*)$/.exec(body)
|
||||||
|
if (matches === null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const [, value, xml] = matches
|
||||||
|
return fromCallback(xml2js.parseString, xml).then((result = {}) => {
|
||||||
|
const object = mapValues(result.variable, value => get(value, '[0].$.value'))
|
||||||
|
if (object.name === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const { name, ...alarmAttributes } = object
|
||||||
|
|
||||||
|
return { name, value, alarmAttributes, id }
|
||||||
|
}, noop)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
export const formatSize = bytes => (bytes != null ? safeHumanFormat(bytes, { scale: 'binary', unit: 'B' }) : 'N/D')
|
export const formatSize = bytes => (bytes != null ? safeHumanFormat(bytes, { scale: 'binary', unit: 'B' }) : 'N/D')
|
||||||
|
|
||||||
export const formatSizeShort = bytes => safeHumanFormat(bytes, { scale: 'binary', unit: 'B', decimals: 0 })
|
export const formatSizeShort = bytes => safeHumanFormat(bytes, { scale: 'binary', unit: 'B', decimals: 0 })
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import _ from 'intl'
|
import _ from 'intl'
|
||||||
import Component from 'base-component'
|
import Component from 'base-component'
|
||||||
import decorate from 'apply-decorators'
|
import decorate from 'apply-decorators'
|
||||||
import fromCallback from 'promise-toolbox/fromCallback'
|
|
||||||
import { get as getDefined } from '@xen-orchestra/defined'
|
import { get as getDefined } from '@xen-orchestra/defined'
|
||||||
import Icon from 'icon'
|
import Icon from 'icon'
|
||||||
import Link from 'link'
|
import Link from 'link'
|
||||||
@ -9,14 +8,13 @@ import NoObjects from 'no-objects'
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import SortedTable from 'sorted-table'
|
import SortedTable from 'sorted-table'
|
||||||
import Tooltip from 'tooltip'
|
import Tooltip from 'tooltip'
|
||||||
import xml2js from 'xml2js'
|
|
||||||
import { Network, Sr, Vm } from 'render-xo-item'
|
import { Network, Sr, Vm } from 'render-xo-item'
|
||||||
import { SelectPool } from 'select-objects'
|
import { SelectPool } from 'select-objects'
|
||||||
import { Container, Row, Col } from 'grid'
|
import { Container, Row, Col } from 'grid'
|
||||||
import { Card, CardHeader, CardBlock } from 'card'
|
import { Card, CardHeader, CardBlock } from 'card'
|
||||||
import { FormattedRelative, FormattedTime } from 'react-intl'
|
import { FormattedRelative, FormattedTime } from 'react-intl'
|
||||||
import { flatten, forEach, get, includes, isEmpty, map, mapValues } from 'lodash'
|
import { flatten, forEach, includes, isEmpty, map } from 'lodash'
|
||||||
import { connectStore, formatSize, noop, resolveIds } from 'utils'
|
import { connectStore, formatLogs, formatSize, noop, resolveIds } from 'utils'
|
||||||
import {
|
import {
|
||||||
deleteMessage,
|
deleteMessage,
|
||||||
deleteMessages,
|
deleteMessages,
|
||||||
@ -555,26 +553,7 @@ export default class Health extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_updateAlarms = props => {
|
_updateAlarms = props => {
|
||||||
Promise.all(
|
formatLogs(props.alertMessages).then(formattedMessages => {
|
||||||
map(props.alertMessages, ({ body }, id) => {
|
|
||||||
const matches = /^value:\s*([0-9.]+)\s+config:\s*([^]*)$/.exec(body)
|
|
||||||
if (!matches) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const [, value, xml] = matches
|
|
||||||
return fromCallback(xml2js.parseString, xml).then(result => {
|
|
||||||
const object = mapValues(result && result.variable, value => get(value, '[0].$.value'))
|
|
||||||
if (!object || !object.name) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const { name, ...alarmAttributes } = object
|
|
||||||
|
|
||||||
return { name, value, alarmAttributes, id }
|
|
||||||
}, noop)
|
|
||||||
})
|
|
||||||
).then(formattedMessages => {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
messages: map(formattedMessages, ({ id, ...formattedMessage }) => ({
|
messages: map(formattedMessages, ({ id, ...formattedMessage }) => ({
|
||||||
formatted: formattedMessage,
|
formatted: formattedMessage,
|
||||||
|
@ -6,7 +6,13 @@ import SortedTable from 'sorted-table'
|
|||||||
import { createPager } from 'selectors'
|
import { createPager } from 'selectors'
|
||||||
import { Row, Col } from 'grid'
|
import { Row, Col } from 'grid'
|
||||||
import { deleteMessage, deleteMessages } from 'xo'
|
import { deleteMessage, deleteMessages } from 'xo'
|
||||||
|
import { formatLogs } from 'utils'
|
||||||
import { FormattedRelative, FormattedTime } from 'react-intl'
|
import { FormattedRelative, FormattedTime } from 'react-intl'
|
||||||
|
import { map } from 'lodash'
|
||||||
|
|
||||||
|
const LOG_BODY_STYLE = {
|
||||||
|
whiteSpace: 'pre-wrap',
|
||||||
|
}
|
||||||
|
|
||||||
const LOG_COLUMNS = [
|
const LOG_COLUMNS = [
|
||||||
{
|
{
|
||||||
@ -34,7 +40,26 @@ const LOG_COLUMNS = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('logContent'),
|
name: _('logContent'),
|
||||||
itemRenderer: log => log.body,
|
itemRenderer: ({ formatted, body }) =>
|
||||||
|
formatted !== undefined ? (
|
||||||
|
<div>
|
||||||
|
<Row>
|
||||||
|
<Col mediumSize={6}>
|
||||||
|
<strong>{formatted.name}</strong>
|
||||||
|
</Col>
|
||||||
|
<Col mediumSize={6}>{formatted.value}</Col>
|
||||||
|
</Row>
|
||||||
|
<br />
|
||||||
|
{map(formatted.alarmAttributes, (value, label) => (
|
||||||
|
<Row key={label}>
|
||||||
|
<Col mediumSize={6}>{label}</Col>
|
||||||
|
<Col mediumSize={6}>{value}</Col>
|
||||||
|
</Row>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<pre style={LOG_BODY_STYLE}>{body}</pre>
|
||||||
|
),
|
||||||
sortCriteria: log => log.body,
|
sortCriteria: log => log.body,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -55,7 +80,7 @@ export default class TabLogs extends Component {
|
|||||||
super()
|
super()
|
||||||
|
|
||||||
this.getLogs = createPager(
|
this.getLogs = createPager(
|
||||||
() => this.props.logs,
|
() => this.state.logs,
|
||||||
() => this.state.page,
|
() => this.state.page,
|
||||||
10
|
10
|
||||||
)
|
)
|
||||||
@ -65,6 +90,26 @@ export default class TabLogs extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this._formatLogs(this.props.logs)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(props) {
|
||||||
|
if (props.logs !== this.props.logs) {
|
||||||
|
this._formatLogs(this.props.logs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_formatLogs = logs =>
|
||||||
|
formatLogs(logs).then(formattedLogs => {
|
||||||
|
this.setState({
|
||||||
|
logs: map(formattedLogs, ({ id, ...formattedLogs }) => ({
|
||||||
|
formatted: formattedLogs,
|
||||||
|
...logs[id],
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
_nextPage = () => this.setState({ page: this.state.page + 1 })
|
_nextPage = () => this.setState({ page: this.state.page + 1 })
|
||||||
_previousPage = () => this.setState({ page: this.state.page - 1 })
|
_previousPage = () => this.setState({ page: this.state.page - 1 })
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user