删除日志记录

由于大量的请求导致日志大量写入代理性能极差所以建议将日志在应用服务处理,而代理应该更纯粹的代理服务。
This commit is contained in:
token
2024-01-26 22:31:53 +08:00
parent c6d5728378
commit b7eaecb6b5
8 changed files with 15 additions and 383 deletions
-1
View File
@@ -10,7 +10,6 @@ Gateway提供了基本的管理服务,提供简单的登录授权,和实时
- [x] dashboard监控
- [x] 静态文件服务代理
- [x] 穿透隧道功能
- [x] 请求日志记录监控
- [ ] 动态插件管理
## 技术栈
+1 -1
View File
@@ -44,7 +44,7 @@ public static class TunnelExensions
var stream = new DuplexHttpStream(context);
using var reg = lifetime.ApplicationStopping.Register(() => stream.Abort());
await using var reg = lifetime.ApplicationStopping.Register(() => stream.Abort());
// Keep reusing this connection while, it's still open on the backend
while (!context.RequestAborted.IsCancellationRequested)
-5
View File
@@ -4,7 +4,6 @@ import MainLayout from './layout/main-layout';
import Home from './pages/home';
import 'reset-css';
import Gateway from './pages/gateway';
import Logger from './pages/logger';
import Setting from './pages/settings';
import Login from './pages/login';
@@ -20,10 +19,6 @@ const router = createBrowserRouter([{
path: "Gateway",
element: <Gateway />
},
{
path: "Logger",
element: <Logger />
},
{
path: "Setting",
element: <Setting />
-5
View File
@@ -17,8 +17,6 @@ export default function MainLayout() {
setSelectedKeys(['Home']);
} else if (path === '/Gateway') {
setSelectedKeys(['Gateway']);
} else if (path === '/Logger') {
setSelectedKeys(['Logger']);
} else if (path === '/Setting') {
setSelectedKeys(['Setting']);
}
@@ -35,8 +33,6 @@ export default function MainLayout() {
navigate('/');
} else if (key.itemKey === 'Gateway') {
navigate('/Gateway');
} else if (key.itemKey === 'Logger') {
navigate('/Logger');
} else if (key.itemKey === 'Setting') {
navigate('/Setting');
}
@@ -45,7 +41,6 @@ export default function MainLayout() {
items={[
{ itemKey: 'Home', text: '首页', icon: <IconHome size="large" /> },
{ itemKey: 'Gateway', text: '代理设置', icon: <IconServerStroked /> },
{ itemKey: 'Logger', text: '日志', icon: <IconFile size="large" /> },
{ itemKey: 'Setting', text: '设置', icon: <IconSetting size="large" /> },
]}
header={{
+10 -191
View File
@@ -1,166 +1,9 @@
import { Panel } from '../../service/RequestLogService';
import { useEffect, useState } from "react";
import { VChart } from "@visactor/react-vchart";
import { Col, Row } from '@douyinfe/semi-ui';
import { stream } from '../../service/NetWorkService';
import { debounce } from '../../utils/utils'
import * as echarts from 'echarts';
export default function Home() {
const [hours, setHours] = useState<number>(24);
const [requestSize, setRequestSize] = useState<any>({
spec: {
type: 'area',
data: {
values: [
]
},
title: {
visible: true,
text: '最近24小时记录'
},
xField: 'time',
yField: 'value'
}
});
const [requestStatusCode, setRequestStatusCode] = useState<any>({
spec: {
type: 'bar',
data: {
values: [
]
}
}
})
const [requestPath, setRequestPath] = useState<any>({
spec: {
type: 'pie',
data: [
{
id: 'id0',
values: [
]
}
],
outerRadius: 0.8,
valueField: 'value',
categoryField: 'type',
title: {
visible: true,
text: '路由热度排名'
},
legends: {
visible: true,
orient: 'left'
},
label: {
visible: true
},
tooltip: {
mark: {
content: [
{
key: (datum: { [x: string]: any; }) => datum['type'],
value: (datum: { [x: string]: string; }) => datum['value'] + '%'
}
]
}
}
}
})
async function loadingPanel() {
const response = await Panel(hours) as any;
setRequestSize({
spec: {
type: 'area',
data: {
values: response.data.requestSize
},
title: {
visible: true,
text: '最近24小时记录'
},
xField: 'time',
yField: 'value'
}
});
setRequestPath({
spec: {
type: 'pie',
data: [
{
id: 'id0',
values: response.data.requestPath
}
],
outerRadius: 0.8,
valueField: 'value',
categoryField: 'type',
title: {
visible: true,
text: '路由热度排名'
},
legends: {
visible: true,
orient: 'left'
},
label: {
visible: true
},
tooltip: {
mark: {
content: [
{
key: (datum: { [x: string]: any; }) => datum['type'],
value: (datum: { [x: string]: string; }) => datum['value'] + '%'
}
]
}
}
}
});
setRequestStatusCode({
spec: {
type: 'bar',
data: {
values: response.data.requestStatusCode
},
xField: ['type', 'country'],
yField: 'value',
seriesField: 'country',
animationAppear: {
duration: 1500,
easing: 'linear'
},
legends: [{ visible: true, position: 'middle', orient: 'bottom' }],
// @ts-ignore
animationAppear: {
duration: 500,
oneByOne: true
},
axes: [
{
orient: 'left',
}
]
}
});
}
useEffect(() => {
const loadingPanelFunction = debounce(loadingPanel, 500, true);
loadingPanelFunction()
}, [hours]);
useEffect(() => {
}, []);
useEffect(() => {
var chartDom = document.getElementById('network')!;
var myChart = echarts.init(chartDom);
@@ -168,7 +11,7 @@ export default function Home() {
option = {
title: {
text: '实时流量监控'
text: '实时流量'
},
tooltip: {
trigger: 'axis'
@@ -291,7 +134,7 @@ export default function Home() {
fetchData();
// 设置定时器,每隔一段时间调用获取数据的函数
const intervalId = setInterval(fetchData, 6000); // 每5秒获取一次数据
const intervalId = setInterval(fetchData, 5900); // 每5秒获取一次数据
// 组件卸载时清除定时器
return () => {
@@ -302,7 +145,14 @@ export default function Home() {
return (
<div className="App">
<h2 style={{
textAlign: 'center',
margin: '10px 0',
fontSize: '20px',
fontWeight: 'bold'
}}>
数据面板
</h2>
<Row>
<div id='network' style={{
width: '100%',
@@ -311,37 +161,6 @@ export default function Home() {
}}>
</div>
</Row>
<Row>
<Col span={12}><div className="col-content">
<VChart
spec={{
height: 350,
...requestSize.spec,
}}
/></div></Col>
<Col span={12}><div className="col-content">
<VChart
spec={{
height: 350,
...requestPath.spec,
}} /></div></Col>
</Row>
<Row style={{
marginTop: '20px',
}}>
<div style={{
fontSize: '20px',
fontWeight: 'bold',
marginBottom: '20px',
}}>
7天请求状态码分布
</div>
<VChart
spec={{
...requestStatusCode.spec,
}} />
</Row>
</div>
);
}
-142
View File
@@ -1,142 +0,0 @@
import { Button, Input, Pagination, Table, Toast, DatePicker } from "@douyinfe/semi-ui";
import { useEffect, useState } from "react";
import { RequestLog } from '../../service/RequestLogService'
export default function Logger() {
const [total, setTotal] = useState<number>(0);
const [data, setData] = useState<any[]>([]);
const [input, setInput] = useState({
page: 1,
pageSize: 20,
keyword: '',
startTime: null as any,
endTime: null as any,
});
const columns = [
{
title: '请求地址',
dataIndex: 'path',
},
{
title: '请求方式',
dataIndex: 'method',
},
{
title: 'IP',
dataIndex: 'ip',
},
{
title: '请求状态',
dataIndex: 'statusCode',
},
{
title: '请求耗时(ms)',
dataIndex: 'executionDuration'
},
{
title: '浏览器信息',
dataIndex: 'browserInfo',
// 超出隐藏
ellipsis: true,
},
{
title: '扩展字段',
dataIndex: 'extraProperties',
},
];
useEffect(() => {
loadingData();
}, [input]);
async function loadingData() {
try {
const data = await RequestLog(input) as any;
setData(data.items);
setTotal(data.total);
} catch (error) {
Toast.error('加载失败' + error);
}
}
return (
<div>
<div style={{
display: 'flex',
marginBottom: '20px'
}}>
<Input
size='large'
placeholder="请输入搜索关键词"
value={input.keyword}
onChange={(e) => {
setInput({
...input,
keyword: e
})
}}
style={{
width: '200px',
marginRight: '20px',
}}
/>
<DatePicker
size='large'
placeholder="开始时间"
style={{
width: '200px',
marginRight: '20px',
}}
value={input.startTime}
onChange={(value) => {
setInput({
...input,
startTime: value
})
}}
/>
<DatePicker
size='large'
placeholder="结束时间"
style={{
width: '200px',
marginRight: '20px',
}}
value={input.endTime}
onChange={(value) => {
setInput({
...input,
endTime: value
})
}}
/>
<Button size='large' type="primary" block style={{ width: '100px' }}>搜索</Button>
</div>
<Table
sticky={{ top: 0 }} style={{
height: 'calc(100vh - 300px)',
overflow: 'auto',
padding: '10px',
}} columns={columns} dataSource={data} pagination={false} />
<Pagination total={total} style={{ marginBottom: 12 }} pageSize={input.pageSize} currentPage={input.page} onPageChange={(page) => {
setInput({
...input,
page: page
})
}} onPageSizeChange={(pageSize) => {
setInput({
...input,
pageSize: pageSize
})
}}></Pagination>
</div>
)
}
+4 -13
View File
@@ -7,7 +7,6 @@ import { getList ,update} from "../../service/SettingService";
export default function Setting() {
const [maxBodySize, setMaxBodySize] = useState(100);
const [maxLogDay, setMaxLogDay] = useState(30);
const LogRetentionTime = "Gateway:Setting:LogRetentionTime";
const maxRequestBodySize = "Gateway:Setting:MaxRequestBodySize";
@@ -18,16 +17,10 @@ export default function Setting() {
// 获取values的数组中你的name为maxRequestBodySize
const v1 = values.find((item: any) => item.name === maxRequestBodySize);
setMaxBodySize(v1.defaultValue);
const v2 = values.find((item: any) => item.name === LogRetentionTime);
setMaxLogDay(v2.defaultValue);
setMaxBodySize(v1?.defaultValue);
}
function save() {
update(LogRetentionTime, maxLogDay)
.then(() => {
Toast.success('保存成功')
})
update(maxRequestBodySize, maxBodySize)
.then(() => {
Toast.success('保存成功')
@@ -53,16 +46,14 @@ export default function Setting() {
fontWeight: 'bold',
marginBottom: '20px',
}}>
<span>
最大请求Body大小(MB)
</span>
<Input value={maxBodySize} onChange={(e) => {
setMaxBodySize(e as any)
}} size='large' style={{
marginTop: '20px',
}} placeholder='最大请求Body大小(MB)'></Input>
<Input size='large' max={360} min={10} value={maxLogDay} onChange={(e) => {
setMaxLogDay(e as any)
}} style={{
marginTop: '20px',
}} type="number" placeholder='日志保留最大天数'></Input>
<Button size='large' style={{
marginTop: '20px',
}} onClick={()=>save()} block>保存</Button>
-25
View File
@@ -1,25 +0,0 @@
import request from "../utils/request";
/***
* 获取请求日志列表
* @param hours {number} 时长(小时)
* @constructor
*/
export function Panel(hours:number){
return request.get("/api/gateway/panel",{
params:{
hours
}
});
}
/**
* 获取请求日志列表
* @param params
* @returns
*/
export function RequestLog(params:any){
return request.get("/api/gateway/request-log",{
params
});
}