Merge pull request #3538 from influxdata/log-viewer/graph
Calculate bin size for log viewerpull/3544/head
commit
98c70f70cb
|
@ -63,6 +63,8 @@ export const saveToLocalStorage = ({
|
|||
const appPersisted = {app: {persisted}}
|
||||
const dashTimeV1 = {ranges: normalizer(ranges)}
|
||||
|
||||
const minimalLogs = _.omit(logs, ['tableData', 'histogramData'])
|
||||
|
||||
window.localStorage.setItem(
|
||||
'state',
|
||||
JSON.stringify({
|
||||
|
@ -73,7 +75,7 @@ export const saveToLocalStorage = ({
|
|||
dataExplorer,
|
||||
dataExplorerQueryConfigs,
|
||||
script,
|
||||
logs,
|
||||
logs: {...minimalLogs, histogramData: [], tableData: {}},
|
||||
})
|
||||
)
|
||||
} catch (err) {
|
||||
|
|
|
@ -1,13 +1,36 @@
|
|||
import _ from 'lodash'
|
||||
import {Source, Namespace, TimeRange, QueryConfig} from 'src/types'
|
||||
import {getSource} from 'src/shared/apis'
|
||||
import {getDatabasesWithRetentionPolicies} from 'src/shared/apis/databases'
|
||||
import {buildHistogramQueryConfig} from 'src/logs/utils'
|
||||
import {buildHistogramQueryConfig, buildTableQueryConfig} from 'src/logs/utils'
|
||||
import {getDeep} from 'src/utils/wrappers'
|
||||
import buildQuery from 'src/utils/influxql'
|
||||
import {executeQueryAsync} from 'src/logs/api'
|
||||
import {LogsState} from 'src/types/localStorage'
|
||||
|
||||
type GetState = () => {logs: LogsState}
|
||||
interface TableData {
|
||||
columns: string[]
|
||||
values: string[]
|
||||
}
|
||||
|
||||
const defaultTableData = {
|
||||
columns: [
|
||||
'time',
|
||||
'message',
|
||||
'facility_code',
|
||||
'procid',
|
||||
'severity_code',
|
||||
'timestamp',
|
||||
'version',
|
||||
],
|
||||
values: [],
|
||||
}
|
||||
|
||||
interface State {
|
||||
logs: LogsState
|
||||
}
|
||||
|
||||
type GetState = () => State
|
||||
|
||||
export enum ActionTypes {
|
||||
SetSource = 'LOGS_SET_SOURCE',
|
||||
|
@ -16,6 +39,8 @@ export enum ActionTypes {
|
|||
SetNamespace = 'LOGS_SET_NAMESPACE',
|
||||
SetHistogramQueryConfig = 'LOGS_SET_HISTOGRAM_QUERY_CONFIG',
|
||||
SetHistogramData = 'LOGS_SET_HISTOGRAM_DATA',
|
||||
SetTableQueryConfig = 'LOGS_SET_TABLE_QUERY_CONFIG',
|
||||
SetTableData = 'LOGS_SET_TABLE_DATA',
|
||||
ChangeZoom = 'LOGS_CHANGE_ZOOM',
|
||||
}
|
||||
|
||||
|
@ -61,6 +86,20 @@ interface SetHistogramData {
|
|||
}
|
||||
}
|
||||
|
||||
interface SetTableQueryConfig {
|
||||
type: ActionTypes.SetTableQueryConfig
|
||||
payload: {
|
||||
queryConfig: QueryConfig
|
||||
}
|
||||
}
|
||||
|
||||
interface SetTableData {
|
||||
type: ActionTypes.SetTableData
|
||||
payload: {
|
||||
data: object
|
||||
}
|
||||
}
|
||||
|
||||
interface ChangeZoomAction {
|
||||
type: ActionTypes.ChangeZoom
|
||||
payload: {
|
||||
|
@ -77,12 +116,32 @@ export type Action =
|
|||
| SetHistogramQueryConfig
|
||||
| SetHistogramData
|
||||
| ChangeZoomAction
|
||||
| SetTableData
|
||||
| SetTableQueryConfig
|
||||
|
||||
const getTimeRange = (state: State): TimeRange | null =>
|
||||
getDeep<TimeRange | null>(state, 'logs.timeRange', null)
|
||||
|
||||
const getNamespace = (state: State): Namespace | null =>
|
||||
getDeep<Namespace | null>(state, 'logs.currentNamespace', null)
|
||||
|
||||
const getProxyLink = (state: State): string | null =>
|
||||
getDeep<string | null>(state, 'logs.currentSource.links.proxy', null)
|
||||
|
||||
const getHistogramQueryConfig = (state: State): QueryConfig | null =>
|
||||
getDeep<QueryConfig | null>(state, 'logs.histogramQueryConfig', null)
|
||||
|
||||
const getTableQueryConfig = (state: State): QueryConfig | null =>
|
||||
getDeep<QueryConfig | null>(state, 'logs.tableQueryConfig', null)
|
||||
|
||||
export const setSource = (source: Source): SetSourceAction => ({
|
||||
type: ActionTypes.SetSource,
|
||||
payload: {
|
||||
source,
|
||||
},
|
||||
payload: {source},
|
||||
})
|
||||
|
||||
const setHistogramData = (response): SetHistogramData => ({
|
||||
type: ActionTypes.SetHistogramData,
|
||||
payload: {data: [{response}]},
|
||||
})
|
||||
|
||||
export const executeHistogramQueryAsync = () => async (
|
||||
|
@ -90,36 +149,51 @@ export const executeHistogramQueryAsync = () => async (
|
|||
getState: GetState
|
||||
): Promise<void> => {
|
||||
const state = getState()
|
||||
const queryConfig = getDeep<QueryConfig | null>(
|
||||
state,
|
||||
'logs.histogramQueryConfig',
|
||||
null
|
||||
)
|
||||
const timeRange = getDeep<TimeRange | null>(state, 'logs.timeRange', null)
|
||||
const namespace = getDeep<Namespace | null>(
|
||||
state,
|
||||
'logs.currentNamespace',
|
||||
null
|
||||
)
|
||||
const proxyLink = getDeep<string | null>(
|
||||
state,
|
||||
'logs.currentSource.links.proxy',
|
||||
null
|
||||
)
|
||||
|
||||
if (queryConfig && timeRange && namespace && proxyLink) {
|
||||
const queryConfig = getHistogramQueryConfig(state)
|
||||
const timeRange = getTimeRange(state)
|
||||
const namespace = getNamespace(state)
|
||||
const proxyLink = getProxyLink(state)
|
||||
|
||||
if (_.every([queryConfig, timeRange, namespace, proxyLink])) {
|
||||
const query = buildQuery(timeRange, queryConfig)
|
||||
const response = await executeQueryAsync(proxyLink, namespace, query)
|
||||
|
||||
dispatch({
|
||||
type: ActionTypes.SetHistogramData,
|
||||
payload: {
|
||||
data: [{response}],
|
||||
},
|
||||
})
|
||||
dispatch(setHistogramData(response))
|
||||
}
|
||||
}
|
||||
|
||||
const setTableData = (series: TableData): SetTableData => ({
|
||||
type: ActionTypes.SetTableData,
|
||||
payload: {data: {columns: series.columns, values: _.reverse(series.values)}},
|
||||
})
|
||||
|
||||
export const executeTableQueryAsync = () => async (
|
||||
dispatch,
|
||||
getState: GetState
|
||||
): Promise<void> => {
|
||||
const state = getState()
|
||||
|
||||
const queryConfig = getTableQueryConfig(state)
|
||||
const timeRange = getTimeRange(state)
|
||||
const namespace = getNamespace(state)
|
||||
const proxyLink = getProxyLink(state)
|
||||
|
||||
if (_.every([queryConfig, timeRange, namespace, proxyLink])) {
|
||||
const query = buildQuery(timeRange, queryConfig)
|
||||
const response = await executeQueryAsync(proxyLink, namespace, query)
|
||||
|
||||
const series = getDeep(response, 'results.0.series.0', defaultTableData)
|
||||
|
||||
dispatch(setTableData(series))
|
||||
}
|
||||
}
|
||||
|
||||
export const executeQueriesAsync = () => async dispatch => {
|
||||
dispatch(executeHistogramQueryAsync())
|
||||
dispatch(executeTableQueryAsync())
|
||||
}
|
||||
|
||||
export const setHistogramQueryConfigAsync = () => async (
|
||||
dispatch,
|
||||
getState: GetState
|
||||
|
@ -144,6 +218,31 @@ export const setHistogramQueryConfigAsync = () => async (
|
|||
}
|
||||
}
|
||||
|
||||
export const setTableQueryConfig = (queryConfig: QueryConfig) => ({
|
||||
type: ActionTypes.SetTableQueryConfig,
|
||||
payload: {queryConfig},
|
||||
})
|
||||
|
||||
export const setTableQueryConfigAsync = () => async (
|
||||
dispatch,
|
||||
getState: GetState
|
||||
): Promise<void> => {
|
||||
const state = getState()
|
||||
const namespace = getDeep<Namespace | null>(
|
||||
state,
|
||||
'logs.currentNamespace',
|
||||
null
|
||||
)
|
||||
const timeRange = getDeep<TimeRange | null>(state, 'logs.timeRange', null)
|
||||
|
||||
if (timeRange && namespace) {
|
||||
const queryConfig = buildTableQueryConfig(namespace, timeRange)
|
||||
|
||||
dispatch(setTableQueryConfig(queryConfig))
|
||||
dispatch(executeTableQueryAsync())
|
||||
}
|
||||
}
|
||||
|
||||
export const setNamespaceAsync = (namespace: Namespace) => async (
|
||||
dispatch
|
||||
): Promise<void> => {
|
||||
|
@ -153,6 +252,7 @@ export const setNamespaceAsync = (namespace: Namespace) => async (
|
|||
})
|
||||
|
||||
dispatch(setHistogramQueryConfigAsync())
|
||||
dispatch(setTableQueryConfigAsync())
|
||||
}
|
||||
|
||||
export const setNamespaces = (
|
||||
|
@ -174,6 +274,7 @@ export const setTimeRangeAsync = (timeRange: TimeRange) => async (
|
|||
},
|
||||
})
|
||||
dispatch(setHistogramQueryConfigAsync())
|
||||
dispatch(setTableQueryConfigAsync())
|
||||
}
|
||||
|
||||
export const populateNamespacesAsync = (proxyLink: string) => async (
|
||||
|
@ -206,16 +307,9 @@ export const changeZoomAsync = (timeRange: TimeRange) => async (
|
|||
getState: GetState
|
||||
): Promise<void> => {
|
||||
const state = getState()
|
||||
const namespace = getDeep<Namespace | null>(
|
||||
state,
|
||||
'logs.currentNamespace',
|
||||
null
|
||||
)
|
||||
const proxyLink = getDeep<string | null>(
|
||||
state,
|
||||
'logs.currentSource.links.proxy',
|
||||
null
|
||||
)
|
||||
|
||||
const namespace = getNamespace(state)
|
||||
const proxyLink = getProxyLink(state)
|
||||
|
||||
if (namespace && proxyLink) {
|
||||
const queryConfig = buildHistogramQueryConfig(namespace, timeRange)
|
||||
|
@ -229,5 +323,8 @@ export const changeZoomAsync = (timeRange: TimeRange) => async (
|
|||
timeRange,
|
||||
},
|
||||
})
|
||||
|
||||
await dispatch(setTimeRangeAsync(timeRange))
|
||||
await dispatch(executeTableQueryAsync())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,178 @@
|
|||
import moment from 'moment'
|
||||
import React, {PureComponent} from 'react'
|
||||
import {Grid, AutoSizer} from 'react-virtualized'
|
||||
import {getDeep} from 'src/utils/wrappers'
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
|
||||
interface Props {
|
||||
thing: string
|
||||
data: {
|
||||
columns: string[]
|
||||
values: string[]
|
||||
}
|
||||
}
|
||||
|
||||
class LogsTableContainer extends PureComponent<Props> {
|
||||
const FACILITY_CODES = [
|
||||
'kern',
|
||||
'user',
|
||||
'mail',
|
||||
'daemon',
|
||||
'auth',
|
||||
'syslog',
|
||||
'lpr',
|
||||
'news',
|
||||
'uucp',
|
||||
'clock',
|
||||
'authpriv',
|
||||
'ftp',
|
||||
'NTP',
|
||||
'log audit',
|
||||
'log alert',
|
||||
'cron',
|
||||
'local0',
|
||||
'local1',
|
||||
'local2',
|
||||
'local3',
|
||||
'local4',
|
||||
'local5',
|
||||
'local6',
|
||||
'local7',
|
||||
]
|
||||
|
||||
class LogsTable extends PureComponent<Props> {
|
||||
public render() {
|
||||
const rowCount = getDeep(this.props, 'data.values.length', 0)
|
||||
const columnCount = getDeep(this.props, 'data.columns.length', 1) - 1
|
||||
|
||||
return (
|
||||
<div className="logs-viewer--table-container">
|
||||
<p>{this.props.thing}</p>
|
||||
<AutoSizer>
|
||||
{({width}) => (
|
||||
<Grid
|
||||
height={40}
|
||||
rowHeight={40}
|
||||
rowCount={1}
|
||||
width={width}
|
||||
cellRenderer={this.headerRenderer}
|
||||
columnCount={columnCount}
|
||||
columnWidth={this.getColumnWidth}
|
||||
/>
|
||||
)}
|
||||
</AutoSizer>
|
||||
<AutoSizer>
|
||||
{({width, height}) => (
|
||||
<FancyScrollbar
|
||||
style={{width, height, marginTop: '40px'}}
|
||||
autoHide={false}
|
||||
>
|
||||
<Grid
|
||||
height={height}
|
||||
rowHeight={40}
|
||||
rowCount={rowCount}
|
||||
width={width}
|
||||
cellRenderer={this.cellRenderer}
|
||||
columnCount={columnCount}
|
||||
columnWidth={this.getColumnWidth}
|
||||
/>
|
||||
</FancyScrollbar>
|
||||
)}
|
||||
</AutoSizer>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private severityLevel(value: number): string {
|
||||
switch (value) {
|
||||
case 0:
|
||||
return 'Emergency'
|
||||
case 1:
|
||||
return 'Alert'
|
||||
case 2:
|
||||
return 'Critical'
|
||||
case 3:
|
||||
return 'Error'
|
||||
case 4:
|
||||
return 'Warning'
|
||||
case 5:
|
||||
return 'Notice'
|
||||
case 6:
|
||||
return 'Informational'
|
||||
default:
|
||||
return 'Debug'
|
||||
}
|
||||
}
|
||||
|
||||
private getColumnWidth = ({index}: {index: number}) => {
|
||||
const column = getDeep<string>(this.props, `data.columns.${index + 1}`, '')
|
||||
|
||||
switch (column) {
|
||||
case 'message':
|
||||
return 700
|
||||
case 'timestamp':
|
||||
return 400
|
||||
default:
|
||||
return 200
|
||||
}
|
||||
}
|
||||
|
||||
private header(key: string): string {
|
||||
return getDeep<string>(
|
||||
{
|
||||
timestamp: 'Timestamp',
|
||||
facility_code: 'Facility',
|
||||
procid: 'Proc ID',
|
||||
severity_code: 'Severity',
|
||||
message: 'Message',
|
||||
},
|
||||
key,
|
||||
''
|
||||
)
|
||||
}
|
||||
|
||||
private facility(key: number): string {
|
||||
return getDeep<string>(FACILITY_CODES, key, '')
|
||||
}
|
||||
|
||||
private headerRenderer = ({key, style, columnIndex}) => {
|
||||
const value = getDeep<string>(
|
||||
this.props,
|
||||
`data.columns.${columnIndex + 1}`,
|
||||
''
|
||||
)
|
||||
|
||||
return (
|
||||
<div style={style} key={key}>
|
||||
{this.header(value)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private cellRenderer = ({key, style, rowIndex, columnIndex}) => {
|
||||
const column = getDeep<string>(
|
||||
this.props,
|
||||
`data.columns.${columnIndex + 1}`,
|
||||
''
|
||||
)
|
||||
|
||||
let value = this.props.data.values[rowIndex][columnIndex + 1]
|
||||
|
||||
switch (column) {
|
||||
case 'timestamp':
|
||||
value = moment(+value / 1000000).format('YYYY/MM/DD HH:mm:ss')
|
||||
break
|
||||
case 'severity_code':
|
||||
value = this.severityLevel(+value)
|
||||
break
|
||||
case 'facility_code':
|
||||
value = this.facility(+value)
|
||||
break
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={style} key={key}>
|
||||
{value}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default LogsTableContainer
|
||||
export default LogsTable
|
||||
|
|
|
@ -130,10 +130,9 @@ class TimeRangeDropdown extends Component<Props, State> {
|
|||
}
|
||||
|
||||
private get dropdownClassName(): string {
|
||||
const {
|
||||
isOpen,
|
||||
customTimeRange: {lower, upper},
|
||||
} = this.state
|
||||
const {isOpen} = this.state
|
||||
|
||||
const {lower, upper} = _.get(this.props, 'selected', {upper: '', lower: ''})
|
||||
|
||||
const absoluteTimeRange = !_.isEmpty(lower) && !_.isEmpty(upper)
|
||||
|
||||
|
|
|
@ -4,16 +4,17 @@ import {
|
|||
getSourceAndPopulateNamespacesAsync,
|
||||
setTimeRangeAsync,
|
||||
setNamespaceAsync,
|
||||
executeHistogramQueryAsync,
|
||||
executeQueriesAsync,
|
||||
changeZoomAsync,
|
||||
} from 'src/logs/actions'
|
||||
import {getSourcesAsync} from 'src/shared/actions/sources'
|
||||
import LogViewerHeader from 'src/logs/components/LogViewerHeader'
|
||||
import Graph from 'src/logs/components/LogsGraph'
|
||||
import Table from 'src/logs/components/LogsTable'
|
||||
import SearchBar from 'src/logs/components/LogsSearchBar'
|
||||
import FilterBar from 'src/logs/components/LogsFilterBar'
|
||||
import LogViewerChart from 'src/logs/components/LogViewerChart'
|
||||
import LogsTable from 'src/logs/components/LogsTable'
|
||||
import {getDeep} from 'src/utils/wrappers'
|
||||
|
||||
import {Source, Namespace, TimeRange} from 'src/types'
|
||||
|
||||
|
@ -35,9 +36,13 @@ interface Props {
|
|||
setTimeRangeAsync: (timeRange: TimeRange) => void
|
||||
setNamespaceAsync: (namespace: Namespace) => void
|
||||
changeZoomAsync: (timeRange: TimeRange) => void
|
||||
executeHistogramQueryAsync: () => void
|
||||
executeQueriesAsync: () => void
|
||||
timeRange: TimeRange
|
||||
histogramData: object[]
|
||||
tableData: {
|
||||
columns: string[]
|
||||
values: string[]
|
||||
}
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -73,11 +78,17 @@ class LogsPage extends PureComponent<Props, State> {
|
|||
|
||||
public componentDidMount() {
|
||||
this.props.getSources()
|
||||
|
||||
if (this.props.currentNamespace) {
|
||||
this.props.executeQueriesAsync()
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {searchString, filters} = this.state
|
||||
|
||||
const count = getDeep(this.props, 'tableData.values.length', 0)
|
||||
|
||||
return (
|
||||
<div className="page">
|
||||
{this.header}
|
||||
|
@ -89,11 +100,11 @@ class LogsPage extends PureComponent<Props, State> {
|
|||
onSearch={this.handleSubmitSearch}
|
||||
/>
|
||||
<FilterBar
|
||||
numResults={300}
|
||||
numResults={count}
|
||||
filters={filters}
|
||||
onUpdateFilters={this.handleUpdateFilters}
|
||||
/>
|
||||
<Table thing="snooo" />
|
||||
<LogsTable data={this.props.tableData} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -149,7 +160,7 @@ class LogsPage extends PureComponent<Props, State> {
|
|||
|
||||
private handleChooseTimerange = (timeRange: TimeRange) => {
|
||||
this.props.setTimeRangeAsync(timeRange)
|
||||
this.props.executeHistogramQueryAsync()
|
||||
this.props.executeQueriesAsync()
|
||||
}
|
||||
|
||||
private handleChooseSource = (sourceID: string) => {
|
||||
|
@ -175,6 +186,7 @@ const mapStateToProps = ({
|
|||
timeRange,
|
||||
currentNamespace,
|
||||
histogramData,
|
||||
tableData,
|
||||
},
|
||||
}) => ({
|
||||
sources,
|
||||
|
@ -183,6 +195,7 @@ const mapStateToProps = ({
|
|||
timeRange,
|
||||
currentNamespace,
|
||||
histogramData,
|
||||
tableData,
|
||||
})
|
||||
|
||||
const mapDispatchToProps = {
|
||||
|
@ -190,7 +203,7 @@ const mapDispatchToProps = {
|
|||
getSources: getSourcesAsync,
|
||||
setTimeRangeAsync,
|
||||
setNamespaceAsync,
|
||||
executeHistogramQueryAsync,
|
||||
executeQueriesAsync,
|
||||
changeZoomAsync,
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ const defaultState: LogsState = {
|
|||
timeRange: {lower: 'now() - 1m', upper: null},
|
||||
currentNamespace: null,
|
||||
histogramQueryConfig: null,
|
||||
tableQueryConfig: null,
|
||||
tableData: [],
|
||||
histogramData: [],
|
||||
}
|
||||
|
||||
|
@ -24,6 +26,10 @@ export default (state: LogsState = defaultState, action: Action) => {
|
|||
return {...state, histogramQueryConfig: action.payload.queryConfig}
|
||||
case ActionTypes.SetHistogramData:
|
||||
return {...state, histogramData: action.payload.data}
|
||||
case ActionTypes.SetTableQueryConfig:
|
||||
return {...state, tableQueryConfig: action.payload.queryConfig}
|
||||
case ActionTypes.SetTableData:
|
||||
return {...state, tableData: action.payload.data}
|
||||
case ActionTypes.ChangeZoom:
|
||||
const {timeRange, data} = action.payload
|
||||
return {...state, timeRange, histogramData: data}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import moment from 'moment'
|
||||
import uuid from 'uuid'
|
||||
import {TimeRange, Namespace, QueryConfig} from 'src/types'
|
||||
|
||||
const fields = [
|
||||
const BIN_COUNT = 30
|
||||
|
||||
const histogramFields = [
|
||||
{
|
||||
alias: '',
|
||||
args: [
|
||||
|
@ -16,27 +19,96 @@ const fields = [
|
|||
},
|
||||
]
|
||||
|
||||
const tableFields = [
|
||||
{
|
||||
alias: 'timestamp',
|
||||
type: 'field',
|
||||
value: 'timestamp',
|
||||
},
|
||||
{
|
||||
alias: 'facility_code',
|
||||
type: 'field',
|
||||
value: 'facility_code',
|
||||
},
|
||||
{
|
||||
alias: 'procid',
|
||||
type: 'field',
|
||||
value: 'procid',
|
||||
},
|
||||
{
|
||||
alias: 'severity_code',
|
||||
type: 'field',
|
||||
value: 'severity_code',
|
||||
},
|
||||
{
|
||||
alias: 'message',
|
||||
type: 'field',
|
||||
value: 'message',
|
||||
},
|
||||
]
|
||||
|
||||
const defaultQueryConfig = {
|
||||
areTagsAccepted: false,
|
||||
fields,
|
||||
fill: '0',
|
||||
groupBy: {time: '2m', tags: []},
|
||||
measurement: 'syslog',
|
||||
rawText: null,
|
||||
shifts: [],
|
||||
tags: {},
|
||||
}
|
||||
|
||||
const computeSeconds = (range: TimeRange) => {
|
||||
const {upper, lower, seconds} = range
|
||||
|
||||
if (seconds) {
|
||||
return seconds
|
||||
} else if (upper && lower) {
|
||||
return moment(upper).unix() - moment(lower).unix()
|
||||
} else {
|
||||
return 120
|
||||
}
|
||||
}
|
||||
|
||||
const createGroupBy = (range: TimeRange) => {
|
||||
const seconds = computeSeconds(range)
|
||||
const time = `${Math.floor(seconds / BIN_COUNT)}s`
|
||||
const tags = []
|
||||
|
||||
return {time, tags}
|
||||
}
|
||||
|
||||
export const buildHistogramQueryConfig = (
|
||||
namespace: Namespace,
|
||||
range: TimeRange
|
||||
): QueryConfig => {
|
||||
const id = uuid.v4()
|
||||
const {database, retentionPolicy} = namespace
|
||||
|
||||
return {
|
||||
...defaultQueryConfig,
|
||||
id,
|
||||
range,
|
||||
database: namespace.database,
|
||||
retentionPolicy: namespace.retentionPolicy,
|
||||
database,
|
||||
retentionPolicy,
|
||||
groupBy: createGroupBy(range),
|
||||
fields: histogramFields,
|
||||
}
|
||||
}
|
||||
|
||||
export const buildTableQueryConfig = (
|
||||
namespace: Namespace,
|
||||
range: TimeRange
|
||||
): QueryConfig => {
|
||||
const id = uuid.v4()
|
||||
const {database, retentionPolicy} = namespace
|
||||
|
||||
return {
|
||||
...defaultQueryConfig,
|
||||
id,
|
||||
range,
|
||||
database,
|
||||
retentionPolicy,
|
||||
groupBy: {tags: []},
|
||||
fields: tableFields,
|
||||
fill: null,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ export interface LogsState {
|
|||
timeRange: TimeRange
|
||||
histogramQueryConfig: QueryConfig | null
|
||||
histogramData: object[]
|
||||
tableQueryConfig: QueryConfig | null
|
||||
tableData: object[]
|
||||
}
|
||||
|
||||
export interface LocalStorage {
|
||||
|
|
|
@ -86,6 +86,7 @@ export interface Status {
|
|||
export interface TimeRange {
|
||||
lower: string
|
||||
upper?: string | null
|
||||
seconds?: number
|
||||
}
|
||||
|
||||
export interface DurationRange {
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import _ from 'lodash'
|
||||
|
||||
export function getDeep<T = any>(obj: any, path: string, fallback: T): T {
|
||||
export function getDeep<T = any>(
|
||||
obj: any,
|
||||
path: string | number,
|
||||
fallback: T
|
||||
): T {
|
||||
return _.get<T>(obj, path, fallback)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue