From 1fde2d642a61c258779edc2d5f8d499ceb34acf8 Mon Sep 17 00:00:00 2001 From: token <239573049@qq.com> Date: Wed, 31 Jan 2024 17:05:45 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=AF=8F=E5=A4=A9?= =?UTF-8?q?=E7=9A=84=E8=AF=B7=E6=B1=82=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BackgroundServices/GatewayBackground.cs | 43 ++++++++++++++++++- src/Gateway/Dto/NetWorkDto.cs | 32 ++++++++++++++ src/Gateway/Entities/SystemLoggerEntity.cs | 21 +++++++++ src/Gateway/Middlewares/GatewayMiddleware.cs | 32 ++++++++++++++ src/Gateway/Program.cs | 13 +++--- src/Gateway/Services/SystemService.cs | 26 +++++++---- web/src/pages/home/index.tsx | 37 +++++++++++++++- 7 files changed, 187 insertions(+), 17 deletions(-) create mode 100644 src/Gateway/Entities/SystemLoggerEntity.cs diff --git a/src/Gateway/BackgroundServices/GatewayBackground.cs b/src/Gateway/BackgroundServices/GatewayBackground.cs index adc450c..cbc9afa 100644 --- a/src/Gateway/BackgroundServices/GatewayBackground.cs +++ b/src/Gateway/BackgroundServices/GatewayBackground.cs @@ -9,10 +9,51 @@ public class GatewayBackgroundService( { // 数据库迁移 freeSql.CodeFirst.SyncStructure(typeof(RouteEntity), typeof(ClusterEntity), typeof(CertificateEntity), - typeof(StaticFileProxyEntity)); + typeof(StaticFileProxyEntity), typeof(SystemLoggerEntity)); // 首次启动时更新配置 await gatewayService.RefreshConfig(); await certificateService.RefreshConfig(); + + while (stoppingToken.IsCancellationRequested == false) + { + // 获取当前时间距离23:59:59剩余多少秒,然后等待这么多秒 + var seconds = (DateTime.Now.Date.AddDays(1) - DateTime.Now).TotalSeconds; + + // Task.Delay不能是负数 + if (seconds < 0) + { + seconds = 1000; + } + + #region 等待第二天凌晨 + + // 如果服务手动被关闭,则先统计当天流量记录。 + try + { + await Task.Delay(TimeSpan.FromSeconds(seconds), stoppingToken); + + // 停止一秒防止时间计算错误 + await Task.Delay(1000, stoppingToken); + } + catch + { + } + + #endregion + + var systemLoggerEntity = new SystemLoggerEntity + { + RequestCount = GatewayMiddleware.CurrentRequestCount, + ErrorRequestCount = GatewayMiddleware.CurrentErrorCount, + CurrentTime = DateTime.Now.AddDays(-1) + }; + + await freeSql.Insert(systemLoggerEntity).ExecuteAffrowsAsync(); + + // 清空请求计数器 + GatewayMiddleware.ClearRequestCount(); + + } } } \ No newline at end of file diff --git a/src/Gateway/Dto/NetWorkDto.cs b/src/Gateway/Dto/NetWorkDto.cs index 9d3b531..a0fdc69 100644 --- a/src/Gateway/Dto/NetWorkDto.cs +++ b/src/Gateway/Dto/NetWorkDto.cs @@ -28,4 +28,36 @@ public class NetWorkDto(long received, long sent) /// 当前时间 /// public string Time => DateTime.Now.ToString("HH:mm:ss"); + + /// + /// 当天请求数量 + /// + public int CurrentRequestCount { get; set; } = GatewayMiddleware.CurrentRequestCount; + + /// + /// 当天错误数量 + /// + public int CurrentErrorCount { get; set; } = GatewayMiddleware.CurrentErrorCount; + + private double _totalRequestCount; + + /// + /// 当天错误率 + /// + public double TotalRequestCount + { + get => _totalRequestCount + CurrentRequestCount; + set => _totalRequestCount = value; + } + + private double _totalErrorCount; + + /// + /// 总错误数量 + /// + public double TotalErrorCount + { + get => _totalErrorCount + CurrentErrorCount; + set => value = _totalErrorCount; + } } \ No newline at end of file diff --git a/src/Gateway/Entities/SystemLoggerEntity.cs b/src/Gateway/Entities/SystemLoggerEntity.cs new file mode 100644 index 0000000..89ad2ec --- /dev/null +++ b/src/Gateway/Entities/SystemLoggerEntity.cs @@ -0,0 +1,21 @@ +namespace Gateway.Entities; + +public sealed class SystemLoggerEntity : Entity +{ + /// + /// 请求数量 + /// + public int RequestCount { get; set; } + + /// + /// 异常数量 + /// + public int ErrorRequestCount { get; set; } + + /// + /// 当前时间 + /// + public DateTime CurrentTime { get; set; } + + +} \ No newline at end of file diff --git a/src/Gateway/Middlewares/GatewayMiddleware.cs b/src/Gateway/Middlewares/GatewayMiddleware.cs index 966ff75..46a39fe 100644 --- a/src/Gateway/Middlewares/GatewayMiddleware.cs +++ b/src/Gateway/Middlewares/GatewayMiddleware.cs @@ -2,6 +2,26 @@ public class GatewayMiddleware : IMiddleware { + /// + /// 请求计数器 + /// + private static int _currentRequestCount; + + /// + /// 异常计数器 + /// + private static int _currentErrorCount; + + public static int CurrentRequestCount => _currentRequestCount; + + public static int CurrentErrorCount => _currentErrorCount; + + public static void ClearRequestCount() + { + Interlocked.Exchange(ref _currentRequestCount, 0); + Interlocked.Exchange(ref _currentErrorCount, 0); + } + public async Task InvokeAsync(HttpContext context, RequestDelegate next) { // TODO: 由于h3需要对应请求的端口,所以这里需要动态设置 @@ -14,6 +34,18 @@ public class GatewayMiddleware : IMiddleware context.Response.Headers["Gateway-Version"] = GatewayOptions.Version; + // Gateway默认的请求不记录 + var record = context.Request.Path.Value?.StartsWith("/api/gateway/") == false; + + // 使用原子操作,防止并发问题 + if (record) + Interlocked.Increment(ref _currentRequestCount); + await next(context); + + if (record && context.Response.StatusCode >= 400) + { + Interlocked.Increment(ref _currentErrorCount); + } } } \ No newline at end of file diff --git a/src/Gateway/Program.cs b/src/Gateway/Program.cs index c50e208..199f3c7 100644 --- a/src/Gateway/Program.cs +++ b/src/Gateway/Program.cs @@ -28,8 +28,8 @@ builder.Configuration.GetSection(GatewayOptions.Name) .Get(); // 获取环境变量 -var https_password = Environment.GetEnvironmentVariable("HTTPS_PASSWORD") ?? "dd666666"; -var https_file = Environment.GetEnvironmentVariable("HTTPS_FILE") ?? "gateway.pfx"; +var httpsPassword = Environment.GetEnvironmentVariable("HTTPS_PASSWORD") ?? "dd666666"; +var httpsFile = Environment.GetEnvironmentVariable("HTTPS_FILE") ?? "gateway.pfx"; builder.WebHost.UseKestrel(options => { @@ -43,8 +43,8 @@ builder.WebHost.UseKestrel(options => !CertificateService.CertificateEntityDict.TryGetValue(name, out var certificate)) { // 创建一个默认的证书 - return new X509Certificate2(Path.Combine(AppContext.BaseDirectory, "certificates", https_file), - https_password); + return new X509Certificate2(Path.Combine(AppContext.BaseDirectory, "certificates", httpsFile), + httpsPassword); } var path = Path.Combine("/data/", certificate.Path); @@ -55,8 +55,8 @@ builder.WebHost.UseKestrel(options => Console.WriteLine($"证书文件不存在:{path}"); Console.ResetColor(); - return new X509Certificate2(Path.Combine(AppContext.BaseDirectory, "certificates", https_file), - https_password); + return new X509Certificate2(Path.Combine(AppContext.BaseDirectory, "certificates", httpsFile), + httpsPassword); }; }); }); @@ -69,6 +69,7 @@ builder.WebHost.ConfigureKestrel(kestrel => { portOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3; portOptions.UseHttps(); + }); kestrel.ListenAnyIP(8080, portOptions => { portOptions.Protocols = HttpProtocols.Http1AndHttp2; }); diff --git a/src/Gateway/Services/SystemService.cs b/src/Gateway/Services/SystemService.cs index 830edf9..ad2cea3 100644 --- a/src/Gateway/Services/SystemService.cs +++ b/src/Gateway/Services/SystemService.cs @@ -1,14 +1,20 @@ namespace Gateway.Services; -public class SystemService +/// +/// 系统服务 +/// +public static class SystemService { - public static async Task StreamAsync(HttpContext context) + public static async Task StreamAsync(HttpContext context, IFreeSql sql) { // 使用sse,返回响应头 context.Response.Headers.ContentType = "text/event-stream"; var i = 0; + var totalErrorCount = (double)await sql.Select().SumAsync(x => x.ErrorRequestCount); + var totalRequestCount = (double)await sql.Select().SumAsync(x => x.RequestCount); + while (!context.RequestAborted.IsCancellationRequested) { // 获取所有网络接口 @@ -27,7 +33,7 @@ public class SystemService initialBytesSent += interfaceStats.BytesSent; initialBytesReceived += interfaceStats.BytesReceived; } - + // 等待1秒钟 await Task.Delay(1000, context.RequestAborted); @@ -50,7 +56,11 @@ public class SystemService var totalBytesReceivedIn1Sec = bytesReceivedAfter1Sec - initialBytesReceived; var data = - $"data:{JsonSerializer.Serialize(new NetWorkDto(totalBytesReceivedIn1Sec, totalBytesSentIn1Sec))}\n\n"; + $"data:{JsonSerializer.Serialize(new NetWorkDto(totalBytesReceivedIn1Sec, totalBytesSentIn1Sec) + { + TotalErrorCount = totalErrorCount, + TotalRequestCount = totalRequestCount + })}\n\n"; // 将数据写入到响应流中 await context.Response.WriteAsync(data, context.RequestAborted); @@ -58,8 +68,8 @@ public class SystemService i++; - // 只维持5秒的连接 - if (i > 5) + // 只维持10秒的连接 + if (i > 10) { break; } @@ -71,7 +81,7 @@ public static class SystemExtension { public static void MapSystem(this IEndpointRouteBuilder app) { - app.MapGet("/api/gateway/system", async context => - await SystemService.StreamAsync(context)); + app.MapGet("/api/gateway/system", async (HttpContext context, IFreeSql sql) => + await SystemService.StreamAsync(context, sql)); } } \ No newline at end of file diff --git a/web/src/pages/home/index.tsx b/web/src/pages/home/index.tsx index 8f4a4a8..88de3ba 100644 --- a/web/src/pages/home/index.tsx +++ b/web/src/pages/home/index.tsx @@ -1,9 +1,14 @@ import { useEffect, useState } from "react"; -import { Col, Row } from '@douyinfe/semi-ui'; +import { Card, Col, Row } from '@douyinfe/semi-ui'; import { stream } from '../../service/NetWorkService'; import * as echarts from 'echarts'; export default function Home() { + const [totalRequestCount, setTotalRequestCount] = useState(0); + const [totalErrorCount, setTotalErrorCount] = useState(0); + const [currentRequestCount, setCurrentRequestCount] = useState(0); + const [currentErrorCount, setCurrentErrorCount] = useState(0); + useEffect(() => { var chartDom = document.getElementById('network')!; var myChart = echarts.init(chartDom); @@ -124,6 +129,12 @@ export default function Home() { option.xAxis.data.push(chunk.Time); option.series[0].data.push(chunk.Sent); option.series[1].data.push(chunk.Received); + + setCurrentErrorCount(chunk.CurrentErrorCount); + setCurrentRequestCount(chunk.CurrentRequestCount); + setTotalErrorCount(chunk.TotalErrorCount); + setTotalRequestCount(chunk.TotalRequestCount); + option && myChart.setOption(option); myChart.resize(); @@ -137,7 +148,7 @@ export default function Home() { fetchData(); // 设置定时器,每隔一段时间调用获取数据的函数 - const intervalId = setInterval(fetchData, 5900); // 每5秒获取一次数据 + const intervalId = setInterval(fetchData, 10900); // 每5秒获取一次数据 // 组件卸载时清除定时器 return () => { @@ -158,6 +169,28 @@ export default function Home() { }}> 数据面板 + + + + 总请求数:{totalRequestCount} + + + + + 总错误数:{totalErrorCount} + + + + + 当天请求数:{currentRequestCount} + + + + + 当天错误数:{currentErrorCount} + + +
Date: Wed, 31 Jan 2024 17:11:57 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B8=85=E7=A9=BA?= =?UTF-8?q?=E8=AE=A1=E6=95=B0=E5=99=A8=E6=89=A7=E8=A1=8C=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Gateway/BackgroundServices/GatewayBackground.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Gateway/BackgroundServices/GatewayBackground.cs b/src/Gateway/BackgroundServices/GatewayBackground.cs index cbc9afa..4db3a71 100644 --- a/src/Gateway/BackgroundServices/GatewayBackground.cs +++ b/src/Gateway/BackgroundServices/GatewayBackground.cs @@ -48,12 +48,11 @@ public class GatewayBackgroundService( ErrorRequestCount = GatewayMiddleware.CurrentErrorCount, CurrentTime = DateTime.Now.AddDays(-1) }; - - await freeSql.Insert(systemLoggerEntity).ExecuteAffrowsAsync(); - + // 清空请求计数器 GatewayMiddleware.ClearRequestCount(); - + + await freeSql.Insert(systemLoggerEntity).ExecuteAffrowsAsync(); } } } \ No newline at end of file -- Gitee