增加日志
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
using Serilog;
|
using Serilog;
|
||||||
|
using Serilog.Enrichers.Span; // Nuget: Serilog.Enrichers.Span
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
using Serilog.Exceptions; // Nuget: Serilog.Exceptions
|
using Serilog.Exceptions; // Nuget: Serilog.Exceptions
|
||||||
using Serilog.Enrichers.Span; // Nuget: Serilog.Enrichers.Span
|
using Serilog.Exceptions.Core;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -61,11 +62,19 @@ namespace Ayay.SerilogLogs
|
|||||||
|
|
||||||
// 2.3 注入全套元数据 (Enrichers) - 让日志更聪明
|
// 2.3 注入全套元数据 (Enrichers) - 让日志更聪明
|
||||||
builder
|
builder
|
||||||
|
// 注入全套元数据 (Enrichers) - 让日志更聪明
|
||||||
.Enrich.FromLogContext() // 允许使用 .ForContext() 注入上下文
|
.Enrich.FromLogContext() // 允许使用 .ForContext() 注入上下文
|
||||||
.Enrich.WithProperty("AppId", opts.AppId) // 注入应用标识
|
.Enrich.WithProperty("AppId", opts.AppId) // 注入应用标识
|
||||||
|
.Enrich.WithProperty("PcCode", opts.PcCode) // 注入应用标识
|
||||||
|
.Enrich.WithMachineName() // [环境] 区分是哪台工控机 (建议加上)
|
||||||
.Enrich.WithThreadId() // 线程ID
|
.Enrich.WithThreadId() // 线程ID
|
||||||
.Enrich.WithProcessId() // 进程ID (用于识别重启)
|
.Enrich.WithProcessId() // 进程ID (用于识别重启)
|
||||||
.Enrich.WithExceptionDetails() // 结构化异常堆栈
|
.Enrich.WithExceptionDetails() // 结构化异常堆栈
|
||||||
|
// [异常] 结构化异常拆解 (非常强大)
|
||||||
|
// 它能把 ex.Data 和 InnerException 自动转成 JSON,而不是单纯的一堆字符串
|
||||||
|
.Enrich.WithExceptionDetails(new DestructuringOptionsBuilder()
|
||||||
|
.WithDefaultDestructurers())
|
||||||
|
//.WithDestructurers(new[] { new SqlExceptionDestructurer() })) // 如果有数据库操作,这行很关键
|
||||||
.Enrich.WithSpan(); // 全链路追踪 ID
|
.Enrich.WithSpan(); // 全链路追踪 ID
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
|
|||||||
@@ -7,22 +7,24 @@
|
|||||||
public static class LogModules
|
public static class LogModules
|
||||||
{
|
{
|
||||||
// --- 核心架构层 ---
|
// --- 核心架构层 ---
|
||||||
public const string Core = "Core"; // 系统主逻辑/启动关闭
|
public static string Core { get; } = "Core"; // 系统主逻辑/启动关闭
|
||||||
public const string Network = "Network"; // 底层网络通讯 (TCP/UDP)
|
public static string Network { get; } = "Network"; // 底层网络通讯 (TCP/UDP)
|
||||||
public const string WebApi = "WebAPI"; // 对外 HTTP 接口
|
public static string WebApi { get; } = "WebAPI"; // 对外 HTTP 接口
|
||||||
public const string WebSocket = "WebSocket"; // 实时通讯
|
public static string gRpc { get; } = "gRPC"; // 对外 gRPC 接口
|
||||||
public const string Ping = "Ping"; // 心跳/Ping包 (通常量大且不重要)
|
|
||||||
|
public static string WebSocket { get; } = "WebSocket"; // 实时通讯
|
||||||
|
public static string Ping { get; } = "Ping"; // 心跳/Ping包 (通常量大且不重要)
|
||||||
|
|
||||||
// --- 业务逻辑层 ---
|
// --- 业务逻辑层 ---
|
||||||
public const string UserSystem = "UserSystem"; // 用户账户/权限系统
|
public static string UserSystem { get; } = "UserSystem"; // 用户账户/权限系统
|
||||||
public const string UserAction = "UserAction"; // 用户操作行为 (审计日志)
|
public static string UserAction { get; } = "UserAction"; // 用户操作行为 (审计日志)
|
||||||
public const string DeviceOps = "DeviceOps"; // 设备运行/控制指令
|
public static string DeviceOps { get; } = "DeviceOps"; // 设备运行/控制指令
|
||||||
|
|
||||||
// --- 核心算法层 ---
|
// --- 核心算法层 ---
|
||||||
public const string Algorithm = "Algorithm"; // 算法分析/AI识别 (需要上下文追踪)
|
public static string Algorithm { get; } = "Algorithm"; // 算法分析/AI识别 (需要上下文追踪)
|
||||||
public const string Observation = "Observation"; // 观察点/埋点 (用于调试或统计)
|
public static string Observation { get; } = "Observation"; // 观察点/埋点 (用于调试或统计)
|
||||||
|
|
||||||
// --- 第三方集成 ---
|
// --- 第三方集成 ---
|
||||||
public const string Sdk = "SDK"; // 第三方 SDK 调用封装
|
public static string HikVisionSdk { get; } = "HikVisionSdk"; // 第三方 SDK 调用封装
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,6 +50,11 @@ namespace Ayay.SerilogLogs
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string SeqApiKey { get; set; }
|
public string SeqApiKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 机器码
|
||||||
|
/// </summary>
|
||||||
|
public string PcCode { get; set; }
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
// 4. 输出端级别控制 (Sink Levels)
|
// 4. 输出端级别控制 (Sink Levels)
|
||||||
// 用于控制不同媒介的“过滤网”疏密程度
|
// 用于控制不同媒介的“过滤网”疏密程度
|
||||||
@@ -97,6 +102,7 @@ namespace Ayay.SerilogLogs
|
|||||||
{ LogModules.Core, LogEventLevel.Debug }, // 系统主逻辑
|
{ LogModules.Core, LogEventLevel.Debug }, // 系统主逻辑
|
||||||
{ LogModules.Network, LogEventLevel.Debug }, // 网络通讯:平时只看警告,防止心跳刷屏
|
{ LogModules.Network, LogEventLevel.Debug }, // 网络通讯:平时只看警告,防止心跳刷屏
|
||||||
{ LogModules.WebApi, LogEventLevel.Debug }, // WebAPI:记录请求响应
|
{ LogModules.WebApi, LogEventLevel.Debug }, // WebAPI:记录请求响应
|
||||||
|
{ LogModules.gRpc, LogEventLevel.Debug }, // gRpc:记录请求响应
|
||||||
|
|
||||||
// --- 业务层 ---
|
// --- 业务层 ---
|
||||||
{ LogModules.UserSystem, LogEventLevel.Debug }, // 用户系统
|
{ LogModules.UserSystem, LogEventLevel.Debug }, // 用户系统
|
||||||
@@ -110,7 +116,7 @@ namespace Ayay.SerilogLogs
|
|||||||
// --- 降噪区 (垃圾数据屏蔽) ---
|
// --- 降噪区 (垃圾数据屏蔽) ---
|
||||||
{ LogModules.WebSocket, LogEventLevel.Debug }, // WS:数据量极大,除非报错否则不记
|
{ LogModules.WebSocket, LogEventLevel.Debug }, // WS:数据量极大,除非报错否则不记
|
||||||
{ LogModules.Ping, LogEventLevel.Debug }, // Ping:几乎不记,除非完全断连
|
{ LogModules.Ping, LogEventLevel.Debug }, // Ping:几乎不记,除非完全断连
|
||||||
{ LogModules.Sdk, LogEventLevel.Debug } // SDK:屏蔽第三方的废话日志
|
{ LogModules.HikVisionSdk, LogEventLevel.Debug } // SDK:屏蔽第三方的废话日志
|
||||||
};
|
};
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using OpenCvSharp;
|
using Ayay.SerilogLogs;
|
||||||
|
using OpenCvSharp;
|
||||||
|
using Serilog;
|
||||||
using SHH.CameraSdk.HikFeatures;
|
using SHH.CameraSdk.HikFeatures;
|
||||||
using System.Runtime.ExceptionServices;
|
using System.Runtime.ExceptionServices;
|
||||||
using System.Security;
|
using System.Security;
|
||||||
@@ -17,6 +19,8 @@ public class HikVideoSource : BaseVideoSource,
|
|||||||
{
|
{
|
||||||
#region --- 静态资源 (Global Resources) ---
|
#region --- 静态资源 (Global Resources) ---
|
||||||
|
|
||||||
|
// 日志实例
|
||||||
|
private static ILogger _sdkLog = Log.ForContext("SourceContext", LogModules.HikVisionSdk);
|
||||||
// 静态路由表
|
// 静态路由表
|
||||||
private static readonly ConcurrentDictionary<int, HikVideoSource> _instances = new();
|
private static readonly ConcurrentDictionary<int, HikVideoSource> _instances = new();
|
||||||
// 全局异常回调
|
// 全局异常回调
|
||||||
@@ -103,14 +107,18 @@ public class HikVideoSource : BaseVideoSource,
|
|||||||
if (currentEpoch != _connectionEpoch) return;
|
if (currentEpoch != _connectionEpoch) return;
|
||||||
|
|
||||||
if (!HikSdkManager.Initialize())
|
if (!HikSdkManager.Initialize())
|
||||||
throw new CameraException(CameraErrorCode.SdkNotInitialized, "SDK初始化失败", DeviceBrand.HikVision);
|
{
|
||||||
|
_sdkLog.Error("HikVision Sdk 初始化失败.");
|
||||||
|
throw new CameraException(CameraErrorCode.SdkNotInitialized, "HikVision Sdk 初始化失败.", DeviceBrand.HikVision);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HikNativeMethods.NET_DVR_SetExceptionCallBack_V30(0, IntPtr.Zero, _globalExceptionCallback, IntPtr.Zero);
|
HikNativeMethods.NET_DVR_SetExceptionCallBack_V30(0, IntPtr.Zero, _globalExceptionCallback, IntPtr.Zero);
|
||||||
|
|
||||||
// [审计] 记录登录动作
|
// [审计] 记录登录动作
|
||||||
AddAuditLog($"正在执行物理登录... ({_config.IpAddress})");
|
AddAuditLog($"Hik 正在执行登录 => ID:{_config.Id} IP:{_config.IpAddress} Port:{_config.Port} Name:{_config.Name}");
|
||||||
|
_sdkLog.Information($"Hik 正在执行登录 => ID:{_config.Id} IP:{_config.IpAddress} Port:{_config.Port} Name:{_config.Name}");
|
||||||
|
|
||||||
var devInfo = new HikNativeMethods.NET_DEVICEINFO_V30();
|
var devInfo = new HikNativeMethods.NET_DEVICEINFO_V30();
|
||||||
int newUserId = HikNativeMethods.NET_DVR_Login_V30(
|
int newUserId = HikNativeMethods.NET_DVR_Login_V30(
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
using System.Net.Sockets;
|
using Ayay.SerilogLogs;
|
||||||
using System.Net;
|
|
||||||
using Ayay.SerilogLogs;
|
|
||||||
using Grpc.Net.Client;
|
using Grpc.Net.Client;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using SHH.CameraSdk;
|
using SHH.CameraSdk;
|
||||||
using SHH.Contracts.Grpc;
|
using SHH.Contracts.Grpc;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace SHH.CameraService;
|
namespace SHH.CameraService;
|
||||||
|
|
||||||
@@ -37,8 +38,8 @@ public static class Bootstrapper
|
|||||||
"--uris", "localhost,9001,command,调试PC;",
|
"--uris", "localhost,9001,command,调试PC;",
|
||||||
|
|
||||||
// 日志中心配置 (格式: IP,Port,Desc)
|
// 日志中心配置 (格式: IP,Port,Desc)
|
||||||
"--sequris", "172.16.41.241,20026,日志处置中心;",
|
"--sequris", "58.216.225.5,20026,日志处置中心;",
|
||||||
"--seqkey", "Shine899195994250;",
|
"--seqkey", "Shine101173874928;",
|
||||||
|
|
||||||
// 端口策略
|
// 端口策略
|
||||||
"--mode", "1",
|
"--mode", "1",
|
||||||
@@ -48,6 +49,7 @@ public static class Bootstrapper
|
|||||||
|
|
||||||
var config = ServiceConfig.BuildFromArgs(args);
|
var config = ServiceConfig.BuildFromArgs(args);
|
||||||
|
|
||||||
|
string pcCode = config.SeqApiKey.Replace("Shine", "");
|
||||||
var ops = new LogOptions
|
var ops = new LogOptions
|
||||||
{
|
{
|
||||||
AppId = config.AppId,
|
AppId = config.AppId,
|
||||||
@@ -56,6 +58,7 @@ public static class Bootstrapper
|
|||||||
// ★这里改为从 config 读取,如果没配则留空或给个默认值
|
// ★这里改为从 config 读取,如果没配则留空或给个默认值
|
||||||
SeqServerUrl = config.SeqServerUrl,
|
SeqServerUrl = config.SeqServerUrl,
|
||||||
SeqApiKey = config.SeqApiKey,
|
SeqApiKey = config.SeqApiKey,
|
||||||
|
PcCode = Regex.Replace(pcCode, ".{3}", "$0-").TrimEnd('-'),
|
||||||
|
|
||||||
MaxRetentionDays = 10,
|
MaxRetentionDays = 10,
|
||||||
FileSizeLimitBytes = 1024L * 1024 * 1024,
|
FileSizeLimitBytes = 1024L * 1024 * 1024,
|
||||||
@@ -234,9 +237,10 @@ public static class Bootstrapper
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 向网关注册实例
|
/// 向网关注册实例
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static async Task RegisterToGatewayAsync(ServiceConfig config, ILogger logger)
|
public static async Task RegisterToGatewayAsync(ServiceConfig config)
|
||||||
{
|
{
|
||||||
if (!config.CommandEndpoints.Any()) return;
|
if (!config.CommandEndpoints.Any()) return;
|
||||||
|
var gRpcLog = Log.ForContext("SourceContext", LogModules.gRpc);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -246,7 +250,7 @@ public static class Bootstrapper
|
|||||||
using var channel = GrpcChannel.ForAddress(targetUrl);
|
using var channel = GrpcChannel.ForAddress(targetUrl);
|
||||||
var client = new GatewayProvider.GatewayProviderClient(channel);
|
var client = new GatewayProvider.GatewayProviderClient(channel);
|
||||||
|
|
||||||
logger.Information($"[Grpc] 正在执行预注册: {targetUrl}");
|
gRpcLog.Information($"[gRPC] 正在执行预注册: {targetUrl}");
|
||||||
var resp = await client.RegisterInstanceAsync(new RegisterRequest
|
var resp = await client.RegisterInstanceAsync(new RegisterRequest
|
||||||
{
|
{
|
||||||
InstanceId = config.AppId,
|
InstanceId = config.AppId,
|
||||||
@@ -257,11 +261,11 @@ public static class Bootstrapper
|
|||||||
ProcessId = Environment.ProcessId,
|
ProcessId = Environment.ProcessId,
|
||||||
Description = ""
|
Description = ""
|
||||||
});
|
});
|
||||||
logger.Information($"💡[Grpc] 预注册成功: {resp.Message}");
|
gRpcLog.Information($"💡[gRPC] 预注册成功: {resp.Message}");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.Error($"⚠️ [Grpc] 预注册尝试失败: {ex.Message}");
|
gRpcLog.Error($"⚠️ [gRPC] 预注册尝试失败: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
using Microsoft.Extensions.Hosting;
|
using Ayay.SerilogLogs;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Serilog;
|
||||||
using SHH.CameraSdk;
|
using SHH.CameraSdk;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设备管理服务引擎 Worker
|
||||||
|
/// </summary>
|
||||||
public class CameraEngineWorker : BackgroundService
|
public class CameraEngineWorker : BackgroundService
|
||||||
{
|
{
|
||||||
private readonly CameraManager _manager;
|
private readonly CameraManager _manager;
|
||||||
@@ -13,17 +18,18 @@ public class CameraEngineWorker : BackgroundService
|
|||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
Console.WriteLine("[Engine] 正在启动核心引擎...");
|
var sysLog = Log.ForContext("SourceContext", LogModules.Core);
|
||||||
|
sysLog.Information("[Engine] 正在启动设备管理服务引擎...");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 1. 理由:启动 SDK 内部加载流程(从本地存储恢复设备)
|
// 1. 理由:启动 SDK 内部加载流程(从本地存储恢复设备)
|
||||||
await _manager.StartAsync();
|
await _manager.StartAsync();
|
||||||
Console.WriteLine("[Engine] 设备管理服务已启动。");
|
sysLog.Warning("[Engine] 设备管理服务引擎已启动...");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"[Engine] 严重启动异常: {ex.Message}");
|
sysLog.Error($"[Engine] 设备管理服务引擎启动异常: {ex.Message}");
|
||||||
return; // 理由:核心组件失败,终止后续逻辑
|
return; // 理由:核心组件失败,终止后续逻辑
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,14 +37,15 @@ public class CameraEngineWorker : BackgroundService
|
|||||||
while (!stoppingToken.IsCancellationRequested)
|
while (!stoppingToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
// 你可以在这里定期输出一些状态统计
|
// 你可以在这里定期输出一些状态统计
|
||||||
// Console.WriteLine($"[Engine] 活跃设备数: {_manager.GetActiveCount()}");
|
sysLog.Debug($"[Engine] 管理设备数: {_manager.GetAllCameras().Count()}");
|
||||||
await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
|
await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task StopAsync(CancellationToken cancellationToken)
|
public override async Task StopAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
Console.WriteLine("[Engine] 正在执行优雅停机...");
|
var sysLog = Log.ForContext("SourceContext", LogModules.Core);
|
||||||
|
sysLog.Debug($"[Engine] 正在执行优雅停机: {_manager.GetAllCameras()}");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 理由:这是重构的核心。必须在 SDK 退出前释放所有非托管句柄
|
// 理由:这是重构的核心。必须在 SDK 退出前释放所有非托管句柄
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Newtonsoft.Json.Linq;
|
using Ayay.SerilogLogs;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using Serilog;
|
||||||
using SHH.Contracts.Grpc;
|
using SHH.Contracts.Grpc;
|
||||||
|
|
||||||
namespace SHH.CameraService;
|
namespace SHH.CameraService;
|
||||||
@@ -9,6 +11,7 @@ namespace SHH.CameraService;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class CommandDispatcher
|
public class CommandDispatcher
|
||||||
{
|
{
|
||||||
|
private static ILogger _gRpcLog = Log.ForContext("SourceContext", LogModules.gRpc);
|
||||||
private readonly Dictionary<string, ICommandHandler> _handlers;
|
private readonly Dictionary<string, ICommandHandler> _handlers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -32,7 +35,8 @@ public class CommandDispatcher
|
|||||||
if (protoMsg == null) return;
|
if (protoMsg == null) return;
|
||||||
|
|
||||||
string cmdCode = protoMsg.CmdCode; // 例如 "Sync_Camera"
|
string cmdCode = protoMsg.CmdCode; // 例如 "Sync_Camera"
|
||||||
Console.WriteLine($"[Dispatcher] 收到远程指令: {cmdCode}, 请求ID: {protoMsg.RequestId}");
|
_gRpcLog.Information($"[gRPC] 响应请求, 业务:{protoMsg.CmdCode}, 请求ID:{protoMsg.RequestId}, 业务分发.");
|
||||||
|
_gRpcLog.Debug($"[gRPC] 响应请求, {protoMsg.CmdCode}, 请求ID:{protoMsg.RequestId}, 业务分发 => {protoMsg}");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -47,16 +51,16 @@ public class CommandDispatcher
|
|||||||
// 3. 调用具体业务执行
|
// 3. 调用具体业务执行
|
||||||
await handler.ExecuteAsync(token);
|
await handler.ExecuteAsync(token);
|
||||||
|
|
||||||
Console.WriteLine($"[Dispatcher] 指令 {cmdCode} 执行成功。");
|
_gRpcLog.Information($"[gRPC] 业务:{protoMsg.CmdCode}, 请求ID:{protoMsg.RequestId}, 执行成功.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine($"[Dispatcher Warning] 未找到指令处理器: {cmdCode}");
|
_gRpcLog.Warning($"[gRPC] 业务:{protoMsg.CmdCode}, 请求ID:{protoMsg.RequestId}, 未找到指令处理器.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"[Dispatcher Error] 执行指令 {cmdCode} 异常: {ex.Message}");
|
_gRpcLog.Error($"[gRPC] 业务:{protoMsg.CmdCode}, 请求ID:{protoMsg.RequestId}, 执行指令处理异常: {ex.Message}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注意:关于 ACK (require_ack)
|
// 注意:关于 ACK (require_ack)
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Newtonsoft.Json.Linq;
|
using Ayay.SerilogLogs;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using Serilog;
|
||||||
using SHH.CameraSdk;
|
using SHH.CameraSdk;
|
||||||
using SHH.Contracts;
|
using SHH.Contracts;
|
||||||
|
|
||||||
@@ -9,6 +11,7 @@ namespace SHH.CameraService;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class DeviceConfigHandler : ICommandHandler
|
public class DeviceConfigHandler : ICommandHandler
|
||||||
{
|
{
|
||||||
|
private static ILogger _sysLog = Log.ForContext("SourceContext", LogModules.Core);
|
||||||
private readonly CameraManager _cameraManager;
|
private readonly CameraManager _cameraManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using Grpc.Core;
|
using Ayay.SerilogLogs;
|
||||||
|
using Grpc.Core;
|
||||||
using Grpc.Net.Client;
|
using Grpc.Net.Client;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Serilog;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using SHH.CameraSdk;
|
using SHH.CameraSdk;
|
||||||
using SHH.Contracts.Grpc; // 引用 Proto 生成的命名空间
|
using SHH.Contracts.Grpc; // 引用 Proto 生成的命名空间
|
||||||
|
|
||||||
@@ -17,24 +17,23 @@ namespace SHH.CameraService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class GatewayService : BackgroundService
|
public class GatewayService : BackgroundService
|
||||||
{
|
{
|
||||||
private readonly ILogger<GatewayService> _logger;
|
|
||||||
private readonly ServiceConfig _config;
|
private readonly ServiceConfig _config;
|
||||||
private readonly CommandDispatcher _dispatcher;
|
private readonly CommandDispatcher _dispatcher;
|
||||||
|
|
||||||
public GatewayService(
|
public GatewayService(
|
||||||
ILogger<GatewayService> logger,
|
|
||||||
ServiceConfig config,
|
ServiceConfig config,
|
||||||
CommandDispatcher dispatcher)
|
CommandDispatcher dispatcher)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
|
||||||
_config = config;
|
_config = config;
|
||||||
_dispatcher = dispatcher;
|
_dispatcher = dispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
|
var gRpcLog = Log.ForContext("SourceContext", LogModules.gRpc);
|
||||||
|
|
||||||
// 预留系统启动缓冲时间,确保数据库和 SDK 已就绪
|
// 预留系统启动缓冲时间,确保数据库和 SDK 已就绪
|
||||||
_logger.LogInformation("[gRPC Bus] 指令接收服务启动,等待环境预热...");
|
gRpcLog.Information("[gRPC] 指令接收服务启动,等待环境预热...");
|
||||||
await Task.Delay(3000, stoppingToken);
|
await Task.Delay(3000, stoppingToken);
|
||||||
|
|
||||||
while (!stoppingToken.IsCancellationRequested)
|
while (!stoppingToken.IsCancellationRequested)
|
||||||
@@ -49,7 +48,7 @@ namespace SHH.CameraService
|
|||||||
var client = new GatewayProvider.GatewayProviderClient(channel);
|
var client = new GatewayProvider.GatewayProviderClient(channel);
|
||||||
|
|
||||||
// --- 第一步:发起节点逻辑注册 (Unary) ---
|
// --- 第一步:发起节点逻辑注册 (Unary) ---
|
||||||
_logger.LogInformation("[gRPC Bus] 正在发起逻辑注册: {Url}", targetUrl);
|
gRpcLog.Information("[gRPC] 正在发起逻辑注册: {Url}", targetUrl);
|
||||||
var regResp = await client.RegisterInstanceAsync(new RegisterRequest
|
var regResp = await client.RegisterInstanceAsync(new RegisterRequest
|
||||||
{
|
{
|
||||||
InstanceId = _config.AppId,
|
InstanceId = _config.AppId,
|
||||||
@@ -60,7 +59,7 @@ namespace SHH.CameraService
|
|||||||
|
|
||||||
if (regResp.Success)
|
if (regResp.Success)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("[gRPC Bus] 注册成功。正在建立双向指令通道...");
|
gRpcLog.Information("[gRPC] 注册成功, 正在建立双向指令通道...");
|
||||||
|
|
||||||
// --- 第二步:开启 Server Streaming 指令流 ---
|
// --- 第二步:开启 Server Streaming 指令流 ---
|
||||||
using var call = client.OpenCommandChannel(new CommandStreamRequest
|
using var call = client.OpenCommandChannel(new CommandStreamRequest
|
||||||
@@ -87,13 +86,14 @@ namespace SHH.CameraService
|
|||||||
}
|
}
|
||||||
catch (RpcException ex)
|
catch (RpcException ex)
|
||||||
{
|
{
|
||||||
_logger.LogError("[gRPC Bus] RPC 异常 (Status: {Code}): {Msg}", ex.StatusCode, ex.Message);
|
gRpcLog.Debug("[gRPC] RPC 异常 (Status: {Code}): {Msg}", ex.StatusCode, ex.Message);
|
||||||
|
|
||||||
// 链路异常,进入重连等待阶段
|
// 链路异常,进入重连等待阶段
|
||||||
await Task.Delay(5000, stoppingToken);
|
await Task.Delay(5000, stoppingToken);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError("[gRPC Bus] 非预期链路异常: {Msg},5秒后尝试重连", ex.Message);
|
gRpcLog.Debug("[gRPC] 非预期链路异常: {Msg},5秒后尝试重连", ex.Message);
|
||||||
await Task.Delay(5000, stoppingToken);
|
await Task.Delay(5000, stoppingToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public class Program
|
|||||||
config.UpdateActualPort(activePort); // 回填端口
|
config.UpdateActualPort(activePort); // 回填端口
|
||||||
|
|
||||||
// 具体的 gRPC 链接逻辑封装在 Bootstrapper 中,保持 Main 清爽但逻辑可见
|
// 具体的 gRPC 链接逻辑封装在 Bootstrapper 中,保持 Main 清爽但逻辑可见
|
||||||
await Bootstrapper.RegisterToGatewayAsync(config, sysLog);
|
await Bootstrapper.RegisterToGatewayAsync(config);
|
||||||
|
|
||||||
// =============================================================
|
// =============================================================
|
||||||
// 3. 构建 Web 主机环境
|
// 3. 构建 Web 主机环境
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ public static class ServiceCollectionExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.Information("📋 加载视频流目标: {Count} 个", netTargets.Count);
|
logger.Information("📋 加载视频流目标: {Count} 个", netTargets.Count);
|
||||||
|
if (netTargets.Count > 0)
|
||||||
|
logger.Debug("🔍 视频流目标详情: {@Targets}", netTargets);
|
||||||
|
|
||||||
services.AddSingleton<IEnumerable<StreamTarget>>(netTargets);
|
services.AddSingleton<IEnumerable<StreamTarget>>(netTargets);
|
||||||
services.AddHostedService<ImageMonitorController>();
|
services.AddHostedService<ImageMonitorController>();
|
||||||
|
|||||||
Reference in New Issue
Block a user