diff --git a/frontend/src/contexts/LogsContext.js b/frontend/src/contexts/LogsContext.js
index fcbed53..61ddac6 100644
--- a/frontend/src/contexts/LogsContext.js
+++ b/frontend/src/contexts/LogsContext.js
@@ -3,6 +3,7 @@ import {
getFullLogApi,
getFullLogChartApi,
getLogIndexApi,
+ // @ts-ignore
getLogRuleApi,
getLogTableInfoAPi,
} from 'src/api/logs'
@@ -15,6 +16,7 @@ export const useLogsContext = () => useContext(LogsContext)
export const LogsProvider = ({ children }) => {
const [state, dispatch] = useReducer(logsReducer, logsInitialState)
const fetchData = async ({ startTime, endTime }) => {
+ // @ts-ignore
dispatch({ type: 'updateLoading', payload: true })
try {
@@ -25,6 +27,7 @@ export const LogsProvider = ({ children }) => {
pageSize: state.pagination.pageSize,
tableName: state.tableInfo?.tableName,
dataBase: state.tableInfo?.dataBase,
+ timeField: state.tableInfo?.timeField,
query: state.query,
}
@@ -33,16 +36,22 @@ export const LogsProvider = ({ children }) => {
getFullLogChartApi(params),
// getLogRuleApi({ tableName: 'test_logs', dataBase: 'default' }),
])
+ // @ts-ignore
let defaultFields = (res1?.defaultFields ?? []).sort()
+ // @ts-ignore
let hiddenFields = (res1?.hiddenFields ?? []).sort()
+ // @ts-ignore
dispatch({
type: 'setLogState',
payload: {
+ // @ts-ignore
logs: res1?.logs ?? [],
defaultFields: defaultFields,
hiddenFields: hiddenFields,
+ // @ts-ignore
logsChartData: res2?.histograms ?? [],
pagination: {
+ // @ts-ignore
total: res2?.count ?? 0,
pageIndex: state.pagination.pageIndex,
pageSize: state.pagination.pageSize,
@@ -52,6 +61,7 @@ export const LogsProvider = ({ children }) => {
})
} catch (error) {
console.error('请求出错:', error)
+ // @ts-ignore
dispatch({
type: 'setLogState',
payload: {
@@ -68,6 +78,7 @@ export const LogsProvider = ({ children }) => {
},
})
} finally {
+ // @ts-ignore
dispatch({ type: 'updateLoading', payload: false })
}
}
@@ -83,9 +94,11 @@ export const LogsProvider = ({ children }) => {
query: state.query,
})
+ // @ts-ignore
dispatch({
type: 'updateFieldIndexMap',
payload: {
+ // @ts-ignore
[column]: res.indexs,
},
})
@@ -99,16 +112,22 @@ export const LogsProvider = ({ children }) => {
const getLogTableInfo = () => {
getLogTableInfoAPi().then((res) => {
- const dataBase = Object.keys(res.logTables)[0]
- const tableList = res.logTables[dataBase][0]
- dispatch({
- type: 'updateTableInfo',
- payload: {
- dataBase: dataBase,
- tableName: tableList?.tableName,
- cluster: tableList?.cluster,
- },
- })
+ // @ts-ignore
+ dispatch({ type: 'setLogRules', payload: res.parses ?? [] })
+ // @ts-ignore
+
+ dispatch({ type: 'setInstances', payload: res.instances ?? [] })
+ if (res?.parses?.length > 0) {
+ // @ts-ignore
+ dispatch({
+ type: 'updateTableInfo',
+ payload: {
+ dataBase: res.parses[0].dataBase,
+ tableName: res.parses[0].tableName,
+ parseName: res.parses[0]?.parseName,
+ },
+ })
+ }
})
}
useEffect(() => {
@@ -126,16 +145,30 @@ export const LogsProvider = ({ children }) => {
loading: state.loading,
fieldIndexMap: state.fieldIndexMap,
tableInfo: state.tableInfo,
+ logRules: state.logRules,
+ instances: state.instances,
fetchData,
getFieldIndexData,
+ // @ts-ignore
updateLogs: (logs) => dispatch({ type: 'setLogs', payload: logs }),
updateLogsPagination: (pagination) =>
+ // @ts-ignore
dispatch({ type: 'setPagination', payload: { ...state.pagination, ...pagination } }),
+ // @ts-ignore
updateLogsChartData: (data) => dispatch({ type: 'setLogsChartData', payload: data }),
+ // @ts-ignore
updateDefaultFields: (data) => dispatch({ type: 'updateDefaultFields', payload: data }),
+ // @ts-ignore
updateHiddenFields: (data) => dispatch({ type: 'updateHiddenFields', payload: data }),
+ // @ts-ignore
updateQuery: (data) => dispatch({ type: 'updateQuery', payload: data }),
- updateTableName: (data) => dispatch({ type: 'updateTableName', payload: data }),
+ // @ts-ignore
+ updateTableInfo: (data) => dispatch({ type: 'updateTableInfo', payload: data }),
+ // @ts-ignore
+ setLogRules: (data) => dispatch({ type: 'setLogRules', payload: data }),
+ // @ts-ignore
+ setInstances: (data) => dispatch({ type: 'setInstances', payload: data }),
+ // @ts-ignore
clearFieldIndexMap: () => dispatch({ type: 'clearFieldIndexMap' }),
}),
[
@@ -148,8 +181,11 @@ export const LogsProvider = ({ children }) => {
state.loading,
state.fieldIndexMap,
state.tableInfo,
+ state.logRules,
+ state.instances,
],
)
+ // @ts-ignore
return {children}
}
diff --git a/frontend/src/store/reducers/logsReducer.js b/frontend/src/store/reducers/logsReducer.js
index 937d851..43a068d 100644
--- a/frontend/src/store/reducers/logsReducer.js
+++ b/frontend/src/store/reducers/logsReducer.js
@@ -2,9 +2,14 @@ export const logsInitialState = {
tableInfo: {
dataBase: '',
tableName: '',
+ parseName: '',
+
cluster: '',
+ instanceName: '',
+ timeField: '',
},
- logRule: {},
+ logRules: [],
+ instances: [],
logs: [],
pagination: {
pageIndex: 1,
@@ -48,6 +53,10 @@ const logsReducer = (state = logsInitialState, action) => {
case 'updateFieldIndexMap':
//增量更新
return { ...state, fieldIndexMap: { ...state.fieldIndexMap, ...action.payload } }
+ case 'setLogRules':
+ return { ...state, logRules: action.payload }
+ case 'setInstances':
+ return { ...state, instances: action.payload }
case 'clearFieldIndexMap':
return { ...state, fieldIndexMap: {} }
default:
diff --git a/frontend/src/views/logs/component/FullLogs/component/IndexList/index.jsx b/frontend/src/views/logs/component/FullLogs/component/IndexList/index.jsx
index 1fcc951..ae7c5de 100644
--- a/frontend/src/views/logs/component/FullLogs/component/IndexList/index.jsx
+++ b/frontend/src/views/logs/component/FullLogs/component/IndexList/index.jsx
@@ -28,7 +28,7 @@ const IndexList = () => {
<>
diff --git a/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogItemDetail.jsx b/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogItemDetail.jsx
index 7add544..cdf85b0 100644
--- a/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogItemDetail.jsx
+++ b/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogItemDetail.jsx
@@ -1,9 +1,10 @@
import { Tag } from 'antd'
import React, { useEffect, useState } from 'react'
import { useLogsContext } from 'src/contexts/LogsContext'
-import LogTag from './LogTag'
+import LogKeyTag from './LogKeyTag'
const LogItemDetail = ({ log }) => {
const [contentInfo, setContentInfo] = useState({})
+ const { tableInfo } = useLogsContext()
useEffect(() => {
try {
const obj = JSON.parse(log.content)
@@ -23,7 +24,10 @@ const LogItemDetail = ({ log }) => {
return (
{Object.entries(contentInfo).map(([key, value]) => (
-
+
+ ))}
+ {Object.entries(log.tags).map(([key, value]) => (
+
))}
)
diff --git a/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogItemFold.jsx b/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogItemFold.jsx
index 61397b4..fbce70f 100644
--- a/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogItemFold.jsx
+++ b/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogItemFold.jsx
@@ -1,28 +1,25 @@
import { Tag, Tooltip } from 'antd'
import React, { useEffect, useState } from 'react'
import LogTagDropDown from './LogTagDropdown'
-const LogItemFold = ({ log }) => {
+import { useLogsContext } from 'src/contexts/LogsContext'
+import LogValueTag from './LogValueTag'
+const LogItemFold = ({ tags }) => {
+ const { tableInfo } = useLogsContext()
return (
-
- {Object.entries(log.tags).map(
- ([key, value]) =>
- value &&
- key !== 'timestamp' && (
-
-
-
- {value}
-
-
- }
- >
-
- ),
- )}
+
+ {Object.entries(tags).map(([key, value]) => {
+ if (
+ value !== '' && // 确保 value 存在且非空
+ key !== (tableInfo?.timeField || 'timestamp') && // 排除与 timeField 相同的键
+ typeof value !== 'object' // 确保 value 不是对象
+ ) {
+ return
+ }
+ return null // 不符合条件时返回 null
+ })}
)
}
diff --git a/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogTag.jsx b/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogKeyTag.jsx
similarity index 86%
rename from frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogTag.jsx
rename to frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogKeyTag.jsx
index e9e9437..f7e8abc 100644
--- a/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogTag.jsx
+++ b/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogKeyTag.jsx
@@ -1,8 +1,8 @@
import { Tag } from 'antd'
import React from 'react'
import LogTagDropDown from './LogTagDropdown'
-
-const LogTag = (props) => {
+//Key 作为log内容
+const LogKeyTag = (props) => {
const { title, description } = props
return (
@@ -18,4 +18,4 @@ const LogTag = (props) => {
)
}
-export default LogTag
+export default LogKeyTag
diff --git a/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogTagDropdown.jsx b/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogTagDropdown.jsx
index 01ffac4..fadecf5 100644
--- a/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogTagDropdown.jsx
+++ b/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogTagDropdown.jsx
@@ -41,7 +41,7 @@ const LogTagDropDown = ({ objKey, value, children }) => {
return (
<>
- {children}
+ <>{children}>
>
)
diff --git a/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogValueTag.jsx b/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogValueTag.jsx
new file mode 100644
index 0000000..27c9d02
--- /dev/null
+++ b/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/component/LogValueTag.jsx
@@ -0,0 +1,21 @@
+import { Tag, Tooltip } from 'antd'
+import React from 'react'
+import LogTagDropDown from './LogTagDropdown'
+// value作为tag内容
+const LogValueTag = (props) => {
+ const { objKey, value } = props
+ return (
+
+
+ {value}
+
+
+ }
+ />
+ )
+}
+export default LogValueTag
diff --git a/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/index.jsx b/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/index.jsx
index 3363b06..9d98fb9 100644
--- a/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/index.jsx
+++ b/frontend/src/views/logs/component/FullLogs/component/LogQueryResult/QueryList/LogItem/index.jsx
@@ -3,12 +3,13 @@ import { AiFillCaretDown, AiFillCaretRight } from 'react-icons/ai'
import LogItemFold from './component/LogItemFold'
import LogItemDetail from './component/LogItemDetail'
import { Button } from 'antd'
+import { useLogsContext } from 'src/contexts/LogsContext'
const LogItem = (props) => {
const { log, foldingChecked } = props
+ const { tableInfo } = useLogsContext()
// 是否折叠日志,true 为是,false 为否
const [isFold, setIsFold] = useState(true)
- const handleFoldClick = () => setIsFold(() => !isFold)
useEffect(() => {
setIsFold(foldingChecked ?? true)
}, [foldingChecked])
@@ -17,21 +18,22 @@ const LogItem = (props) => {
{/* icon 和 时间 */}
- {/*
*/}
- {log?.tags.timestamp}
+ >
+ {log?.tags?.[tableInfo?.timeField ? tableInfo?.timeField : 'timestamp']}
{/* 具体日志 */}
-
-
- {/* {isFold ? : } */}
+ {/*
+ */}
+ {/* */}
+ {isFold ? : }
)
diff --git a/frontend/src/views/logs/component/FullLogs/component/Sider/DataSourceTree/index.jsx b/frontend/src/views/logs/component/FullLogs/component/Sider/DataSourceTree/index.jsx
new file mode 100644
index 0000000..fca6a8a
--- /dev/null
+++ b/frontend/src/views/logs/component/FullLogs/component/Sider/DataSourceTree/index.jsx
@@ -0,0 +1,104 @@
+import { Card, Tree } from 'antd'
+import React, { useEffect, useState } from 'react'
+import { useLogsContext } from 'src/contexts/LogsContext'
+import { LuDatabase, LuServer } from 'react-icons/lu'
+import { ImTable2 } from 'react-icons/im'
+const DataSourceTree = () => {
+ const { instances, tableInfo, updateTableInfo } = useLogsContext()
+ const [treeData, setTreeData] = useState([])
+ const [expandedKeys, setExpandedKeys] = useState([])
+ const [selectedKeys, setSelectedKeys] = useState([])
+ // level:
+ // 0: instance:{dataBases:[],instanceName}
+ // 1: dataBase:{tables:[],dataBase}
+ // 2: table:{cluster,tableName,timeField}
+ const treeTitle = (title, icon) => {
+ return (
+
+ )
+ }
+ useEffect(() => {
+ const expandedKeys = []
+ const newTreeData = instances?.map((instance) => {
+ const instanceKey = 'instance-' + instance.instanceName
+ expandedKeys.push(instanceKey) // 收集instance的key
+ return {
+ key: instanceKey,
+ title: treeTitle(
+ instance.instanceName,
+ ,
+ ),
+ children: instance.dataBases?.map((dataBase) => {
+ const dataBaseKey = 'instance-' + instance.instanceName + '-dataBase-' + dataBase.dataBase
+ expandedKeys.push(dataBaseKey) // 收集dataBase的key
+ return {
+ key: dataBaseKey,
+ title: treeTitle(
+ dataBase.dataBase,
+ ,
+ ),
+ children: dataBase.tables?.map((table) => {
+ const tableKey = instance.instanceName + dataBase.dataBase + table.tableName
+ return {
+ key: tableKey,
+ title: treeTitle(
+ table.tableName,
+ ,
+ ),
+ dataBase: dataBase.dataBase,
+ instanceName: instance.instanceName,
+ ...table,
+ }
+ }),
+ }
+ }),
+ }
+ })
+
+ setTreeData(newTreeData)
+ setExpandedKeys(expandedKeys) // 更新defaultExpandedKeys
+ }, [instances])
+
+ const onSelect = (selectedKeys, { selectedNodes }) => {
+ if (selectedNodes[0].tableName) {
+ updateTableInfo({
+ dataBase: selectedNodes[0].dataBase,
+ tableName: selectedNodes[0].tableName,
+ cluster: selectedNodes[0].cluster,
+ timeField: selectedNodes[0].timeField,
+ instanceName: selectedNodes[0].instanceName,
+ })
+ }
+ }
+ const onExpand = (expandedKeys) => {
+ setExpandedKeys(expandedKeys)
+ }
+ useEffect(() => {
+ setSelectedKeys([tableInfo.instanceName + tableInfo.dataBase + tableInfo.tableName])
+ }, [tableInfo])
+ return (
+
+
+
+ )
+}
+
+export default DataSourceTree
diff --git a/frontend/src/views/logs/component/FullLogs/component/Sider/LogRuleList/index.jsx b/frontend/src/views/logs/component/FullLogs/component/Sider/LogRuleList/index.jsx
new file mode 100644
index 0000000..379120d
--- /dev/null
+++ b/frontend/src/views/logs/component/FullLogs/component/Sider/LogRuleList/index.jsx
@@ -0,0 +1,58 @@
+import { Card, Tree } from 'antd'
+import React, { useEffect, useState } from 'react'
+import { useLogsContext } from 'src/contexts/LogsContext'
+
+const LogRuleList = () => {
+ const { logRules, tableInfo, updateTableInfo } = useLogsContext()
+ const [treeData, setTreeData] = useState([])
+
+ const [selectedKeys, setSelectedKeys] = useState([])
+
+ const menuLabel = (parseName, parseInfo) => {
+ return (
+
+
{parseName}
+
{parseInfo}
+
+ )
+ }
+ useEffect(() => {
+ setTreeData(
+ logRules.map((rule, index) => ({
+ key: rule.dataBase + rule.tableName,
+ title: menuLabel(rule.parseName, rule.parseInfo),
+ ...rule,
+ })),
+ )
+ }, [logRules])
+ const onSelect = (selectedKeys, { selectedNodes }) => {
+ updateTableInfo({
+ dataBase: selectedNodes[0].dataBase,
+ tableName: selectedNodes[0].tableName,
+ cluster: '',
+ parseName: selectedNodes[0].parseName,
+ })
+ }
+ useEffect(() => {
+ setSelectedKeys([tableInfo.dataBase + tableInfo.tableName])
+ }, [tableInfo])
+ return (
+
+
+
+ )
+}
+
+export default LogRuleList
diff --git a/frontend/src/views/logs/component/FullLogs/component/Sider/index.jsx b/frontend/src/views/logs/component/FullLogs/component/Sider/index.jsx
new file mode 100644
index 0000000..7804049
--- /dev/null
+++ b/frontend/src/views/logs/component/FullLogs/component/Sider/index.jsx
@@ -0,0 +1,16 @@
+import React from 'react'
+import LogRuleList from './LogRuleList'
+import DataSourceTree from './DataSourceTree'
+import Sider from 'antd/es/layout/Sider'
+import { Card } from 'antd'
+
+const FullLogSider = () => {
+ return (
+ <>
+
+
+ >
+ )
+}
+
+export default FullLogSider
diff --git a/frontend/src/views/logs/component/FullLogs/index.css b/frontend/src/views/logs/component/FullLogs/index.css
new file mode 100644
index 0000000..3f87be7
--- /dev/null
+++ b/frontend/src/views/logs/component/FullLogs/index.css
@@ -0,0 +1,24 @@
+.logSiderButton {
+ top: 50%;
+ position: absolute;
+ transform: translate(0, -50%);
+ z-index: 100;
+ background: #ffffff1a;
+ height: 40px;
+ border-radius: 0px 100% 100% 0px / 50%;
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+}
+
+.openButton {
+ left: 190px;
+ transition: left 0.2s ease;
+ /* 添加 transition */
+}
+
+.closeButton {
+ left: -1px;
+ transition: left 0.2s ease;
+ /* 添加 transition */
+}
\ No newline at end of file
diff --git a/frontend/src/views/logs/component/FullLogs/index.jsx b/frontend/src/views/logs/component/FullLogs/index.jsx
index c754361..f6e8ffd 100644
--- a/frontend/src/views/logs/component/FullLogs/index.jsx
+++ b/frontend/src/views/logs/component/FullLogs/index.jsx
@@ -9,6 +9,12 @@ import IndexList from './component/IndexList'
import LogQueryResult from './component/LogQueryResult'
import { useLogsContext } from 'src/contexts/LogsContext'
import { useDebounce, useUpdateEffect } from 'react-use'
+import FullLogSider from './component/Sider'
+import { Button, Layout } from 'antd'
+import Sider from 'antd/es/layout/Sider'
+import { Content } from 'antd/es/layout/layout'
+import { AiOutlineCaretLeft, AiOutlineCaretRight } from 'react-icons/ai'
+import './index.css'
function FullLogs() {
const {
query,
@@ -21,6 +27,7 @@ function FullLogs() {
} = useLogsContext()
const [searchParams] = useSearchParams()
+ const [collapsed, setCollapsed] = useState(false)
useUpdateEffect(() => {
if (searchParams.get('log-from') && searchParams.get('log-to')) {
@@ -59,18 +66,43 @@ function FullLogs() {
<>
{/* 顶部筛选 */}
-
-
-
-
-
-
-
+
+
+ setCollapsed(!collapsed)}
+ className={`logSiderButton ${collapsed ? ' closeButton ' : 'openButton'}`}
+ >
+ {collapsed ? (
+
+ ) : (
+
+ )}
-
-
-
-
+
+
+
+
+
+
+
>
)